350 votes

Comment utiliser les Servlets et Ajax ?

Je suis très novice en matière d'applications Web et de Servlets et j'ai la question suivante :

Chaque fois que j'imprime quelque chose à l'intérieur de la servlet et que je l'appelle par le navigateur web, celle-ci renvoie une nouvelle page contenant ce texte. Existe-t-il un moyen d'imprimer le texte dans la page actuelle en utilisant Ajax ?

582voto

BalusC Points 498232

En effet, le mot clé est "ajax" : JavaScript asynchrone et XML . Cependant, ces dernières années, c'est plus que souvent JavaScript asynchrone et JSON . En gros, vous laissez JS exécuter une requête HTTP asynchrone et mettre à jour l'arbre DOM HTML en fonction des données de la réponse.

Puisque c'est plutôt un fastidieux pour le faire fonctionner sur tous les navigateurs (en particulier Internet Explorer par rapport à d'autres), il existe de nombreuses bibliothèques JavaScript qui simplifient cette tâche en une seule fonction et couvrent autant que possible les bogues et les problèmes spécifiques aux navigateurs, tels que jQuery , Prototype , Mootools . Puisque jQuery est le plus populaire de nos jours, je vais l'utiliser dans les exemples ci-dessous.

Exemple de retour de coup d'envoi String en texte brut

Créer un /some.jsp comme ci-dessous (note : les extraits de code dans cette réponse ne s'attendent pas à ce que le fichier JSP soit placé dans un sous-dossier, si c'est le cas, modifiez l'URL de la servlet en conséquence à partir de "someservlet" a "${pageContext.request.contextPath}/someservlet" (il est simplement omis dans les extraits de code pour des raisons de brièveté) :

<!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 une servlet avec un doGet() qui ressemblent à 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.
}

Mapper cette servlet sur un modèle d'URL de /someservlet o /someservlet/* comme ci-dessous (évidemment, le modèle d'URL est libre de votre choix, mais vous devrez modifier l'adresse de l'utilisateur. someservlet URL dans les exemples de code JS sur toute la place en conséquence) :

package com.example;

@WebServlet("/someservlet/*")
public class SomeServlet extends HttpServlet {
    // ...
}

Ou, si vous n'êtes pas encore sur un conteneur compatible avec Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6, etc. ou plus récent), vous pouvez le mettre en correspondance dans le fichier web.xml à l'ancienne (voir aussi notre page wiki sur les 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 le site 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 du servlet.

Retour à List<String> en JSON

Avec JSON au lieu du texte en clair comme format de réponse, vous pouvez même aller un peu plus loin. Cela permet plus de dynamique. Tout d'abord, vous aimeriez disposer d'un outil permettant de convertir les objets Java en chaînes JSON. Il en existe de nombreux (voir le bas de la page cette page pour un aperçu). Mon préféré est Google Gson . Téléchargez et placez son fichier JAR dans /WEB-INF/lib de votre application web.

Voici un exemple qui affiche List<String> como <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 à application/json . Si vous oubliez de le définir ou si vous vous fiez à un défaut de text/plain o text/html alors le responseJson ne vous donnera pas un objet JSON, mais une simple chaîne de caractères et vous devrez manipuler manuellement les paramètres suivants JSON.parse() par la suite, ce qui est donc totalement inutile si vous définissez correctement le type de contenu en premier lieu.

Retour à Map<String, String> en JSON

Voici un autre exemple qui affiche 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);
}

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 à List<Entity> en JSON

Voici un exemple qui affiche List<Product> dans un <table> où le Product a les propriétés suivantes Long id , String name y 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> en tant que XML

Voici un exemple qui fait effectivement la même chose que l'exemple précédent, mais avec XML au lieu de JSON. En utilisant JSP comme générateur de sortie XML, vous verrez qu'il est moins fastidieux de coder la table et tout le reste. JSTL est de cette façon beaucoup plus utile car vous pouvez l'utiliser pour itérer sur les résultats et effectuer le formatage des données côté serveur. La 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 (note : si vous mettez le code <table> dans un <jsp:include> il peut être réutilisé 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 avez maintenant probablement compris pourquoi XML est tellement plus puissant que JSON dans le but particulier de mettre à jour un document HTML en utilisant Ajax. JSON est amusant, mais après tout, il n'est généralement utile que pour les "services web publics". Les frameworks MVC comme JSF utilisent XML sous la couverture de leur magie ajax.

Ajaxifier un formulaire existant

Vous pouvez utiliser jQuery $.serialize() pour ajaxifier facilement les formulaires POST existants sans avoir à se préoccuper de la collecte et du passage des paramètres de saisie des formulaires individuels. En partant d'un formulaire existant qui fonctionne parfaitement bien sans JavaScript/jQuery (et qui 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.
});

Dans la servlet, vous pouvez faire la distinction entre les requêtes normales et les requêtes 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.
    }
}

El 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 multipart/form-data comme l'exige le téléchargement de fichiers.

Envoi manuel des paramètres de la demande au servlet

Si vous n'avez pas de formulaire, mais que vous souhaitez simplement interagir avec le servlet "en arrière-plan" en envoyant des données, vous pouvez utiliser jQuery. $.param() pour convertir facilement un objet JSON en une chaîne de requête codée en URL.

var params = {
    foo: "fooValue",
    bar: "barValue",
    baz: "bazValue"
};

$.post("someservlet", $.param(params), function(response) {
    // ...
});

Le même doPost() comme indiqué ci-dessus peut être réutilisé. Notez que la syntaxe ci-dessus fonctionne également avec $.get() dans jQuery et doGet() dans la servlet.

Envoi manuel d'un objet JSON à la servlet

Si, pour une raison quelconque, vous avez l'intention d'envoyer l'objet JSON dans son ensemble plutôt que sous la forme de paramètres de requête individuels, vous devrez le sérialiser en une chaîne de caractères à l'aide de la commande JSON.stringify() (qui ne fait pas partie de jQuery) et demander à jQuery de définir le type de contenu de la requête comme étant application/json au lieu de (par défaut) application/x-www-form-urlencoded . Cela ne peut pas être fait via $.post() mais elle doit être réalisée via $.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 de starters mélangent contentType con dataType . Le site contentType représente le type de la demande corps. Le site dataType représente le type (attendu) de la réponse ce qui n'est généralement pas nécessaire puisque jQuery le détecte déjà automatiquement en se basant sur l'élément de réponse Content-Type en-tête.

Ensuite, pour traiter l'objet JSON dans la servlet qui n'est pas envoyé en tant que paramètres de requête individuels mais en tant que chaîne JSON entière de la manière décrite ci-dessus, il suffit d'analyser manuellement le corps de la requête à l'aide d'un outil JSON au lieu d'utiliser getParameter() de la manière habituelle. A savoir, les servlets ne supportent pas application/json des demandes formatées, mais seulement application/x-www-form-urlencoded o multipart/form-data demandes formatées. Gson prend également en charge l'analyse d'une chaîne JSON en 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 ceci est plus maladroit que d'utiliser simplement $.param() . Normalement, vous voulez utiliser JSON.stringify() uniquement si le service cible est, par exemple, un service JAX-RS (RESTful) qui, pour une raison quelconque, ne peut consommer que des chaînes JSON et non des paramètres de requête ordinaires.

Envoi d'une redirection à partir d'une servlet

Il est important de réaliser et de comprendre que toute sendRedirect() y forward() par la servlet sur une requête ajax ne ferait que transférer ou rediriger la requête ajax elle-même et non pas le document/fenêtre principal d'où provient la requête ajax. Dans ce cas, JavaScript/jQuery ne récupère que la réponse redirigée/transférée en tant que responseText dans la fonction de rappel. Si elle 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 celle-ci.

document.open();
document.write(responseText);
document.close();

Notez que cela ne change pas l'URL que l'utilisateur final voit dans la barre d'adresse du navigateur. Il y a donc des problèmes avec la possibilité d'ajouter des signets. Par conséquent, il est préférable de renvoyer une "instruction" à JavaScript/jQuery pour effectuer une redirection plutôt que de renvoyer le contenu complet 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 aussi :

0 votes

Besoin de parser le json sur le dernier exemple.

4 votes

@kuhaku : nope. Si tu lis le post de haut en bas, tu vas comprendre pourquoi.

1 votes

Cette réponse a été ma bouée de sauvetage pendant le dernier mois environ lol. J'en ai beaucoup appris. J'adore l'exemple XML. Merci de l'avoir mis en place ! Une question de noob cependant si vous avez le temps. Y a-t-il une raison de placer le dossier xml dans WEB-INF ?

14voto

Stephen C Points 255558

La bonne façon de mettre à jour la page actuellement affichée dans le navigateur de l'utilisateur (sans la recharger) est de faire en sorte qu'un code exécuté dans le navigateur mette à jour le DOM de la page.

Ce code est généralement du javascript intégré ou lié à la page HTML, d'où la suggestion AJAX. (En fait, si nous supposons que le texte mis à jour provient du serveur via une requête HTTP, il s'agit d'AJAX classique).

Il est également possible d'implémenter ce genre de choses à l'aide d'un plugin ou d'un module complémentaire du navigateur, bien qu'il puisse être difficile pour un plugin d'accéder aux structures de données du navigateur pour mettre à jour le DOM. (Les plugins en code natif écrivent normalement dans un cadre graphique qui est intégré à la page).

13voto

Mitul Maheshwari Points 1101

Je vais vous montrer un exemple complet de servlet et comment faire un appel ajax.

Ici, nous allons créer un exemple simple pour créer le formulaire de connexion en utilisant un 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>  

Voici un exemple d'ajax

       $.ajax
        ({
            type: "POST",           
            data: 'LoginServlet='+name+'&name='+type+'&pass='+password,
            url: url,
        success:function(content)
        {
                $('#center').html(content);           
            }           
        });

Code du servlet LoginServlet :-

    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);
        } 
    }
}

7voto

user3468976 Points 31

Ajax (également AJAX, acronyme de Asynchronous JavaScript and XML) est un groupe de techniques de développement web interdépendantes utilisées côté client pour créer des applications web asynchrones. Avec Ajax, les applications Web peuvent envoyer des données à un serveur et en récupérer de manière asynchrone. Voici un exemple de code :

Page Jsp java script fonction pour soumettre des données à servlet avec deux variables firstName et lastName :

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 pour lire les données et les renvoyer à la jsp au format xml (vous pouvez aussi utiliser du texte). Il suffit de changer le contenu de la réponse en texte et de rendre les données sur la fonction 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>");
}

5voto

Peter Knego Points 57985

Normalement, vous ne pouvez pas mettre à jour une page à partir d'une servlet. Le client (navigateur) doit demander une mise à jour. Le client peut charger une nouvelle page entière ou demander une mise à jour d'une partie d'une page existante. Cette technique est appelée Ajax.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X