我应该如何使用 servlet 和 Ajax?

How should I use servlets and Ajax?

提问人:Amir Rachum 提问时间:11/6/2010 最后编辑:Peter MortensenAmir Rachum 更新时间:10/20/2021 访问量:373814

问:

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

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

Java AJAX JSP Servlet

评论


答:

5赞 Peter Knego 11/6/2010 #1

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

14赞 Stephen C 11/6/2010 #2

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

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

也可以使用一些浏览器插件或附加组件来实现这种事情,尽管插件进入浏览器的数据结构以更新 DOM 可能很棘手。 (原生代码插件通常写入页面中嵌入的某些图形框架。

585赞 BalusC 11/6/2010 #3

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

由于让它在所有浏览器(尤其是 Internet Explorer 与其他浏览器)上运行是一项非常繁琐的工作,因此有很多 JavaScript 库可以在单个函数中简化这一点,并尽可能多地涵盖特定于浏览器的 bug/怪癖,例如 jQueryPrototypeMootools。由于jQuery是当今最流行的,因此我将在下面的例子中使用它。

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

在下面创建一个赞:/some.jsp

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>SO question 4112686</title>
        <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
        <script>
            const yourServletURL = "${pageContext.request.contextPath}/yourServlet";
            $(document).on("click", "#somebutton", function() { // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
                $.get(yourServletURL, function(responseText) {  // Execute Ajax GET request on your servlet URL 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()

@WebServlet("/yourServlet")
public class YourServlet extends HttpServlet {

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

显然,URL 模式是您可以自由选择的,但如果您更改它,则需要相应地更改 JS 变量中的字符串。/yourServlet/yourServletyourServletURL

现在在浏览器中打开 http://localhost:8080/context/test.jsp 并按下按钮。您将看到 div 的内容使用 servlet 响应进行更新。

以 JSON 形式返回List<String>

使用 JSON 而不是纯文本作为响应格式,您甚至可以更进一步。它允许更多的动态。首先,您需要一个在 Java 对象和 JSON 字符串之间进行转换的工具。其中也有很多(有关概述,请参阅本页底部)。我个人最喜欢的是 Google Gson

以下示例显示为 .servlet: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(yourServletURL, function(responseJson) {     // Execute Ajax GET request on your servlet URL and execute the following function with Ajax response JSON...
        const $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(),因此如果你首先设置内容类型,这是完全不必要的。responseJsonapplication/jsontext/plaintext/htmlresponseJson

以 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(yourServletURL, function(responseJson) {                // Execute Ajax GET request on your servlet URL and execute the following function with Ajax response JSON...
        const $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>

下面是一个示例,该示例显示在 其中类具有属性 和 。servlet:List<Product><table>ProductLong idString nameBigDecimal 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(yourServletURL, function(responseJson) {           // Execute Ajax GET request on your servlet URL and execute the following function with Ajax response JSON...
        const $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 代码(注意:如果将 放在 中,它可能在非 Ajax 响应中的其他位置重用):<table><jsp:include>

<?xml version="1.0" encoding="UTF-8"?>
<%@page contentType="application/xml" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="jakarta.tags.core" %>
<%@taglib prefix="fmt" uri="jakarta.tags.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(yourServletURL, function(responseXml) {               // Execute Ajax GET request on your servlet URL 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 在使用 Ajax 更新 HTML 文档的特定目的方面比 JSON 强大得多。JSON很有趣,但毕竟通常只对所谓的“公共Web服务”有用。像 JSF 这样的 MVC 框架在幕后使用 XML 来实现其 ajax 魔力。

对现有表单进行 ajaxify

您可以使用 jQuery $.serialize() 轻松地对现有 POST 表单进行ajaxing,而无需手动收集和传递单个表单输入参数。假设现有表单在没有 JavaScript/jQuery 的情况下可以正常工作(因此当最终用户禁用 JavaScript 时会正常降级):

<form id="someform" action="${pageContext.request.contextPath}/yourServletURL" 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) {
    const $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编码的查询字符串,就像普通的HTML表单一样,这样你就可以继续使用来提取数据。application/x-www-form-urlencodedrequest.getParameter(name)

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

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

$.post() 实质上是以下 $.ajax() 调用的简写。

$.ajax({
    type: "POST",
    url: yourServletURL,
    data: $.param(params),
    success: function(response) {
        // ...
    }
});

可以重用上一节中所示的相同方法。请注意,上述语法也适用于 jQuery 和 servlet 中的 $.get()。doPost()$.post()doGet()

手动将 JSON 对象发送到 servlet

但是,如果您出于某种原因打算将JSON对象作为一个整体而不是作为单个请求参数发送,那么您需要使用JSON.stringify()(不是jQuery的一部分)将其序列化为字符串,并指示jQuery将请求内容类型设置为而不是(默认)。这不能通过便利功能来完成,但需要通过以下方式完成。application/jsonapplication/x-www-form-urlencoded$.post()$.ajax()

const data = {
    foo: "fooValue",
    bar: "barValue",
    baz: "bazValue"
};

$.ajax({
    type: "POST",
    url: yourServletURL,
    contentType: "application/json", // NOT dataType!
    data: JSON.stringify(data),
    success: function(response) {
        // ...
    }
});

请注意,很多启动器与 .表示请求正文的类型。表示响应正文的(预期)类型,这通常是不必要的,因为jQuery已经根据响应的标头自动检测它。contentTypedataTypecontentTypedataTypeContent-Type

然后,为了处理 servlet 中的 JSON 对象,该对象不是作为单个请求参数发送的,而是作为整个 JSON 字符串发送的,您只需要使用 JSON 工具手动解析请求正文,而不是使用通常的方式。也就是说,servlet 不支持格式化请求,而仅支持或格式化请求。Gson 还支持将 JSON 字符串解析为 JSON 对象。getParameter()application/jsonapplication/x-www-form-urlencodedmultipart/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 请求的任何 and 调用只会转发或重定向 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;
    }

    // ...
}

另请参阅:

评论

0赞 shinzou 10/12/2016
需要解析最后一个示例中的 JSON。
4赞 BalusC 10/12/2016
@kuhaku:没有。如果你从上到下阅读帖子,你就会明白为什么。
1赞 Jonathan Laliberte 6/21/2017
在过去的一个月左右的时间里,这个答案一直是我的生命线,哈哈。从中学到很多东西。我喜欢XML的例子。谢谢你把这些放在一起!不过,如果你有时间,一个菜鸟问题。是否有理由将xml文件夹放在WEB-INF中?
1赞 BalusC 6/21/2017
@JonathanLaliberte:因此用户无法下载它们。
0赞 629 4/17/2018
@BalusC,你的XML示例很棒,谢谢。但是我得到的是“无法获取未定义或空引用的属性'替换'”。它还显示“参数数量错误或属性赋值无效”。我还可以看到,当我调试XML时,它填充了数据。有什么想法吗?$("#somediv").html($(responseXml).find("data").html())
13赞 Mitul Maheshwari 2/5/2014 #4

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

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

文件索引.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);
        }
    }
}

评论

0赞 Fakipo 9/9/2022
我无法在 ajax 成功函数中获取任何内容
8赞 SUBZ 3/20/2014 #5
$.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);
    }
});

评论

0赞 Peter Mortensen 10/20/2021
解释是有序的。例如,想法/要点是什么?请通过编辑(更改)您的答案来回复,而不是在评论中(没有“编辑:”,“更新:”或类似内容 - 答案应该看起来像今天写的一样)。
7赞 user3468976 4/3/2014 #6

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>");
}
4赞 Thakhani Tharage 7/27/2014 #7

使用 Bootstrap multi 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")