Jak korzystać z serwletów i Ajax?

334

Jestem bardzo nowy w aplikacjach internetowych i serwletach i mam następujące pytanie:

Ilekroć drukuję coś wewnątrz serwletu i wywołuję go przez przeglądarkę internetową, zwraca nową stronę zawierającą ten tekst. Czy istnieje sposób wydrukowania tekstu na bieżącej stronie za pomocą Ajax?

Amir Rachum
źródło

Odpowiedzi:

561

Rzeczywiście, słowem kluczowym jest „ajax”: asynchroniczny JavaScript i XML . Jednak w ostatnich latach jest to bardziej niż często Asynchroniczny JavaScript i JSON . Zasadniczo pozwalasz JS wykonać asynchroniczne żądanie HTTP i aktualizujesz drzewo DOM HTML na podstawie danych odpowiedzi.

Ponieważ praca we wszystkich przeglądarkach (szczególnie Internet Explorer w porównaniu z innymi) jest dość żmudna , istnieje wiele bibliotek JavaScript, które upraszczają to w pojedynczych funkcjach i obejmują jak najwięcej błędów / dziwactw związanych z przeglądarką pod maskami , takich jak jQuery , Prototype , Mootools . Ponieważ jQuery jest obecnie najbardziej popularny, użyję go w poniższych przykładach.

Przykład rozpoczęcia powracający Stringjako zwykły tekst

Utwórz /some.jsppodobny sposób poniżej (uwaga: kod nie oczekuje umieszczenia pliku JSP w podfolderze, jeśli to zrobisz, odpowiednio zmień adres URL serwletu):

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

Utwórz serwlet za pomocą doGet()metody, która wygląda następująco:

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

Odwzoruj ten serwlet na wzorzec adresu URL /someservletlub /someservlet/*niższy (oczywiście wzorzec adresu URL jest dowolny, ale musisz odpowiednio zmienić someservletadres URL w przykładach kodu JS):

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

Lub, jeśli nie jesteś jeszcze w kontenerze kompatybilnym z Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6 itp. Lub nowszym), to zamapuj go w web.xmlstaromodny sposób (zobacz także naszą stronę wiki Servletów ):

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

Teraz otwórz http: // localhost: 8080 / context / test.jsp w przeglądarce i naciśnij przycisk. Zobaczysz, że zawartość div zostanie zaktualizowana o odpowiedź serwletu.

Wracając List<String>jako JSON

Dzięki JSON zamiast zwykłego tekstu jako formatu odpowiedzi możesz nawet zrobić kilka kroków dalej. Pozwala na większą dynamikę. Po pierwsze, chcesz mieć narzędzie do konwersji między obiektami Java i łańcuchami JSON. Jest ich także dużo (przegląd na dole tej strony ). Moim ulubionym jest Google Gson . Pobierz i umieść plik JAR w /WEB-INF/libfolderze swojej aplikacji internetowej.

Oto przykład, który wyświetla się List<String>jako <ul><li>. Serwlet:

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

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

Zauważ, że jQuery automatycznie analizuje odpowiedź jako JSON i daje ci bezpośrednio obiekt JSON ( responseJson) jako argument funkcji, gdy ustawisz typ zawartości odpowiedzi na application/json. Jeśli zapomnisz ustawić go lub polegać na domyślnym ustawieniu text/plainlub text/html, wówczas responseJsonargument nie dałby ci obiektu JSON, ale zwykły ciąg waniliowy i musiałbyś ręcznie manipulować nim JSON.parse()później, co jest całkowicie niepotrzebne, jeśli ustaw typ zawartości na pierwszym miejscu.

Wracając Map<String, String>jako JSON

Oto kolejny przykład, który wyświetla się Map<String, String>jako <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);
}

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

z

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

Wracając List<Entity>jako JSON

Oto przykład, który wyświetla się List<Product>w miejscu, w <table>którym Productklasa ma właściwości Long id, String nameoraz BigDecimal price. Serwlet:

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

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

Zwracanie List<Entity>jako XML

Oto przykład, który działa tak samo jak poprzedni przykład, ale następnie z XML zamiast JSON. Gdy używasz JSP jako generatora danych wyjściowych XML, zobaczysz, że mniej uciążliwe jest kodowanie tabeli i wszystkich innych. JSTL jest w ten sposób o wiele bardziej pomocny, ponieważ można go używać do iteracji wyników i formatowania danych po stronie serwera. Serwlet:

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

Kod JSP (uwaga: jeśli umieścisz go <table>w <jsp:include>, może on zostać użyty w innym miejscu w odpowiedzi innej niż 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>

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

Prawdopodobnie już zdasz sobie sprawę, dlaczego XML jest o wiele potężniejszy niż JSON, szczególnie w celu aktualizacji dokumentu HTML za pomocą Ajax. JSON jest zabawny, ale ogólnie przydatny tylko w przypadku tak zwanych „publicznych usług sieciowych”. Frameworki MVC, takie jak JSF, używają XML pod przykryciem do swojej magii ajax.

Ajaxifying istniejącego formularza

Możesz użyć jQuery $.serialize()do łatwego przechwytywania istniejących formularzy POST bez zbędnego kręcenia się przy zbieraniu i przekazywaniu poszczególnych parametrów wejściowych formularza. Przyjmując istniejącą formę, która działa idealnie bez JavaScript / jQuery (i tym samym łagodnie się psuje, gdy użytkownik ma wyłączoną obsługę 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>

Możesz go stopniowo ulepszać za pomocą ajax, jak poniżej:

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

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

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

W serwletu możesz rozróżnić zwykłe żądania i żądania ajax, jak poniżej:

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

Plugin jQuery Formularz robi mniej lub więcej takie same jak powyżej przykład jQuery, ale ma dodatkową przezroczystą obsługę multipart/form-dataformularzy wymaganych przez przesłanych plików.

Ręczne wysyłanie parametrów żądania do serwletu

Jeśli w ogóle nie masz formularza, a chcesz po prostu wchodzić w interakcję z serwletem „w tle”, w którym chcesz wysłać dane, możesz użyć jQuery, $.param()aby łatwo przekonwertować obiekt JSON na kodowany adres URL ciąg zapytania.

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

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

Tę samą doPost()metodę, jak pokazano powyżej, można ponownie wykorzystać. Zauważ, że powyższa składnia działa również z $.get()jQuery i doGet()serwletem.

Ręczne wysyłanie obiektu JSON do serwletu

Jeśli jednak z jakiegoś powodu zamierzasz wysłać obiekt JSON jako całość zamiast jako indywidualne parametry żądania, musisz serializować go do ciągu za pomocą JSON.stringify()(nie stanowiącego części jQuery) i poinstruować jQuery, aby application/jsonzamiast tego ustawić typ zawartości żądania z (domyślnie) application/x-www-form-urlencoded. Nie można tego zrobić za pomocą $.post()funkcji wygody, ale należy to zrobić $.ajax()w następujący sposób.

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

Zauważ, że wiele przystawek łączy się contentTypez dataType. contentTypeReprezentuje typ żądania ciała. dataTypeReprezentuje (expected) typ reakcji organizmu, który jest zwykle konieczne, ponieważ jQuery już automatycznie wykrywa go w oparciu o odpowiedź za Content-Typecel.

Następnie, aby przetworzyć obiekt JSON w serwlecie, który nie jest wysyłany jako indywidualne parametry żądania, ale jako cały ciąg JSON w powyższy sposób, wystarczy ręcznie przeanalizować treść żądania za pomocą narzędzia JSON zamiast getParameter()zwykłego droga. Mianowicie, serwlety nie obsługują application/jsonsformatowanych żądań, ale tylko application/x-www-form-urlencodedlub multipart/form-datasformatowanych żądań. Gson obsługuje również parsowanie łańcucha JSON w obiekcie 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();
// ...

Pamiętaj, że to wszystko jest bardziej niezdarne niż zwykłe używanie $.param(). Zwykle chcesz używać JSON.stringify()tylko wtedy, gdy usługą docelową jest np. Usługa JAX-RS (RESTful), która z jakiegoś powodu jest w stanie zużywać tylko ciągi JSON, a nie parametry regularnego żądania.

Wysyłanie przekierowania z serwletu

Ważne jest, aby zrozumieć i zrozumieć, że dowolne sendRedirect()i forward()wywołanie przez serwlet na żądanie ajax spowoduje tylko przekazanie lub przekierowanie samego żądania ajax, a nie główny dokument / okno, z którego pochodzi zapytanie ajax. JavaScript / jQuery w takim przypadku pobierałby tylko przekierowaną / przekazaną odpowiedź jako responseTextzmienną w funkcji wywołania zwrotnego. Jeśli reprezentuje całą stronę HTML, a nie odpowiedź w formacie XML lub JSON specyficzną dla ajax, to wszystko, co możesz zrobić, to zastąpić go bieżącym dokumentem.

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

Pamiętaj, że nie zmienia to adresu URL, tak jak użytkownik widzi w pasku adresu przeglądarki. Są więc problemy z bukmacherstwem. Dlatego o wiele lepiej jest po prostu zwrócić „instrukcję” dla JavaScript / jQuery, aby wykonać przekierowanie, zamiast zwracać całą treść przekierowanej strony. Np. Przez zwrócenie wartości logicznej lub adresu 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;
    }

    // ...
}

Zobacz też:

BalusC
źródło
trzeba przeanalizować JSON na ostatnim przykładzie.
shinzou
4
@kuhaku: nope. Jeśli czytasz post od góry do dołu, dowiesz się, dlaczego.
BalusC
1
Ta odpowiedź była moją linią ratunkową przez ostatni miesiąc lol. Uczenie się z tego wielu. UWIELBIAM przykład XML. Dziękuję za złożenie tego do kupy! Jedno pytanie noob, jeśli masz czas. Czy istnieje powód, aby umieścić folder xml w WEB-INF?
Jonathan Laliberte
1
@JonathanLaliberte: Użytkownicy nie mogą ich pobrać.
BalusC
@BalusC, twój przykład XML jest świetny, dziękuję. Ale dla $("#somediv").html($(responseXml).find("data").html())tego wiersza pojawia się komunikat „Nie można uzyskać właściwości„ zamień ”niezdefiniowanego lub zerowego odwołania . Mówi także „Zła liczba argumentów lub nieprawidłowe przypisanie właściwości”. Widzę też, że mój plik XML jest zapełniany danymi podczas debugowania. Jakieś pomysły ?
629
14

Właściwym sposobem na aktualizację strony aktualnie wyświetlanej w przeglądarce użytkownika (bez jej ponownego ładowania) jest posiadanie kodu wykonującego się w przeglądarce, który aktualizuje DOM strony.

Ten kod jest zazwyczaj javascript, który jest osadzony lub połączony ze stroną HTML, stąd sugestia AJAX. (W rzeczywistości, jeśli założymy, że zaktualizowany tekst pochodzi z serwera za pośrednictwem żądania HTTP, jest to klasyczny AJAX.)

Możliwe jest również zaimplementowanie tego rodzaju rzeczy za pomocą wtyczki lub dodatku do przeglądarki, chociaż wtyczka może mieć trudności z dostępem do struktur danych przeglądarki w celu aktualizacji DOM. (Wtyczki natywnego kodu zwykle zapisują do niektórych ramek graficznych osadzonych na stronie).

Stephen C.
źródło
13

Pokażę ci cały przykład serwletu i jak wywołać ajax.

Tutaj stworzymy prosty przykład, aby utworzyć formularz logowania za pomocą serwletu.

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>  

Oto ajax Próbka

       $.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);
        } 
    }
}
Mitul Maheshwari
źródło
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
źródło
7

Ajax (również AJAX) akronim dla asynchronicznego JavaScript i XML) to grupa powiązanych ze sobą technik tworzenia stron internetowych wykorzystywanych po stronie klienta do tworzenia asynchronicznych aplikacji internetowych. Dzięki Ajax aplikacje internetowe mogą asynchronicznie wysyłać dane i pobierać je z serwera. Poniżej znajduje się przykładowy kod:

Funkcja skryptu Java strony Jsp do przesyłania danych do serwletu z dwiema zmiennymi firstName i 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);

    }

Serwlet do odczytu danych odsyła z powrotem do formatu jsp w formacie xml (możesz również użyć tekstu. Wystarczy zmienić treść odpowiedzi na tekst i renderować dane w funkcji 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>");
}
użytkownik3468976
źródło
5

Zwykle nie można zaktualizować strony z serwletu. Klient (przeglądarka) musi poprosić o aktualizację. Klient Eiter ładuje całą nową stronę lub żąda aktualizacji części istniejącej strony. Ta technika nazywa się Ajax.

Peter Knego
źródło
4

Korzystając z 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'
    });}
}

W Servlet

request.getParameter("input")
Thakhani Tharage
źródło