如何使用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/plain
或text/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 id
, String name
和BigDecimal 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) { // ... } });
请注意,很多初学者将contentType
与dataType
混合在一起。 contentType
表示请求主体的types。 dataType
表示响应正文的(预期的)types,通常这是不必要的,因为jQuery已经基于响应的Content-Type
头来自动检测它。
然后,为了处理不作为单独的请求参数而作为整体JSONstring发送的servlet中的JSON对象,您只需要使用JSON工具手动parsing请求主体,而不是使用getParameter()
通常的方式。 也就是说,servlet不支持application/json
格式的请求,但只支持application/x-www-form-urlencoded
或multipart/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作为responseText
variables。 如果它代表一个完整的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")