![](/img/trans.png)
[英]Should I avoid use of filters in servlets to check whether user is logged in
[英]How should I use servlets and Ajax?
每當我在 servlet 中打印某些內容並由 web 瀏覽器調用它時,它都會返回一個包含該文本的新頁面。 有沒有辦法使用 Ajax 打印當前頁面中的文本?
我對 web 應用程序和 servlets 非常陌生。
實際上,關鍵字是“Ajax”:異步 JavaScript 和 XML 。 然而,去年它比異步 JavaScript 和 JSON更常見。 基本上,您讓 JavaScript 執行異步 HTTP 請求並根據響應數據更新 HTML DOM 樹。
由於讓它在所有瀏覽器(尤其是 Internet Explorer 與其他瀏覽器)上工作是一項相當 繁瑣的工作,因此有大量 JavaScript 庫可以將其簡化為單個函數並涵蓋盡可能多的瀏覽器特定的錯誤/怪癖,如jQuery 、 Prototype 、 Mootools 。 由於 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 響應而更新。
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/plain
或text/html
的默認值,那么responseJson
參數不會給您一個 JSON 對象,而是一個普通的字符串,您需要手動擺弄JSON.parse()
之后,如果您首先正確設置內容類型,則完全沒有必要這樣做。
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>
List<Entity>
這是一個在<table>
中顯示List<Product>
的示例,其中Product
類具有屬性Long id
、 String name
和BigDecimal 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>.
});
});
});
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。
您可以使用 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 進行交互,您想發布一些數據,那么您可以使用 jQuery $.param()
輕松轉換 JSON 對象到 URL 編碼的查詢字符串。
var params = {
foo: "fooValue",
bar: "barValue",
baz: "bazValue"
};
$.post("someservlet", $.param(params), function(response) {
// ...
});
可以重復使用上面顯示的相同doPost()
方法。 請注意,上述語法也適用於 jQuery 中的$.get()
和 servlet 中的doGet()
。
但是,如果您出於某種原因打算將 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
標頭自動檢測它。
然后,為了處理 servlet 中的 JSON 對象,它不是作為單個請求參數發送,而是作為整個 JSON 字符串以上述方式發送,您只需要使用 JSON 工具手動解析請求正文,而不是使用getParameter()
通常的方式。 也就是說,servlet 不支持application/json
格式的請求,而只支持application/x-www-form-urlencoded
或multipart/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 對 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 創建登錄表單。
<form>
Name:<input type="text" name="username"/><br/><br/>
Password:<input type="password" name="userpass"/><br/><br/>
<input type="button" value="login"/>
</form>
$.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.