Das Schlüsselwort lautet in der Tat "Ajax": Asynchrones JavaScript und XML . Doch in den letzten Jahren ist es mehr als oft Asynchrones JavaScript und JSON . Im Wesentlichen lassen Sie JavaScript eine asynchrone HTTP-Anfrage ausführen und den HTML-DOM-Baum auf der Grundlage der Antwortdaten aktualisieren.
Da es ziemlich mühsame Arbeit, um es zum Laufen zu bringen in allen Browsern (insbesondere Internet Explorer gegenüber anderen), gibt es viele JavaScript-Bibliotheken, die dies in einzelnen Funktionen vereinfachen und möglichst viele browserspezifische Fehler/Ungereimtheiten abdecken, wie z. B. jQuery , Prototyp , Mootools . Da jQuery heutzutage sehr beliebt ist, werde ich es in den folgenden Beispielen verwenden.
Beispiel Kickoff-Rückgabe String
als Klartext
Erstellen einer /some.jsp
wie unten (Hinweis: Die Codeschnipsel in dieser Antwort erwarten nicht, dass die JSP-Datei in einem Unterordner platziert wird; wenn Sie dies tun, ändern Sie die Servlet-URL entsprechend von "someservlet"
a "${pageContext.request.contextPath}/someservlet"
(sie wird in den Codeschnipseln nur der Kürze halber weggelassen):
<!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>
Erstellen Sie ein Servlet mit einer doGet()
Methode, die wie folgt aussieht:
@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.
}
Bilden Sie dieses Servlet auf ein URL-Muster von /someservlet
または /someservlet/*
wie unten (natürlich ist das URL-Muster frei wählbar, aber Sie müssen die someservlet
URL in JS-Codebeispielen über alles entsprechend platzieren):
package com.example;
@WebServlet("/someservlet/*")
public class SomeServlet extends HttpServlet {
// ...
}
Oder, wenn Sie nicht auf einer Servlet 3.0-kompatiblen Container noch nicht ( Tomcat 7, GlassFish 3, JBoss AS 6, etc. oder neuer), dann in web.xml
auf die altmodische Weise (siehe auch unsere Servlets-Wiki-Seite ):
<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>
Öffnen Sie nun die Seite http://localhost:8080/context/test.jsp im Browser und drücken Sie die Schaltfläche. Sie werden sehen, dass der Inhalt des Divs mit der Servlet-Antwort aktualisiert wird.
Rücksendung List<String>
als JSON
Mit JSON anstelle von Klartext als Antwortformat können Sie sogar einige Schritte weiter gehen. Es ermöglicht eine größere Dynamik. Zunächst benötigen Sie ein Tool, das zwischen Java-Objekten und JSON-Strings konvertiert. Auch davon gibt es eine ganze Menge (siehe den unteren Teil von diese Seite für einen Überblick). Mein persönlicher Favorit ist Google Gson . Laden Sie die JAR-Datei herunter und legen Sie sie in /WEB-INF/lib
Ordner Ihrer Webanwendung.
Hier ist ein Beispiel, das Folgendes anzeigt List<String>
como <ul><li>
. Das 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);
}
Der JavaScript-Code:
$(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>.
});
});
});
Beachten Sie, dass jQuery die Antwort automatisch als JSON parst und Ihnen direkt ein JSON-Objekt ( responseJson
) als Funktionsargument, wenn Sie den Inhaltstyp der Antwort auf application/json
. Wenn Sie die Einstellung vergessen oder sich auf die Vorgabe von text/plain
または text/html
dann ist die responseJson
Argument würde Ihnen kein JSON-Objekt, sondern eine einfache Zeichenkette liefern und Sie müssten manuell mit JSON.parse()
was also völlig unnötig ist, wenn Sie den Inhaltstyp von vornherein richtig einstellen.
Rücksendung Map<String, String>
als JSON
Hier ist ein weiteres Beispiel, das Folgendes anzeigt Map<String, String>
como <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);
}
Und die 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>.
});
});
});
mit
<select id="someselect"></select>
Rücksendung List<Entity>
als JSON
Hier ist ein Beispiel, das Folgendes anzeigt List<Product>
en un <table>
wo die Product
Klasse hat die Eigenschaften Long id
, String name
y BigDecimal price
. Das 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);
}
Der JS-Code:
$(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>.
});
});
});
Rücksendung List<Entity>
als XML
Hier ist ein Beispiel, das im Grunde dasselbe tut wie das vorherige Beispiel, aber dann mit XML statt JSON. Wenn Sie JSP als XML-Ausgabegenerator verwenden, werden Sie sehen, dass es weniger mühsam ist, die Tabelle und alles andere zu codieren. JSTL ist auf diese Weise viel hilfreicher, da Sie damit über die Ergebnisse iterieren und serverseitige Datenformatierungen vornehmen können. Das 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);
}
Der JSP-Code (Hinweis: Wenn Sie die <table>
en un <jsp:include>
kann sie an anderer Stelle in einer Nicht-Ajax-Antwort wiederverwendet werden):
<?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>
Der JavaScript-Code:
$(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".
});
});
Sie wissen jetzt wahrscheinlich, warum XML für den speziellen Zweck der Aktualisierung eines HTML-Dokuments mit Ajax so viel leistungsfähiger ist als JSON. JSON ist zwar witzig, aber im Grunde genommen nur für so genannte "öffentliche Webdienste" nützlich. MVC-Frameworks wie JSF verwenden XML als Deckmantel für ihre Ajax-Magie.
Ajaxifizierung eines bestehenden Formulars
Sie können jQuery verwenden $.serialize()
um bestehende POST-Formulare einfach ajaxifizieren zu können, ohne sich mit dem Sammeln und Übergeben der einzelnen Formular-Eingabeparameter herumzuschlagen. Angenommen, ein bestehendes Formular, das ohne JavaScript/jQuery einwandfrei funktioniert (und sich daher anständig verschlechtert, wenn der Endbenutzer JavaScript deaktiviert hat):
<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>
Sie können sie schrittweise mit Ajax wie unten beschrieben erweitern:
$(document).on("submit", "#someform", function(event) {
var $form = $(this);
$.post($form.attr("action"), $form.serialize(), function(response) {
// ...
});
event.preventDefault(); // Important! Prevents submitting the form.
});
Sie können im Servlet zwischen normalen Anfragen und Ajax-Anfragen wie folgt unterscheiden:
@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-Formular-Plugin macht mehr oder weniger das Gleiche wie das obige jQuery-Beispiel, aber es hat zusätzliche transparente Unterstützung für multipart/form-data
Formulare, die für das Hochladen von Dateien erforderlich sind.
Manuelles Senden von Anfrageparametern an das Servlet
Wenn Sie überhaupt kein Formular haben, sondern nur mit dem Servlet "im Hintergrund" interagieren wollen, wobei Sie einige Daten POSTEN möchten, können Sie jQuery verwenden $.param()
um ein JSON-Objekt einfach in einen URL-kodierten Abfrage-String zu konvertieren.
var params = {
foo: "fooValue",
bar: "barValue",
baz: "bazValue"
};
$.post("someservlet", $.param(params), function(response) {
// ...
});
Das gleiche doPost()
Methode, wie hier oben gezeigt, wiederverwendet werden. Bitte beachten Sie, dass die obige Syntax auch mit $.get()
in jQuery und doGet()
im Servlet.
Manuelles Senden eines JSON-Objekts an ein Servlet
Wenn Sie jedoch beabsichtigen, das JSON-Objekt aus irgendeinem Grund als Ganzes und nicht als einzelne Anforderungsparameter zu senden, dann müssen Sie es mit JSON.stringify()
(nicht Teil von jQuery) und weisen jQuery an, den Inhaltstyp der Anfrage auf application/json
anstelle von (Standard) application/x-www-form-urlencoded
. Dies ist nicht möglich über $.post()
Komfortfunktion, sondern muss über $.ajax()
wie unten.
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) {
// ...
}
});
Bitte beachten Sie, dass viele Vorspeisen contentType
avec dataType
. En contentType
steht für den Typ des Anfrage Körper. Die Website dataType
steht für den (erwarteten) Typ des Antwort Körper, was in der Regel unnötig ist, da jQuery es bereits automatisch anhand der Antwort des Content-Type
Kopfzeile.
Um dann das JSON-Objekt im Servlet zu verarbeiten, das nicht als einzelne Request-Parameter, sondern als ganzer JSON-String auf die oben beschriebene Weise gesendet wird, müssen Sie den Request-Body nur noch manuell mit einem JSON-Tool parsen, anstatt mit getParameter()
auf die übliche Weise. Servlets unterstützen nämlich nicht application/json
formatierte Anfragen, sondern nur application/x-www-form-urlencoded
または multipart/form-data
formatierte Anfragen. Gson unterstützt auch das Parsen eines JSON-Strings in ein JSON-Objekt.
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();
// ...
Beachten Sie, dass dies alles etwas umständlicher ist, als wenn Sie einfach $.param()
. Normalerweise sollten Sie JSON.stringify()
nur, wenn der Zieldienst z. B. ein JAX-RS (RESTful)-Dienst ist, der aus irgendeinem Grund nur JSON-Strings und keine regulären Anfrageparameter verarbeiten kann.
Senden einer Weiterleitung vom Servlet
Es ist wichtig zu erkennen und zu verstehen, dass jede sendRedirect()
y forward()
Aufruf durch das Servlet bei einer Ajax-Anfrage würde nur weiterleiten oder umleiten die Ajax-Anfrage selbst und nicht das Hauptdokument/Fenster, aus dem die Ajax-Anfrage stammt. JavaScript/jQuery würde in einem solchen Fall nur die umgeleitete/weitergeleitete Antwort als responseText
in der Callback-Funktion. Wenn es sich um eine ganze HTML-Seite und nicht um eine Ajax-spezifische XML- oder JSON-Antwort handelt, können Sie lediglich das aktuelle Dokument durch diese ersetzen.
document.open();
document.write(responseText);
document.close();
Beachten Sie, dass dies die URL, die der Endbenutzer in der Adressleiste des Browsers sieht, nicht ändert. Es gibt also Probleme mit der Lesezeichenfähigkeit. Daher ist es viel besser, nur eine "Anweisung" für JavaScript/jQuery zurückzugeben, um eine Umleitung durchzuführen, anstatt den gesamten Inhalt der umgeleiteten Seite zurückzugeben. Z. B. durch Rückgabe eines booleschen Wertes oder einer 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;
}
// ...
}
Siehe auch: