簡體   English   中英

我應該如何使用 servlets 和 Ajax?

[英]How should I use servlets and Ajax?

每當我在 servlet 中打印某些內容並由 web 瀏覽器調用它時,它都會返回一個包含該文本的新頁面。 有沒有辦法使用 Ajax 打印當前頁面中的文本?

我對 web 應用程序和 servlets 非常陌生。

實際上,關鍵字是“Ajax”:異步 JavaScript 和 XML 然而,去年它比異步 JavaScript 和 JSON更常見。 基本上,您讓 JavaScript 執行異步 HTTP 請求並根據響應數據更新 HTML DOM 樹。

由於讓它在所有瀏覽器(尤其是 Internet Explorer 與其他瀏覽器)上工作是一項相當 繁瑣的工作,因此有大量 JavaScript 庫可以將其簡化為單個函數並涵蓋盡可能多的瀏覽器特定的錯誤/怪癖,如jQueryPrototypeMootools 由於 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 (另請參閱我們的 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 響應而更新。

以 JSON 形式返回List<String>

使用JSON而不是純文本作為響應格式,您甚至可以更進一步。 它允許更多的動態。 首先,您需要一個工具來在 Java 對象和 JSON 字符串之間進行轉換。 它們也有很多(請參閱本頁底部的概述)。 我個人最喜歡的是Google Gson 下載它的 JAR 文件並將其放在 Web 應用程序的/WEB-INF/lib文件夾中。

這是一個將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("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 小服務程序:

@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 這種方式更有幫助,因為您實際上可以使用它來迭代結果並執行服務器端數據格式化。 小服務程序:

@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 很有趣,但畢竟一般只對所謂的“公共網絡服務”有用。 JSF這樣的 MVC 框架在其 ajax 魔法的背后使用 XML。

Ajaxifying 現有表單

您可以使用 jQuery $.serialize()輕松地 ajaxify 現有的 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()方法。 請注意,上述語法也適用於 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;
    }

    // ...
}

也可以看看:

更新當前顯示在用戶瀏覽器中的頁面(無需重新加載)的正確方法是讓瀏覽器中執行的一些代碼更新頁面的 DOM。

該代碼通常是嵌入或鏈接自 HTML 頁面的 JavaScript,因此是 Ajax 建議。 (事實上​​,如果我們假設更新的文本通過 HTTP 請求來自服務器,這就是經典的 Ajax。)

也可以使用一些瀏覽器插件或附加組件來實現這種事情,盡管插件進入瀏覽器的數據結構以更新 DOM 可能很棘手。 (本機代碼插件通常會寫入頁面中嵌入的某些圖形框架。)

我將向您展示一個 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>");
}

通常您不能從 servlet 更新頁面。 客戶端(瀏覽器)必須請求更新。 客戶端要么加載一個全新的頁面,要么請求更新現有頁面的一部分。 這種技術稱為 Ajax。

使用Bootstrap多選:

阿賈克斯

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM