Wie benutzt man Servlets und Ajax?


334

Ich bin sehr neu in Web-Apps und Servlets und habe die folgende Frage:

Immer wenn ich etwas im Servlet drucke und es vom Webbrowser aufrufe, wird eine neue Seite mit diesem Text zurückgegeben. Gibt es eine Möglichkeit, den Text auf der aktuellen Seite mit Ajax zu drucken?

Antworten:


560

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 Stringals einfacher Text zurückgegeben wird

Erstellen /some.jspSie 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 /someservletoder /someservlet/*wie folgt zu (natürlich steht das URL-Muster Ihrer Wahl frei, aber Sie müssen die someservletURL 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.xmldie 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/libOrdner 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/plainoder zu verlassen text/html, erhalten Sie mit dem responseJsonArgument 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 ProductKlasse die Eigenschaften hat Long id, String nameund 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-dataFormulare, 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/jsonstattdessen 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 contentTypemit dataType. Das contentTyperepräsentiert den Typ des Anforderungshauptteils . Das dataTypestellt den (erwarteten) Typ des Antwortkörpers dar , der normalerweise nicht erforderlich ist, da jQuery ihn bereits anhand des Content-TypeHeaders 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/jsonformatierten Anforderungen, sondern nur application/x-www-form-urlencodedoder multipart/form-dataformatierte 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 responseTextVariable 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:


Ich muss den JSON im letzten Beispiel analysieren.
Shinzou

4
@kuhaku: nein. Wenn Sie den Beitrag von oben nach unten lesen, erfahren Sie, warum.
BalusC

1
Diese Antwort war meine Lebensader für den letzten Monat oder so lol. Ein paar daraus lernen. Ich liebe das XML-Beispiel. Danke, dass du das zusammengestellt hast! Eine Noob-Frage, wenn Sie Zeit haben. Gibt es einen Grund, den XML-Ordner in WEB-INF abzulegen?
Jonathan Laliberte

1
@ JonathanLaliberte: Benutzer können sie also nicht herunterladen.
BalusC

@BalusC, dein XML-Beispiel ist großartig, danke. Für $("#somediv").html($(responseXml).find("data").html())diese Zeile wird jedoch die Meldung "Ersetzen der Eigenschaft durch undefinierte oder Nullreferenz nicht möglich" angezeigt. Es heißt auch "Falsche Anzahl von Argumenten oder ungültige Eigenschaftszuweisung". Ich kann auch sehen, dass mein XML beim Debuggen mit Daten gefüllt ist. Irgendwelche Ideen ?
629

14

Der richtige Weg, um die aktuell im Browser des Benutzers angezeigte Seite zu aktualisieren (ohne sie neu zu laden), besteht darin, dass im Browser Code ausgeführt wird, der das DOM der Seite aktualisiert.

Dieser Code ist normalerweise Javascript, das in die HTML-Seite eingebettet oder von dieser verlinkt ist, daher der AJAX-Vorschlag. (Wenn wir davon ausgehen, dass der aktualisierte Text über eine HTTP-Anforderung vom Server stammt, handelt es sich um klassisches AJAX.)

Es ist auch möglich, solche Dinge mit einem Browser-Plugin oder Add-On zu implementieren, obwohl es für ein Plugin schwierig sein kann, in die Datenstrukturen des Browsers zu gelangen, um das DOM zu aktualisieren. (Native Code-Plugins schreiben normalerweise in einen Grafikrahmen, der in die Seite eingebettet ist.)


13

Ich werde Ihnen ein ganzes Beispiel für Servlet zeigen und wie Ajax aufruft.

Hier erstellen wir ein einfaches Beispiel zum Erstellen des Anmeldeformulars mithilfe eines Servlets.

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>  

Hier ist ein Ajax-Beispiel

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

LoginServlet Servlet Code: -

    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 (auch AJAX), eine Abkürzung für Asynchronous JavaScript and XML, ist eine Gruppe miteinander verbundener Webentwicklungstechniken, die auf der Clientseite zum Erstellen asynchroner Webanwendungen verwendet werden. Mit Ajax können Webanwendungen Daten asynchron an einen Server senden und von diesem abrufen. Nachfolgend finden Sie einen Beispielcode:

Java-Skriptfunktion für Jsp-Seiten zum Senden von Daten an das Servlet mit zwei Variablen Vorname und Nachname:

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 zum Lesen von Daten, die im XML-Format an JSP zurückgesendet werden (Sie können auch Text verwenden. Sie müssen lediglich den Antwortinhalt in Text ändern und Daten in der Javascript-Funktion rendern.)

/**
 * @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

Normalerweise können Sie eine Seite von einem Servlet nicht aktualisieren. Der Client (Browser) muss ein Update anfordern. Der Eiter-Client lädt eine ganz neue Seite oder fordert eine Aktualisierung eines Teils einer vorhandenen Seite an. Diese Technik heißt Ajax.


4

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

In Servlet

request.getParameter("input")
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.