Comment utiliser les servlets et Ajax?

334

Je suis très nouveau dans les applications Web et les servlets et j'ai la question suivante:

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

Amir Rachum
la source

Réponses:

561

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 Stringen texte brut

Créez un /some.jspcomme 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 /someservletou /someservlet/*comme ci-dessous (évidemment, le modèle d'URL est libre de votre choix, mais vous devrez modifier l' someservletURL 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.xmll'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/libdossier 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/plainou text/html, l' responseJsonargument 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 Productclasse a les propriétés Long id, String nameet 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-dataformulaires 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/jsonplace 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 contentTypeavec dataType. Le contentTypereprésente le type du corps de la demande . Le dataTyperepré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-Typetê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/jsondemandes formatées, mais uniquement application/x-www-form-urlencodedou les multipart/form-datademandes 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 responseTextvariable 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:

BalusC
la source
besoin d'analyser le json sur le dernier exemple.
shinzou
4
@kuhaku: non. Si vous lisez le post de haut en bas, vous comprendrez pourquoi.
BalusC
1
Cette réponse a été ma bouée de sauvetage pour le dernier mois environ lol. J'en apprends beaucoup. J'AIME l'exemple XML. Merci d'avoir mis cela ensemble! Une seule question si vous avez le temps. Y a-t-il une raison pour placer le dossier xml dans WEB-INF?
Jonathan Laliberte
1
@JonathanLaliberte: Les utilisateurs ne peuvent donc pas les télécharger.
BalusC
@BalusC, votre exemple XML est génial, merci. Mais j'obtiens «Impossible d'obtenir la propriété« remplacer »de référence non définie ou nulle» pour $("#somediv").html($(responseXml).find("data").html())cette ligne. Il indique également "Nombre d'arguments incorrect ou affectation de propriété non valide". Je peux également voir que mon XML est rempli de données lorsque je le débogue. Des idées ?
629
14

La bonne façon de mettre à jour la page actuellement affichée dans le navigateur de l'utilisateur (sans la recharger) est de faire exécuter du code dans le navigateur pour mettre à jour le DOM de la page.

Ce code est généralement javascript qui est intégré ou lié à partir de 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, c'est AJAX classique.)

Il est également possible d'implémenter ce genre de chose en utilisant un plugin ou un module complémentaire de 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 de code natif écrivent normalement dans un cadre graphique intégré à la page.)

Stephen C
la source
13

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

Ici, nous allons créer l'exemple simple pour créer le formulaire de connexion à l'aide de 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 Ajax Sample

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

Code 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);
        } 
    }
}
Mitul Maheshwari
la source
8
$.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);
 }
});
SUBZ
la source
7

Ajax (également AJAX), acronyme de JavaScript asynchrone et 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 les récupérer de manière asynchrone. Voici un exemple de code:

Fonction de script Java de page JSP pour soumettre des données à la 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 renvoyées à jsp au format xml (Vous pouvez également utiliser du texte. Il vous 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>");
}
user3468976
la source
5

Normalement, vous ne pouvez pas mettre à jour une page à partir d'un servlet. Le client (navigateur) doit demander une mise à jour. Le client Eiter charge une toute nouvelle page ou demande une mise à jour d'une partie d'une page existante. Cette technique est appelée Ajax.

Peter Knego
la source
4

Utiliser Bootstrap Multi Select

Ajax

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

Dans Servlet

request.getParameter("input")
Thakhani Tharage
la source