如何使用Servlet和Ajax?


334

我是Web应用程序和Servlet的新手,我有以下问题:

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

Answers:


561

实际上,关键字是“ ajax”:异步JavaScript和XML。但是,去年,它比异步JavaScript和JSON更为常见。基本上,让JS执行异步HTTP请求并根据响应数据更新HTML DOM树。

由于要使其能够在所有浏览器(尤其是Internet Explorer与其他浏览器)上进行都是一项繁琐的工作,因此有大量的JavaScript库简化了单个功能,并涵盖了尽可能多的浏览器特定的错误/怪癖。 ,例如jQueryPrototypeMootools。由于jQuery目前最流行,因此我将在以下示例中使用它。

String以纯文本形式返回的启动示例

/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()方法创建一个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模式是您自由选择的,但是您需要相应地someservlet在所有地方更改JS代码示例中的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并按按钮。您将看到div的内容随servlet响应一起更新。

List<String>作为JSON 返回

使用JSON而不是纯文本作为响应格式,您甚至可以进一步采取一些措施。它允许更多的动态。首先,您想要一个工具来在Java对象和JSON字符串之间进行转换。也有很多(请参阅本页底部的概述)。我个人最喜欢的是Google Gson。下载其JAR文件并将其放在/WEB-INF/libWeb应用程序的文件夹中。

这是显示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>.
        });
    });
});

请注意,responseJson当您将响应内容类型设置为时,jQuery会自动将响应解析为JSON,并直接为您提供JSON对象()作为函数参数application/json。如果您忘记设置它或依赖于默认值text/plainor text/html,那么该responseJson参数将不会为您提供JSON对象,而是一个普通的香草字符串,并且您之后需要手动进行操作JSON.parse(),因此如果您完全不需要首先设置内容类型。

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>

List<Entity>作为JSON 返回

下面是其中显示了一个例子List<Product><table>,其中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框架在其ajax魔术的底层使用XML。

合并现有表格

您可以使用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的表格插件确实更少或更多的与上述相同的jQuery例子,但它具有用于附加透明支持multipart/form-data所要求的文件上传形式。

手动将请求参数发送到servlet

如果您根本没有表单,而只想与“后台”与servlet交互,从而希望发布一些数据,那么您可以使用jQuery $.param()轻松地将JSON对象转换为URL编码请求参数。

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

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

doPost()可以重复使用上面显示的相同方法。请注意,以上语法$.get()在jQuery和doGet()servlet中也适用。

手动将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) {
        // ...
    }
});

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

然后,为了以上述方式处理不是作为单独的请求参数而是作为整个JSON字符串发送的Servlet中的JSON对象,您只需要使用JSON工具手动解析请求主体,而无需使用getParameter()通常的道路。也就是说,小服务程序不支持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()。通常,JSON.stringify()仅在目标服务是例如JAX-RS(RESTful)服务的情况下才要使用,由于某种原因,该服务仅能够使用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;
    }

    // ...
}

也可以看看:


需要在上一个示例中解析json。
shinzou

4
@kuhaku:不。如果您从上至下阅读文章,您将了解原因。
BalusC

1
这个答案是我过去一个月左右的命脉。从中学到很多东西。我喜欢XML示例。感谢您整理这些内容!如果您有时间,请问一个菜鸟问题。是否有理由将xml文件夹放在WEB-INF中?
乔纳森·拉利伯特

1
@JonathanLaliberte:因此用户无法下载它们。
BalusC

@BalusC,您的XML示例很棒,谢谢。但是我在此行中收到“无法获取未定义或空引用的属性'替换'” $("#somediv").html($(responseXml).find("data").html())。它还说“参数数量错误或属性分配无效”。我还可以看到在调试XML时,我的XML中已填充了数据。有任何想法吗 ?
629

14

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

该代码通常是嵌入HTML页面或从HTML页面链接的javascript,因此是AJAX建议。(实际上,如果我们假设更新的文本是通过HTTP请求来自服务器的,则这是经典的AJAX。)

也可以使用某些浏览器插件或附加组件来实现这种功能,尽管插件很难进入浏览器的数据结构以更新DOM。(本机代码插件通常会写入页面中嵌入的某些图形框架。)


13

我将向您展示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);
        } 
    }
}

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

7

Ajax(也称为AJAX,是异步JavaScript和XML的缩写)是一组相互关联的Web开发技术,用于客户端以创建异步Web应用程序。使用Ajax,Web应用程序可以异步向服务器发送数据和从服务器检索数据。下面是示例代码:

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

5

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


4

使用引导多选

阿贾克斯

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")
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.