Come usare Servlet e Ajax?


334

Sono molto nuovo di app e servlet Web e ho la seguente domanda:

Ogni volta che stampo qualcosa all'interno del servlet e lo chiamo dal browser web, restituisce una nuova pagina contenente quel testo. C'è un modo per stampare il testo nella pagina corrente usando Ajax?

Risposte:


561

In effetti, la parola chiave è "ajax": JavaScript asincrono e XML . Tuttavia, negli ultimi anni è più che spesso JavaScript asincrono e JSON . Fondamentalmente, si consente a JS di eseguire una richiesta HTTP asincrona e aggiornare l'albero DOM HTML in base ai dati di risposta.

Dal momento che è un lavoro piuttosto noioso farlo funzionare su tutti i browser (specialmente Internet Explorer rispetto ad altri), ci sono molte librerie JavaScript che lo semplificano in singole funzioni e coprono il maggior numero possibile di bug / strane specifici del browser sotto i cofani , come jQuery , Prototype , Mootools . Poiché jQuery è più popolare in questi giorni, lo userò negli esempi seguenti.

Esempio di avvio che ritorna Stringcome testo normale

Crea un /some.jsplike di seguito (nota: il codice non prevede che il file JSP venga inserito in una sottocartella, in tal caso, modifica di conseguenza l'URL del servlet):

<!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>

Crea un servlet con un doGet()metodo simile al seguente:

@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.
}

Mappa questo servlet su un pattern URL di /someservleto /someservlet/*come di seguito (ovviamente, il pattern URL è gratuito a tua scelta, ma dovresti modificare l' someservletURL negli esempi di codice JS in tutto il luogo di conseguenza):

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

Oppure, quando non sei ancora su un contenitore compatibile con Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6, ecc. O più recenti), quindi mappaloweb.xml alla vecchia maniera (vedi anche la nostra pagina wiki Servlet ):

<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>

Ora apri http: // localhost: 8080 / context / test.jsp nel browser e premi il pulsante. Vedrai che il contenuto del div viene aggiornato con la risposta servlet.

Tornando List<String>come JSON

Con JSON invece del testo in chiaro come formato di risposta è possibile ottenere ulteriori passi. Consente una maggiore dinamica. Innanzitutto, ti piacerebbe avere uno strumento per convertire tra oggetti Java e stringhe JSON. Ce ne sono anche molti (vedi il fondo di questa pagina per una panoramica). Il mio preferito è Google Gson . Scarica e metti il ​​suo file JAR nella /WEB-INF/libcartella della tua applicazione web.

Ecco un esempio che viene visualizzato List<String>come <ul><li>. Il 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);
}

Il codice 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>.
        });
    });
});

Si noti che jQuery analizza automaticamente la risposta come JSON e fornisce direttamente un oggetto JSON ( responseJson) come argomento della funzione quando si imposta il tipo di contenuto della risposta su application/json. Se dimentichi di impostarlo o fai affidamento su un valore predefinito di text/plaino text/html, allora l' responseJsonargomento non ti darebbe un oggetto JSON, ma una semplice stringa di vaniglia e avresti bisogno di armeggiare manualmente in JSON.parse()seguito, il che è quindi totalmente inutile se tu imposta il tipo di contenuto al primo posto.

Tornando Map<String, String>come JSON

Ecco un altro esempio che viene visualizzato Map<String, String>come <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);
}

E il 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>.
        });
    });
});

con

<select id="someselect"></select>

Tornando List<Entity>come JSON

Ecco un esempio che mostra List<Product>in <table>cui la Productclasse ha le proprietà Long id, String namee BigDecimal price. Il 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);
}

Il codice 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>.
        });
    });
});

Restituendo List<Entity>come XML

Ecco un esempio che funziona esattamente come nell'esempio precedente, ma poi con XML anziché JSON. Quando usi JSP come generatore di output XML, vedrai che è meno noioso codificare la tabella e tutto il resto. JSTL è molto più utile in quanto è possibile utilizzarlo per scorrere i risultati ed eseguire la formattazione dei dati lato server. Il 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);
}

Il codice JSP (nota: se si inserisce <table>in a <jsp:include>, potrebbe essere riutilizzabile altrove in una risposta 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>

Il codice 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".
    });
});

Ormai probabilmente ti renderai conto del perché XML è molto più potente di JSON per il particolare scopo di aggiornare un documento HTML usando Ajax. JSON è divertente, ma dopo tutto generalmente utile solo per i cosiddetti "servizi web pubblici". I framework MVC come JSF usano XML sotto le copertine per la loro magia ajax.

Ajaxifying un modulo esistente

È possibile utilizzare jQuery $.serialize()per ajaxificare facilmente i moduli POST esistenti senza armeggiare con la raccolta e il passaggio dei singoli parametri di input del modulo. Supponendo un modulo esistente che funzioni perfettamente senza JavaScript / jQuery (e quindi degrada con garbo quando l'utente finale ha JavaScript disabilitato):

<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>

Puoi migliorarlo progressivamente con ajax come di seguito:

$(document).on("submit", "#someform", function(event) {
    var $form = $(this);

    $.post($form.attr("action"), $form.serialize(), function(response) {
        // ...
    });

    event.preventDefault(); // Important! Prevents submitting the form.
});

Nel servlet puoi distinguere tra richieste normali e richieste Ajax come di seguito:

@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.
    }
}

Il plug-in jQuery Form fa meno o più lo stesso dell'esempio jQuery sopra, ma ha un supporto trasparente aggiuntivo per i multipart/form-datamoduli come richiesto dai caricamenti di file.

Invio manuale dei parametri di richiesta al servlet

Se non si dispone di un modulo, ma si desidera solo interagire con il servlet "in background" per cui si desidera POST alcuni dati, è possibile utilizzare jQuery $.param()per convertire facilmente un oggetto JSON in un codice codificato URL stringa della domanda.

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

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

Lo stesso doPost()metodo mostrato qui sopra può essere riutilizzato. Nota che la sintassi sopra funziona anche con $.get()jQuery e doGet()in servlet.

Invio manuale dell'oggetto JSON al servlet

Se tuttavia si intende inviare l'oggetto JSON nel suo complesso anziché come singoli parametri di richiesta per qualche motivo, è necessario serializzarlo su una stringa utilizzando JSON.stringify()(non parte di jQuery) e indicare a jQuery di impostare application/jsoninvece il tipo di contenuto della richiesta di (impostazione predefinita) application/x-www-form-urlencoded. Questo non può essere fatto tramite la $.post()funzione di convenienza, ma deve essere fatto $.ajax()come di seguito.

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) {
        // ...
    }
});

Si noti che molti antipasti si mescolano contentTypecon dataType. Il contentTyperappresenta il tipo di corpo della richiesta . Il dataTyperappresenta il tipo (atteso) della risposta corpo, che di solito è superflua in quanto già jQuery autorileva è basato su di risposta Content-Typedi intestazione.

Quindi, al fine di elaborare l'oggetto JSON nel servlet che non viene inviato come singoli parametri di richiesta ma come una stringa JSON intera nel modo sopra, è necessario solo analizzare manualmente il corpo della richiesta utilizzando uno strumento JSON invece di utilizzare getParameter()il solito modo. Vale a dire, i servlet non supportano application/jsonrichieste formattate, ma solo application/x-www-form-urlencodedo multipart/form-datarichieste formattate. Gson supporta anche l'analisi di una stringa JSON in un oggetto 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();
// ...

Si noti che tutto questo è più goffo del semplice utilizzo $.param(). Normalmente, si desidera utilizzare JSON.stringify()solo se il servizio di destinazione è ad esempio un servizio JAX-RS (RESTful) che è per qualche motivo in grado di consumare stringhe JSON e non parametri di richiesta regolari.

Invio di un reindirizzamento dal servlet

È importante rendersi conto e comprendere che qualsiasi sendRedirect()e forward()chiamata da parte del servlet su una richiesta Ajax avrebbe solo inoltrato o reindirizzato la richiesta Ajax stessa e non il documento / finestra principale da cui proveniva la richiesta Ajax. JavaScript / jQuery in tal caso recupererebbe la risposta reindirizzata / inoltrata come responseTextvariabile nella funzione di callback. Se rappresenta un'intera pagina HTML e non una risposta XML o JSON specifica per Ajax, tutto ciò che potresti fare è sostituire il documento corrente con esso.

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

Nota che questo non cambia l'URL come vede l'utente finale nella barra degli indirizzi del browser. Quindi ci sono problemi con la segnalabilità. Pertanto, è molto meglio semplicemente restituire una "istruzione" per JavaScript / jQuery per eseguire un reindirizzamento invece di restituire l'intero contenuto della pagina reindirizzata. Ad esempio restituendo un valore booleano o un 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;
    }

    // ...
}

Guarda anche:


è necessario analizzare il json sull'ultimo esempio.
shinzou,

4
@kuhaku: no. Se leggi i post dall'alto verso il basso, scoprirai perché.
BalusC

1
Questa risposta è stata la mia linfa vitale per l'ultimo mese o giù di lì lol. Imparare un sacco da esso. ADORO l'esempio XML. Grazie per averlo messo insieme! Una domanda noob però se hai tempo. C'è un motivo per mettere la cartella xml in WEB-INF?
Jonathan Laliberte,

1
@JonathanLaliberte: quindi gli utenti non possono scaricarli.
BalusC,

@BalusC, il tuo esempio XML è fantastico, grazie. Ma sto ottenendo "Impossibile ottenere la proprietà 'sostituire' di riferimento indefinito o nullo" per$("#somediv").html($(responseXml).find("data").html()) questa riga. Dice anche "Numero errato di argomenti o assegnazione di proprietà non valida". Posso anche vedere che il mio XML è popolato di dati quando eseguo il debug. Qualche idea ?
629,

14

Il modo giusto per aggiornare la pagina attualmente visualizzata nel browser dell'utente (senza ricaricarla) è fare in modo che un codice in esecuzione nel browser aggiorni il DOM della pagina.

Tale codice è in genere javascript incorporato o collegato dalla pagina HTML, da cui il suggerimento AJAX. (In effetti, se assumiamo che il testo aggiornato provenga dal server tramite una richiesta HTTP, questo è il classico AJAX.)

È anche possibile implementare questo tipo di cose utilizzando alcuni plug-in o componenti aggiuntivi del browser, anche se può essere difficile per un plug-in raggiungere le strutture di dati del browser per aggiornare il DOM. (I plug-in di codice nativo normalmente scrivono su alcuni frame grafici incorporati nella pagina.)


13

Ti mostrerò un intero esempio di servlet e come si chiama ajax.

Qui, creeremo il semplice esempio per creare il modulo di accesso usando 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>  

Ecco un esempio Ajax

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

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

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

7

Ajax (anche AJAX) acronimo di Asynchronous JavaScript e XML) è un gruppo di tecniche di sviluppo web correlate utilizzate sul lato client per creare applicazioni web asincrone. Con Ajax, le applicazioni Web possono inviare e recuperare dati da un server in modo asincrono Di seguito è riportato il codice di esempio:

Funzione di script java della pagina JSP per inviare i dati al servlet con due variabili firstName e 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 per leggere i dati rinviati a jsp in formato xml (È possibile utilizzare anche il testo. Basta solo cambiare il contenuto della risposta in testo e renderizzare i dati sulla funzione 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>");
}

5

Normalmente non è possibile aggiornare una pagina da un servlet. Il client (browser) deve richiedere un aggiornamento. Il client Eiter carica una pagina completamente nuova o richiede un aggiornamento a una parte di una pagina esistente. Questa tecnica si chiama Ajax.


4

Utilizzando la selezione multipla di bootstrap

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

In Servlet

request.getParameter("input")
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.