En effet, le mot clé est "ajax": JavaScript asynchrone et XML . Cependant, ces dernières années, il s'agit plus que souvent de JavaScript et JSON asynchrones . Fondamentalement, vous laissez JS exécuter une requête HTTP asynchrone et mettre à jour l'arborescence DOM HTML en fonction des données de réponse.
Étant donné que c'est un travail assez fastidieux de le faire fonctionner sur tous les navigateurs (en particulier Internet Explorer par rapport à d'autres), il existe de nombreuses bibliothèques JavaScript qui simplifient cela dans des fonctions uniques et couvrent autant de bugs / bizarreries spécifiques au navigateur sous les hottes , tels que jQuery , Prototype , Mootools . Étant donné que jQuery est le plus populaire de nos jours, je vais l'utiliser dans les exemples ci-dessous.
Exemple de lancement renvoyant String
en texte brut
Créez un /some.jsp
comme ci-dessous (remarque: le code ne s'attend pas à ce que le fichier JSP soit placé dans un sous-dossier, si vous le faites, modifiez l'URL du servlet en conséquence):
<!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>
Créez un servlet avec une doGet()
méthode qui ressemble à ceci:
@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.
}
Mappez cette servlet sur un modèle d'URL /someservlet
ou /someservlet/*
comme ci-dessous (évidemment, le modèle d'URL est libre de votre choix, mais vous devrez modifier l' someservlet
URL dans les exemples de code JS partout en conséquence):
@WebServlet("/someservlet/*")
public class SomeServlet extends HttpServlet {
// ...
}
Ou, lorsque vous n'êtes pas encore sur un conteneur compatible Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6, etc. ou plus récent), mappez-le à web.xml
l'ancienne (voir également notre page wiki Servlets ):
<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>
Ouvrez maintenant http: // localhost: 8080 / context / test.jsp dans le navigateur et appuyez sur le bouton. Vous verrez que le contenu du div est mis à jour avec la réponse de la servlet.
Retour en List<String>
tant que JSON
Avec JSON au lieu du texte en clair comme format de réponse, vous pouvez même aller plus loin. Il permet plus de dynamique. Tout d'abord, vous aimeriez avoir un outil pour convertir entre les objets Java et les chaînes JSON. Il y en a aussi beaucoup (voir le bas de cette page pour un aperçu). Mon préféré est Google Gson . Téléchargez et mettez son fichier JAR dans le /WEB-INF/lib
dossier de votre application web.
Voici un exemple qui s'affiche List<String>
sous la forme <ul><li>
. Le 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);
}
Le code 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 $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>.
});
});
});
Notez que jQuery analyse automatiquement la réponse en tant que JSON et vous donne directement un objet JSON ( responseJson
) comme argument de fonction lorsque vous définissez le type de contenu de la réponse sur application/json
. Si vous oubliez de le définir ou si vous vous reposez sur une valeur par défaut de text/plain
ou text/html
, l' responseJson
argument ne vous donnera pas un objet JSON, mais une chaîne de vanille simple et vous devrez manipuler manuellement JSON.parse()
après, ce qui est donc totalement inutile si vous définissez le type de contenu en premier lieu.
Retour en Map<String, String>
tant que JSON
Voici un autre exemple qui s'affiche Map<String, String>
comme <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);
}
Et le 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>.
});
});
});
avec
<select id="someselect"></select>
Retour en List<Entity>
tant que JSON
Voici un exemple qui s'affiche List<Product>
dans un <table>
où la Product
classe a les propriétés Long id
, String name
et BigDecimal price
. Le 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);
}
Le code 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>.
});
});
});
Retour List<Entity>
au format XML
Voici un exemple qui fait effectivement la même chose que l'exemple précédent, mais avec XML au lieu de JSON. Lorsque vous utilisez JSP comme générateur de sortie XML, vous verrez qu'il est moins fastidieux de coder la table et tout. JSTL est de cette façon beaucoup plus utile car vous pouvez réellement l'utiliser pour parcourir les résultats et effectuer un formatage des données côté serveur. Le 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);
}
Le code JSP (remarque: si vous mettez le <table>
dans un <jsp:include>
, il peut être réutilisable ailleurs dans une réponse non 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>
Le code 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(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".
});
});
Vous comprendrez probablement maintenant pourquoi XML est tellement plus puissant que JSON dans le but particulier de mettre à jour un document HTML à l'aide d'Ajax. JSON est drôle, mais après tout, il n'est généralement utile que pour les soi-disant «services Web publics». Les frameworks MVC comme JSF utilisent XML sous les couvertures pour leur magie ajax.
Ajaxification d'un formulaire existant
Vous pouvez utiliser jQuery $.serialize()
pour ajuster facilement les formulaires POST existants sans jouer avec la collecte et la transmission des paramètres d'entrée de formulaire individuels. En supposant un formulaire existant qui fonctionne parfaitement bien sans JavaScript / jQuery (et se dégrade donc gracieusement lorsque l'utilisateur final a désactivé 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>
Vous pouvez l'améliorer progressivement avec ajax comme ci-dessous:
$(document).on("submit", "#someform", function(event) {
var $form = $(this);
$.post($form.attr("action"), $form.serialize(), function(response) {
// ...
});
event.preventDefault(); // Important! Prevents submitting the form.
});
Vous pouvez dans le servlet distinguer les demandes normales des demandes ajax comme ci-dessous:
@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.
}
}
Le plugin jQuery Form fait plus ou moins la même chose que l'exemple jQuery ci-dessus, mais il a un support transparent supplémentaire pour les multipart/form-data
formulaires comme requis par les téléchargements de fichiers.
Envoi manuel des paramètres de requête à la servlet
Si vous n'avez pas de formulaire du tout, mais que vous vouliez simplement interagir avec le servlet "en arrière-plan" par lequel vous souhaitez publier des données, vous pouvez utiliser jQuery $.param()
pour convertir facilement un objet JSON en un URL encodé chaîne de requête.
var params = {
foo: "fooValue",
bar: "barValue",
baz: "bazValue"
};
$.post("someservlet", $.param(params), function(response) {
// ...
});
La même doPost()
méthode que celle illustrée ci-dessus peut être réutilisée. Notez que la syntaxe ci-dessus fonctionne également avec $.get()
dans jQuery et doGet()
dans servlet.
Envoi manuel d'un objet JSON à la servlet
Si vous avez toutefois l'intention d'envoyer l'objet JSON dans son ensemble au lieu de paramètres de demande individuels pour une raison quelconque, vous devez alors le sérialiser en une chaîne à l'aide de JSON.stringify()
(ne fait pas partie de jQuery) et demander à jQuery de définir le type de contenu de la demande à la application/json
place de (par défaut) application/x-www-form-urlencoded
. Cela ne peut pas être fait via la $.post()
fonction confort, mais doit être fait $.ajax()
comme ci-dessous.
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) {
// ...
}
});
Notez que beaucoup d'entrées se mélangent contentType
avec dataType
. Le contentType
représente le type du corps de la demande . Le dataType
représente le type (attendu) du corps de la réponse , ce qui n'est généralement pas nécessaire car jQuery le détecte déjà automatiquement en fonction de l'en- Content-Type
tête de la réponse .
Ensuite, afin de traiter l'objet JSON dans le servlet qui n'est pas envoyé en tant que paramètres de demande individuels mais comme une chaîne JSON entière de la manière ci-dessus, il vous suffit d'analyser manuellement le corps de la demande à l'aide d'un outil JSON au lieu d'utiliser getParameter()
l'habituel façon. À savoir, les servlets ne prennent pas en charge les application/json
demandes formatées, mais uniquement application/x-www-form-urlencoded
ou les multipart/form-data
demandes formatées. Gson prend également en charge l'analyse d'une chaîne JSON dans un objet 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();
// ...
Notez que tout cela est plus maladroit que de simplement l'utiliser $.param()
. Normalement, vous ne souhaitez utiliser JSON.stringify()
que si le service cible est par exemple un service JAX-RS (RESTful) qui, pour une raison quelconque, est uniquement capable de consommer des chaînes JSON et non des paramètres de requête réguliers.
Envoi d'une redirection depuis le servlet
Il est important de se rendre compte et comprendre est que tout sendRedirect()
et forward()
appel par le servlet sur une demande ajax serait seulement vers l' avant ou rediriger la demande ajax lui - même et non le document principal / fenêtre où la demande de paiement ajax origine. Dans ce cas, JavaScript / jQuery ne récupère que la réponse redirigée / transmise en tant que responseText
variable dans la fonction de rappel. S'il représente une page HTML entière et non une réponse XML ou JSON spécifique à ajax, alors tout ce que vous pouvez faire est de remplacer le document actuel par lui.
document.open();
document.write(responseText);
document.close();
Notez que cela ne change pas l'URL comme l'utilisateur final le voit dans la barre d'adresse du navigateur. Il y a donc des problèmes de signetabilité. Par conséquent, il est préférable de renvoyer simplement une "instruction" pour que JavaScript / jQuery effectue une redirection au lieu de renvoyer tout le contenu de la page redirigée. Par exemple, en renvoyant un booléen ou une 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;
}
// ...
}
Voir également: