如何使用Servlets和Ajax?

我对web应用程序和Servlets非常陌生,我有以下问题:

每当我在servlet中打印一些内容并通过浏览器调用它时,它将返回一个包含该文本的新页面。 有没有办法使用Ajax打印当前页面中的文本?

的确,关键字是“ajax”: asynchronousJavaScript和XML 。 但是,去年这比经常使用asynchronousJavaScript和JSON 。 基本上,你让JS执行一个asynchronous的HTTP请求,并基于响应数据更新HTML DOM树。

由于在所有的浏览器(尤其是Internet Explorer和其他浏览器)中工作起来相当麻烦 ,因此有大量的JavaScript库可以简化单个function,并且尽可能多地包含浏览器特定的错误/怪癖,比如jQuery , Prototype , Mootools 。 由于jQuery最stream行,我将在下面的例子中使用它。

Kickoff示例以纯文本forms返回String

像下面那样创build一个/some.jsp (注意:代码并不期望JSP文件被放置在子文件夹中,如果这样做,请相应地更改servlet URL):

 <!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()方法创build一个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模式可以自由select,但是你需要相应地在JS代码示例中改变someservlet URL):

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

或者,如果你还没有使用Servlet 3.0兼容的容器(Tomcat 7,Glassfish 3,JBoss AS 6等),那么以旧式的方式将其映射到web.xml中(另见我们的Servlets 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并按下button。 你会看到div的内容被servlet响应更新了。

List<String>返回为JSON

使用JSON而不是明文作为响应格式,您甚至可以进一步获得一些步骤。 它允许更多的dynamic。 首先,你想有一个工具来转换Java对象和JSONstring。 其中也有很多(参见本页底部的概述)。 我个人最喜欢的是Google Gson 。 下载并将其JAR文件放在您的/WEB-INF/lib程序的/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); } 

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 $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自动将响应parsing为JSON,并在将响应内容types设置为application/json时,直接为您提供JSON对象( responseJson )作为函数参数。 如果你忘了设置它,或者依赖默认的text/plaintext/html ,那么responseJson参数将不会给你一个JSON对象,而是一个普通的香草串,你需要用JSON.parse()来手动摆弄JSON.parse() ,这是完全不必要的,如果你把内容types设置在第一位。

Map<String, String>返回为JSON

下面是将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>中的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>. }); }); }); 

List<Entity>作为XML返回

下面是一个与前面的例子有效相同的例子,然后是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> 

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(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框架使用XML下的Ajax魔术。

使现有表单Ajax化

您可以使用jQuery $.serialize()轻松地对现有的POST表单进行Ajax化,而无需收集和传递各个表单input参数。 假设一个没有JavaScript / jQuery的完美工作的现有表单(当enduser被禁用时,会优雅地退化):

 <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示例不一样或者更多,但是它对file upload所需的multipart/form-data表单有额外的透明支持。

手动发送请求参数给servlet

如果你根本没有表单,但是只想与后台的servlet进行交互,那么你可以使用jQuery $.param()来轻松地转换一个JSON对象到一个URL编码的查询string。

 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的一部分JSON.stringify()序列化为string,并指示jQuery设置请求内容types到application/json而不是(默认) application/x-www-form-urlencoded 。 这不能通过$.post()方便的function来完成,但需要通过下面的$.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表示请求主体的types。 dataType表示响应正文的(预期的)types,通常这是不必要的,因为jQuery已经基于响应的Content-Type头来自动检测它。

然后,为了处理不作为单独的请求参数而作为整体JSONstring发送的servlet中的JSON对象,您只需要使用JSON工具手动parsing请求主体,而不是使用getParameter()通常的方式。 也就是说,servlet不支持application/json格式的请求,但只支持application/x-www-form-urlencodedmultipart/form-data格式的请求。 Gson还支持将JSONstringparsing为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() ,因为某些原因只能使用JSONstring而不是常规的请求参数。

从servlet发送redirect

实现和理解的重要一点是,servlet在ajax请求上的任何sendRedirect()forward()调用都只会转发或redirectajax请求本身,而不是发送ajax请求的主文档/窗口。 在这种情况下,JavaScript / jQuery只会在callback函数中检索redirect/转发的response作为responseTextvariables。 如果它代表一个完整的HTML页面,而不是一个特定于Ajax的XML或JSON响应,那么你所能做的就是用它replace当前文档。

 document.open(); document.write(responseText); document.close(); 

请注意,这不会像最终用户在浏览器的地址栏中看到的那样更改URL。 所以有书签的问题。 因此,返回JavaScript / jQuery的“指令”来执行redirect而不是返回redirect页面的整个内容会更好。 例如通过返回一个布尔值或一个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并从JavaScript调用Java代码以及参数
  • 在JavaScript中访问Java / Servlet / JSP / JSTL / ELvariables
  • 如何轻松地在基于ajax的网站和基本的HTML网站之间切换?
  • 如何使用JSP / Servlet和Ajax将file upload到服务器?

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

该代码通常是embedded或链接到HTML页面的JavaScript,因此是AJAX的build议。 (事实上​​,如果我们假设更新后的文本通过HTTP请求来自服务器,这就是传统的AJAX。)

也可以使用一些浏览器插件或附加组件来实现这种事情,不过插件可能会很棘手,以达到浏览器的数据结构来更新DOM。 (原生代码插件通常会写入一些embedded在页面中的graphics框架。)

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

在这里,我们将创build一个使用servlet创buildlogin表单的简单示例。

的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(也称为AJAX)是Asynchronous JavaScript和XML的缩写)是一组相互关联的Web开发技术,用于在客户端上创buildasynchronousWeb应用程序。 使用Ajax,Web应用程序可以asynchronous地向服务器发送数据和从服务器检索数据下面是示例代码:

Jsp页面的Java脚本函数使用两个variablesfirstName和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>"); } 

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

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

使用引导多select

阿贾克斯

 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")