事实上,关键字是“Ajax”:异步JavaScript和XML。但是,在过去几年中,它通常是异步JavaScript和JSON。基本上,您让JavaScript执行异步HTTP请求并根据响应数据更新HTML DOM树。
由于在所有浏览器(特别是Internet Explorer与其他浏览器)上工作是非常繁琐的工作,因此有很多JavaScript库在单个函数中简化了这一点,并涵盖了尽可能多的浏览器特定的错误/怪癖,例如jQuery,Prototype,Mootools。由于jQuery现在最受欢迎,我将在下面的示例中使用它。
以纯文本形式返回的启动示例String
创建一个类似下面的代码(注意:这个答案中的代码片段并不期望将JSP文件放在子文件夹中,如果你这样做,请相应地从to更改servlet URL;为了简洁起见,它只是从代码片段中省略):/some.jsp
"someservlet"
"${pageContext.request.contextPath}/someservlet"
<!DOCTYPE html>
<html lang="en">
<head>
<title>SO question 4112686</title>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
$(document).on("click", "#somebutton", function() { // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
$.get("someservlet", function(responseText) { // Execute Ajax GET request on URL of "someservlet" and execute the following function with Ajax response text...
$("#somediv").text(responseText); // Locate HTML DOM element with ID "somediv" and set its text content with the response text.
});
});
</script>
</head>
<body>
<button id="somebutton">press here</button>
<div id="somediv"></div>
</body>
</html>
使用如下所示的方法创建一个 servlet:doGet()
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String text = "some text";
response.setContentType("text/plain"); // Set content type of the response so that jQuery knows what it can expect.
response.setCharacterEncoding("UTF-8"); // You want world domination, huh?
response.getWriter().write(text); // Write response body.
}
将此 servlet 映射到 URL 模式上,如下所示(显然,URL 模式可以自由选择,但您需要相应地更改 JS 代码示例中的 URL):/someservlet
/someservlet/*
someservlet
package com.example;
@WebServlet("/someservlet/*")
public class SomeServlet extends HttpServlet {
// ...
}
或者,当您还没有使用Servlet 3.0兼容容器(Tomcat 7,GlassFish 3,JBoss AS 6等或更高版本)时,请以老式的方式映射它(另请参阅我们的Servlets wiki页面):web.xml
<servlet>
<servlet-name>someservlet</servlet-name>
<servlet-class>com.example.SomeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>someservlet</servlet-name>
<url-pattern>/someservlet/*</url-pattern>
</servlet-mapping>
现在在浏览器中打开 http://localhost:8080/context/test.jsp,然后按按钮。您将看到 div 的内容使用 servlet 响应进行更新。
以 JSON 格式返回List<String>
使用JSON而不是明文作为响应格式,您甚至可以进一步了解一些步骤。它允许更多的动态。首先,您希望有一个工具在 Java 对象和 JSON 字符串之间进行转换。它们也有很多(有关概述,请参阅本页底部)。我个人最喜欢的是Google Gson。下载其 JAR 文件并将其放在 Web 应用程序的文件夹中。/WEB-INF/lib
下面是一个显示为 .服务备件:List<String>
<ul><li>
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<String> list = new ArrayList<>();
list.add("item1");
list.add("item2");
list.add("item3");
String json = new Gson().toJson(list);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
}
JavaScript 代码:
$(document).on("click", "#somebutton", function() { // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
$.get("someservlet", function(responseJson) { // Execute Ajax GET request on URL of "someservlet" and execute the following function with Ajax response JSON...
var $ul = $("<ul>").appendTo($("#somediv")); // Create HTML <ul> element and append it to HTML DOM element with ID "somediv".
$.each(responseJson, function(index, item) { // Iterate over the JSON array.
$("<li>").text(item).appendTo($ul); // Create HTML <li> element, set its text content with currently iterated item and append it to the <ul>.
});
});
});
请注意,jQuery 会自动将响应解析为 JSON,并在您将响应内容类型设置为 时直接为您提供 JSON 对象 () 作为函数参数。如果您忘记设置它或依赖于默认值 or ,则该参数不会为您提供 JSON 对象,而是一个普通的香草字符串,之后您需要手动摆弄 JSON.parse(),
因此,如果您首先将内容类型设置得正确,则完全没有必要。responseJson
application/json
text/plain
text/html
responseJson
以 JSON 格式返回Map<String, String>
这是另一个示例,显示为:Map<String, String>
<option>
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Map<String, String> options = new LinkedHashMap<>();
options.put("value1", "label1");
options.put("value2", "label2");
options.put("value3", "label3");
String json = new Gson().toJson(options);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
}
而 JSP:
$(document).on("click", "#somebutton", function() { // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
$.get("someservlet", function(responseJson) { // Execute Ajax GET request on URL of "someservlet" and execute the following function with Ajax response JSON...
var $select = $("#someselect"); // Locate HTML DOM element with ID "someselect".
$select.find("option").remove(); // Find all child elements with tag name "option" and remove them (just to prevent duplicate options when button is pressed again).
$.each(responseJson, function(key, value) { // Iterate over the JSON object.
$("<option>").val(key).text(value).appendTo($select); // Create HTML <option> element, set its value with currently iterated key and its text content with currently iterated item and finally append it to the <select>.
});
});
});
跟
<select id="someselect"></select>
以 JSON 格式返回List<Entity>
下面是一个示例,它显示在 类具有属性 和 .服务备件:List<Product>
<table>
Product
Long id
String name
BigDecimal price
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Product> products = someProductService.list();
String json = new Gson().toJson(products);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
}
JS 代码:
$(document).on("click", "#somebutton", function() { // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
$.get("someservlet", function(responseJson) { // Execute Ajax GET request on URL of "someservlet" and execute the following function with Ajax response JSON...
var $table = $("<table>").appendTo($("#somediv")); // Create HTML <table> element and append it to HTML DOM element with ID "somediv".
$.each(responseJson, function(index, product) { // Iterate over the JSON array.
$("<tr>").appendTo($table) // Create HTML <tr> element, set its text content with currently iterated item and append it to the <table>.
.append($("<td>").text(product.id)) // Create HTML <td> element, set its text content with id of currently iterated product and append it to the <tr>.
.append($("<td>").text(product.name)) // Create HTML <td> element, set its text content with name of currently iterated product and append it to the <tr>.
.append($("<td>").text(product.price)); // Create HTML <td> element, set its text content with price of currently iterated product and append it to the <tr>.
});
});
});
以 XML 格式返回List<Entity>
下面是一个示例,它实际上与前面的示例相同,但随后使用 XML 而不是 JSON。当使用 JSP 作为 XML 输出生成器时,您会发现对表和所有内容进行编码不那么繁琐。JSTL 以这种方式更有用,因为您实际上可以使用它来迭代结果并执行服务器端数据格式化。服务备件:
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Product> products = someProductService.list();
request.setAttribute("products", products);
request.getRequestDispatcher("/WEB-INF/xml/products.jsp").forward(request, response);
}
JSP 代码(注意:如果将 放在 中,它可以在非 Ajax 响应中的其他位置重用):<table>
<jsp:include>
<?xml version="1.0" encoding="UTF-8"?>
<%@page contentType="application/xml" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<data>
<table>
<c:forEach items="${products}" var="product">
<tr>
<td>${product.id}</td>
<td><c:out value="${product.name}" /></td>
<td><fmt:formatNumber value="${product.price}" type="currency" currencyCode="USD" /></td>
</tr>
</c:forEach>
</table>
</data>
JavaScript 代码:
$(document).on("click", "#somebutton", function() { // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
$.get("someservlet", function(responseXml) { // Execute Ajax GET request on URL of "someservlet" and execute the following function with Ajax response XML...
$("#somediv").html($(responseXml).find("data").html()); // Parse XML, find <data> element and append its HTML to HTML DOM element with ID "somediv".
});
});
到现在为止,您可能已经意识到为什么XML比JSON强大得多,以便使用Ajax更新HTML文档。JSON很有趣,但毕竟通常只对所谓的“公共Web服务”有用。像JSF这样的MVC框架在幕后使用XML来实现他们的ajax魔术。
对现有窗体进行混杂
您可以使用 jQuery $.serialize()
轻松对现有 POST 表单进行混杂,而无需随意收集和传递各个表单输入参数。假设一个现有的形式在没有JavaScript / jQuery的情况下工作得很好(因此当最终用户禁用JavaScript时,它会优雅地降级):
<form id="someform" action="someservlet" method="post">
<input type="text" name="foo" />
<input type="text" name="bar" />
<input type="text" name="baz" />
<input type="submit" name="submit" value="Submit" />
</form>
您可以使用Ajax逐步增强它,如下所示:
$(document).on("submit", "#someform", function(event) {
var $form = $(this);
$.post($form.attr("action"), $form.serialize(), function(response) {
// ...
});
event.preventDefault(); // Important! Prevents submitting the form.
});
您可以在 servlet 中区分普通请求和 Ajax 请求,如下所示:
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String foo = request.getParameter("foo");
String bar = request.getParameter("bar");
String baz = request.getParameter("baz");
boolean ajax = "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
// ...
if (ajax) {
// Handle Ajax (JSON or XML) response.
} else {
// Handle regular (JSP) response.
}
}
jQuery Form插件的功能或多或少与上面的jQuery示例相同,但它根据文件上传的要求对表单具有额外的透明支持。multipart/form-data
手动将请求参数发送到 servlet
如果您根本没有表单,但只想“在后台”与servlet进行交互,从而发布一些数据,那么您可以使用jQuery $.param()
轻松地将JSON对象转换为URL编码的查询字符串。
var params = {
foo: "fooValue",
bar: "barValue",
baz: "bazValue"
};
$.post("someservlet", $.param(params), function(response) {
// ...
});
可以重复使用上面显示的相同方法。请注意,上述语法也适用于jQuery和servlet。doPost()
$.get()
doGet()
手动将 JSON 对象发送到 servlet
但是,如果您出于某种原因打算将 JSON 对象作为一个整体而不是作为单独的请求参数发送,则需要使用 JSON.stringify()
(不是 jQuery 的一部分)将其序列化为字符串,并指示 jQuery 将请求内容类型设置为而不是(默认)。这不能通过便利功能完成,但需要通过以下方式完成。application/json
application/x-www-form-urlencoded
$.post()
$.ajax()
var data = {
foo: "fooValue",
bar: "barValue",
baz: "bazValue"
};
$.ajax({
type: "POST",
url: "someservlet",
contentType: "application/json", // NOT dataType!
data: JSON.stringify(data),
success: function(response) {
// ...
}
});
请注意,许多启动器都与 .表示请求正文的类型。表示响应正文的(预期)类型,这通常是不必要的,因为 jQuery 已经根据响应的标头自动检测它。contentType
dataType
contentType
dataType
Content-Type
然后,为了处理 servlet 中的 JSON 对象,该对象不是作为单独的请求参数发送,而是以上述方式作为整个 JSON 字符串发送,您只需要使用 JSON 工具手动解析请求正文,而不是使用通常的方式。也就是说,servlet 不支持格式化请求,而只支持格式化请求。Gson 还支持将 JSON 字符串解析为 JSON 对象。getParameter()
application/json
application/x-www-form-urlencoded
multipart/form-data
JsonObject data = new Gson().fromJson(request.getReader(), JsonObject.class);
String foo = data.get("foo").getAsString();
String bar = data.get("bar").getAsString();
String baz = data.get("baz").getAsString();
// ...
请注意,这一切都比仅仅使用更笨拙。通常,仅当目标服务是 JAX-RS(RESTful) 服务时才要使用,该服务由于某种原因只能使用 JSON 字符串,而不能使用常规请求参数。$.param()
JSON.stringify()
从 servlet 发送重定向
需要认识到和理解的重要一点是,servlet 对 ajax 请求的任何和调用只会转发或重定向 Ajax 请求本身,而不是发起 Ajax 请求的主文档/窗口。在这种情况下,JavaScript/jQuery 只会在回调函数中将重定向/转发的响应作为变量检索。如果它表示整个HTML页面,而不是特定于Ajax的XML或JSON响应,那么你所能做的就是用它替换当前文档。sendRedirect()
forward()
responseText
document.open();
document.write(responseText);
document.close();
请注意,这不会更改最终用户在浏览器地址栏中看到的 URL。因此,书签性存在问题。因此,最好只返回 JavaScript/jQuery 执行重定向的“指令”,而不是返回重定向页面的全部内容。例如,通过返回布尔值或 URL。
String redirectURL = "http://example.com";
Map<String, String> data = new HashMap<>();
data.put("redirect", redirectURL);
String json = new Gson().toJson(data);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
function(responseJson) {
if (responseJson.redirect) {
window.location = responseJson.redirect;
return;
}
// ...
}
另请参阅: