In der Tat lautet das Schlüsselwort "ajax": Asynchrones JavaScript und XML . In den letzten Jahren ist es jedoch mehr als oft asynchrones JavaScript und JSON . Grundsätzlich lassen Sie JS eine asynchrone HTTP-Anforderung ausführen und den HTML-DOM-Baum basierend auf den Antwortdaten aktualisieren.
Da es ziemlich mühsam ist , alle Browser (insbesondere Internet Explorer im Vergleich zu anderen) zu verwenden, gibt es zahlreiche JavaScript-Bibliotheken, die dies in einzelnen Funktionen vereinfachen und so viele browserspezifische Fehler / Macken wie möglich abdecken wie jQuery , Prototype , Mootools . Da jQuery heutzutage am beliebtesten ist, werde ich es in den folgenden Beispielen verwenden.
Kickoff-Beispiel, das String
als einfacher Text zurückgegeben wird
Erstellen /some.jsp
Sie ein "Gefällt mir" (Hinweis: Der Code erwartet nicht, dass die JSP-Datei in einem Unterordner abgelegt wird. Wenn Sie dies tun, ändern Sie die Servlet-URL entsprechend):
<!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 folgendermaßen 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.
}
Ordnen Sie dieses Servlet einem URL-Muster von /someservlet
oder /someservlet/*
wie folgt zu (natürlich steht das URL-Muster Ihrer Wahl frei, aber Sie müssen die someservlet
URL in JS-Codebeispielen an allen Stellen entsprechend ändern ):
@WebServlet("/someservlet/*")
public class SomeServlet extends HttpServlet {
// ...
}
Wenn Sie sich noch nicht in einem Servlet 3.0-kompatiblen Container befinden (Tomcat 7, Glassfish 3, JBoss AS 6 usw. oder neuer), ordnen Sie ihn auf web.xml
die altmodische Weise zu (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 Datei http: // localhost: 8080 / context / test.jsp im Browser und drücken Sie die Taste. Sie werden sehen, dass der Inhalt des div mit der Servlet-Antwort aktualisiert wird.
Rückkehr List<String>
als JSON
Mit JSON anstelle von Klartext als Antwortformat können Sie sogar einige Schritte weiter gehen. Es ermöglicht mehr Dynamik. Zunächst möchten Sie ein Tool zum Konvertieren zwischen Java-Objekten und JSON-Zeichenfolgen haben. Es gibt auch viele davon ( eine Übersicht finden Sie unten auf dieser Seite ). Mein persönlicher Favorit ist Google Gson . Laden Sie die JAR-Datei herunter und legen Sie sie im /WEB-INF/lib
Ordner Ihrer Webanwendung ab.
Hier ist ein Beispiel, das List<String>
als angezeigt wird <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 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 $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 analysiert und Ihnen direkt ein JSON-Objekt ( responseJson
) als Funktionsargument gibt, wenn Sie den Antwortinhaltstyp auf festlegen application/json
. Wenn Sie vergessen, es festzulegen oder sich auf eine Standardeinstellung von text/plain
oder zu verlassen text/html
, erhalten Sie mit dem responseJson
Argument kein JSON-Objekt, sondern eine einfache Vanille-Zeichenfolge, mit der Sie anschließend manuell herumspielen müssen. Dies JSON.parse()
ist daher völlig unnötig, wenn Sie dies tun Stellen Sie den Inhaltstyp an erster Stelle ein.
Rückkehr Map<String, String>
als JSON
Hier ist ein weiteres Beispiel , das zeigt , Map<String, String>
wie <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ückkehr List<Entity>
als JSON
Hier ist ein Beispiel, das List<Product>
an einer Stelle angezeigt wird, <table>
an der die Product
Klasse die Eigenschaften hat Long id
, String name
und 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ückgabe List<Entity>
als XML
Hier ist ein Beispiel, das effektiv dasselbe wie im vorherigen Beispiel tut, jedoch mit XML anstelle von JSON. Wenn Sie JSP als XML-Ausgabegenerator verwenden, werden Sie feststellen, dass das Codieren der Tabelle und aller Elemente weniger mühsam ist. JSTL ist auf diese Weise viel hilfreicher, da Sie es tatsächlich verwenden können, um die Ergebnisse zu durchlaufen und eine serverseitige Datenformatierung durchzuführen. 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 den <table>
in a eingeben <jsp:include>
, kann er 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 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(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 werden wahrscheinlich inzwischen erkennen, warum XML für den speziellen Zweck der Aktualisierung eines HTML-Dokuments mit Ajax so viel leistungsfähiger als JSON ist. JSON ist lustig, aber im Allgemeinen nur für sogenannte "öffentliche Webdienste" nützlich. MVC-Frameworks wie JSF verwenden XML unter der Decke für ihre Ajax-Magie.
Ajaxifizierung eines vorhandenen Formulars
Mit jQuery $.serialize()
können Sie vorhandene POST-Formulare auf einfache Weise optimieren, ohne die einzelnen Formulareingabeparameter erfassen und übergeben zu müssen. Angenommen, ein vorhandenes Formular funktioniert ohne JavaScript / jQuery einwandfrei (und verschlechtert sich daher ordnungsgemäß, 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 es schrittweise mit Ajax wie folgt verbessern:
$(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 wie folgt zwischen normalen Anforderungen und Ajax-Anforderungen 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.
}
}
Das jQuery Form-Plugin funktioniert weniger oder mehr wie im obigen jQuery-Beispiel, bietet jedoch zusätzliche transparente Unterstützung für multipart/form-data
Formulare, die für das Hochladen von Dateien erforderlich sind.
Manuelles Senden von Anforderungsparametern an das Servlet
Wenn Sie überhaupt kein Formular haben, sondern nur "im Hintergrund" mit dem Servlet interagieren möchten, um einige Daten zu veröffentlichen, können Sie mit jQuery $.param()
ein JSON-Objekt einfach in ein URL-codiertes Objekt konvertieren Abfragezeichenfolge.
var params = {
foo: "fooValue",
bar: "barValue",
baz: "bazValue"
};
$.post("someservlet", $.param(params), function(response) {
// ...
});
Die gleiche doPost()
Methode wie hier oben kann wiederverwendet werden. Beachten Sie, dass die obige Syntax auch $.get()
in jQuery und doGet()
im Servlet funktioniert .
Manuelles Senden des JSON-Objekts an das Servlet
Wenn Sie jedoch aus irgendeinem Grund beabsichtigen, das JSON-Objekt als Ganzes anstatt als einzelne Anforderungsparameter zu senden, müssen Sie es mithilfe von JSON.stringify()
(nicht Teil von jQuery) in eine Zeichenfolge serialisieren und jQuery anweisen, application/json
stattdessen den Anforderungsinhaltstyp festzulegen von (Standard) application/x-www-form-urlencoded
. Dies kann nicht über die $.post()
Komfortfunktion erfolgen, sondern muss $.ajax()
wie folgt erfolgen.
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) {
// ...
}
});
Zu beachten ist, dass viele Starter mischen contentType
mit dataType
. Das contentType
repräsentiert den Typ des Anforderungshauptteils . Das dataType
stellt den (erwarteten) Typ des Antwortkörpers dar , der normalerweise nicht erforderlich ist, da jQuery ihn bereits anhand des Content-Type
Headers der Antwort automatisch erkennt .
Um das JSON-Objekt im Servlet zu verarbeiten, das nicht als einzelne Anforderungsparameter, sondern als ganze JSON-Zeichenfolge auf die oben beschriebene Weise gesendet wird, müssen Sie den Anforderungshauptteil nur manuell mit einem JSON-Tool analysieren, anstatt getParameter()
das übliche zu verwenden Weg. Servlets unterstützen nämlich keine application/json
formatierten Anforderungen, sondern nur application/x-www-form-urlencoded
oder multipart/form-data
formatierte Anforderungen. Gson unterstützt auch das Parsen einer JSON-Zeichenfolge 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 ungeschickter ist als nur zu verwenden $.param()
. Normalerweise möchten Sie JSON.stringify()
nur verwenden, wenn der Zieldienst beispielsweise ein JAX-RS-Dienst (RESTful) ist, der aus irgendeinem Grund nur JSON-Zeichenfolgen und keine regulären Anforderungsparameter verwenden kann.
Senden einer Weiterleitung vom Servlet
Zu erkennen und zu verstehen , wichtig ist , dass jeder sendRedirect()
und forward()
durch das Servlet auf einer Ajax - Anforderung würde nur vorwärts Anruf oder umleiten den Ajax - Request selbst und nicht das Hauptdokument / Fenster , in dem die Ajax - Anforderung stammte. JavaScript / jQuery würde in diesem Fall nur die umgeleitete / weitergeleitete Antwort als responseText
Variable in der Rückruffunktion abrufen . 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 dieses ersetzen.
document.open();
document.write(responseText);
document.close();
Beachten Sie, dass dies die URL nicht ändert, wie der Endbenutzer in der Adressleiste des Browsers sieht. Es gibt also Probleme mit der Lesefä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. Zum Beispiel durch Rückgabe eines Booleschen Werts 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: