我应该如何使用servlet和Ajax?

每当我在servlet中打印一些内容并由web浏览器调用它时,它都会返回一个包含该文本的新页面。是否有一种方法可以使用Ajax打印当前页面中的文本?

我对web应用程序和servlet非常陌生。

367925 次浏览

通常不能从servlet更新页面。客户端(浏览器)必须请求更新。客户端要么加载一个全新的页面,要么请求更新现有页面的某个部分。这种技术称为Ajax。

更新用户浏览器中当前显示的页面(无需重新加载)的正确方法是在浏览器中执行一些代码来更新页面的DOM。

该代码通常是嵌入在HTML页面或从HTML页面链接的JavaScript,因此建议使用Ajax。(事实上,如果我们假设更新的文本通过HTTP请求来自服务器,这就是典型的Ajax。)

也可以使用一些浏览器插件或附加组件来实现这类事情,尽管插件要到达浏览器的数据结构来更新DOM可能有些棘手。(本地代码插件通常写入嵌入在页面中的图形帧。)

事实上,关键字是"Ajax": 异步JavaScript和XML。然而,去年它经常是异步JavaScript和JSON。基本上,让JavaScript执行异步HTTP请求,并根据响应数据更新HTML DOM树。

因为它在所有浏览器上都是让它起作用的工作很乏味的(特别是Internet Explorer相对于其他浏览器),所以有很多JavaScript库可以在单个函数中简化它,并在底层覆盖尽可能多的浏览器特定的bug /癖好,例如jQuery原型Mootools。由于jQuery现在最流行,我将在下面的示例中使用它。

启动示例返回String为纯文本

创建一个如下所示的/some.jsp(注意:这个答案中的代码片段并不期望JSP文件被放置在子文件夹中,如果你这样做,将servlet URL相应地从"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>

doGet()方法创建一个servlet,如下所示:

@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映射到/someservlet/someservlet/*的URL模式上,如下所示(显然,URL模式由你自由选择,但你需要在JS代码示例中相应地改变someservlet URL):

package com.example;


@WebServlet("/someservlet/*")
public class SomeServlet extends HttpServlet {
// ...
}

或者,当你还没有在Servlet 3.0兼容的容器上(Tomcat 7, GlassFish 3, JBoss AS 6等或更新版本),然后用老式的方式在web.xml中映射它(另见我们的servlet wiki页面):

<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字符串之间进行转换。它们也有很多(参见这个页面底部的概述)。我个人最喜欢谷歌Gson。下载并把它的JAR文件放在你的web应用程序的/WEB-INF/lib文件夹中。

下面是一个将List<String>显示为<ul><li>的例子。servlet:

@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>.
});
});
});

请注意,当你将响应内容类型设置为application/json时,jQuery会自动将响应解析为JSON,并直接给你一个JSON对象(responseJson)作为函数参数。如果你忘记设置它或依赖于默认的text/plaintext/html,那么responseJson参数不会给你一个JSON对象,而是一个普通的字符串,然后你需要手动摆弄JSON.parse(),因此,如果你首先设置正确的内容类型,这是完全不必要的。

返回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>

下面是一个例子,它在<table>中显示List<Product>,其中Product类具有Long idString nameBigDecimal price属性。servlet:

@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在这方面更有帮助,因为您实际上可以使用它来迭代结果并执行服务器端数据格式化。servlet:

@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代码(注意:如果你把<table>放在<jsp:include>中,它可以在非ajax响应的其他地方被重用):

<?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".
});
});

现在您可能已经意识到,在使用Ajax更新HTML文档的特定目的方面,XML为什么比JSON强大得多。JSON很有趣,但毕竟通常只对所谓的“公共web服务”有用。像JSF这样的MVC框架在它们的ajax魔法的掩护下使用XML。

对现有形式进行ajax化

你可以使用jQuery $.serialize()轻松地ajax现有的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表单插件的功能与上面的jQuery示例大致相同,但它根据文件上传的需要对multipart/form-data表单提供了额外的透明支持。

手动发送请求参数到servlet

如果你根本没有表单,而只是想在后台与servlet交互;如果你想POST一些数据,那么你可以使用jQuery $.param()轻松地将JSON对象转换为url编码的查询字符串。

var params = {
foo: "fooValue",
bar: "barValue",
baz: "bazValue"
};


$.post("someservlet", $.param(params), function(response) {
// ...
});

如上所示的相同doPost()方法可以被重用。请注意,上述语法也适用于jQuery中的$.get()和servlet中的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) {
// ...
}
});

请注意,许多启动器将contentTypedataType混合使用。contentType表示请求主体的类型。dataType表示响应主体的(预期)类型,这通常是不必要的,因为jQuery已经根据响应的Content-Type报头自动检测到它。

然后,为了处理servlet中的JSON对象,它不是作为单独的请求参数发送的,而是作为一个完整的JSON字符串发送,你只需要使用JSON工具手动解析请求体,而不是通常的方式使用getParameter()。也就是说,servlet不支持application/json格式的请求,而只支持application/x-www-form-urlencodedmultipart/form-data格式的请求。Gson还支持将JSON字符串解析为JSON对象。

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();
// ...

请注意,这比仅使用$.param()更加笨拙。通常,只有当目标服务是一个JAX-RS (RESTful)服务时,你才想使用JSON.stringify(),因为某种原因,这个服务只能使用JSON字符串,而不能使用常规的请求参数。

从servlet发送重定向

重要的是要认识和理解servlet对ajax请求的任何sendRedirect()forward()调用只会转发或重定向Ajax请求本身,而不会转发ajax请求发出的主文档/窗口。JavaScript/jQuery在这种情况下只会在回调函数中检索被重定向/转发的响应作为responseText变量。如果它表示整个HTML页面,而不是特定于ajax的XML或JSON响应,那么您所能做的就是用它替换当前文档。

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;
}


// ...
}

参见:

我将向您展示一个servlet的完整示例以及如何进行Ajax调用。

在这里,我们将创建使用servlet创建登录表单的简单示例。

文件index . html

<form>
Name:<input type="text" name="username"/><br/><br/>
Password:<input type="password" name="userpass"/><br/><br/>
<input type="button" value="login"/>
</form>

Ajax示例

$.ajax
({
type: "POST",
data: 'LoginServlet=' + name + '&name=' + type + '&pass=' + password,
url: url,
success:function(content)
{
$('#center').html(content);
}
});

LoginServlet servlet代码:

package abc.servlet;


import java.io.File;


public class AuthenticationServlet extends HttpServlet {


private static final long serialVersionUID = 1L;


protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
doPost(request, response);
}


protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {


try{
HttpSession session = request.getSession();
String username = request.getParameter("name");
String password = request.getParameter("pass");


/// Your Code
out.println("sucess / failer")
}
catch (Exception ex) {
// System.err.println("Initial SessionFactory creation failed.");
ex.printStackTrace();
System.exit(0);
}
}
}
$.ajax({
type: "POST",
url: "URL to hit on servelet",
data: JSON.stringify(json),
dataType: "json",
success: function(response){
// We have the response
if(response.status == "SUCCESS"){
$('#info').html("Info  has been added to the list successfully.<br>" +
"The details are as follws: <br> Name: ");
}
else{
$('#info').html("Sorry, there is some thing wrong with the data provided.");
}
},
error: function(e){
alert('Error: ' + e);
}
});

Ajax(也称为Ajax)是异步JavaScript和XML的首字母缩写,是一组用于客户端创建异步web应用程序的相互关联的web开发技术。使用Ajax, web应用程序可以异步地向服务器发送数据,并从服务器检索数据。

下面是示例代码:

一个JSP页面JavaScript函数,通过两个变量firstName和lastName向servlet提交数据:

function onChangeSubmitCallWebServiceAJAX()
{
createXmlHttpRequest();
var firstName = document.getElementById("firstName").value;
var lastName = document.getElementById("lastName").value;
xmlHttp.open("GET", "/AJAXServletCallSample/AjaxServlet?firstName="
+ firstName + "&lastName=" + lastName, true)
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.send(null);
}

Servlet读取以XML格式发送回JSP的数据(也可以使用文本)。您只需要将响应内容更改为文本并在JavaScript函数上呈现数据。)

/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");


response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<details>");
response.getWriter().write("<firstName>" + firstName + "</firstName>");
response.getWriter().write("<lastName>" + lastName + "</lastName>");
response.getWriter().write("</details>");
}

使用引导 multi select:

Ajax

function() { $.ajax({
type: "get",
url: "OperatorController",
data: "input=" + $('#province').val(),
success: function(msg) {
var arrayOfObjects = eval(msg);
$("#operators").multiselect('dataprovider',
arrayOfObjects);
// $('#output').append(obj);
},
dataType: 'text'
});}
}

在Servlet

request.getParameter("input")