Як користуватися сервлетами та Ajax?


334

Я дуже новачок у веб-додатках та сервлетах, і у мене таке питання:

Щоразу, коли я надрукую щось у сервлеті і зателефонував йому веб-браузером, він повертає нову сторінку, що містить цей текст. Чи є спосіб надрукувати текст на поточній сторінці за допомогою Ajax?

Відповіді:


561

Дійсно, ключове слово "ajax": Асинхронний JavaScript та XML . Однак останніми роками це більш ніж часто асинхронний JavaScript та JSON . В основному, ви дозволяєте JS виконувати асинхронний запит HTTP та оновлювати дерево HTML DOM на основі даних відповіді.

Оскільки це досить копітка робота, щоб змусити її працювати у всіх браузерах (особливо Internet Explorer порівняно з іншими), існує безліч бібліотек JavaScript, що спрощує це в окремих функціях і охоплює якомога більше помилок / хитрощів, пов’язаних із браузером, під кришками , таких як jQuery , Prototype , Mootools . Оскільки jQuery є найпопулярнішим в наші дні, я буду використовувати його в наведених нижче прикладах.

Приклад Kickoff, що повертається Stringяк звичайний текст

Створіть /some.jspподібне нижче (зверніть увагу: код не очікує, що файл JSP буде розміщений у підпапці, якщо ви це зробите відповідно, змініть URL-адресу сервлета):

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

Створіть сервлет doGet()методом, який виглядає приблизно так:

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

Позначте цей сервлет на шаблоні URL-адреси /someservletабо /someservlet/*нижче (очевидно, що шаблон URL-адреси на ваш вибір є вільним, але вам потрібно буде змінити someservletURL-адресу в прикладах коду JS для всіх місць відповідно):

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

Або якщо ви ще не використовуєте контейнер, сумісний із Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6 тощо, або новіший), то позначайте його web.xmlстаромодно (див. Також нашу сторінку Вікі сервлетів ):

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

Тепер відкрийте http: // localhost: 8080 / context / test.jsp у браузері і натисніть кнопку. Ви побачите, що вміст div оновлюється у відповіді сервлета.

Повертаючись List<String>як JSON

З JSON замість простого тексту як формату відповіді ви навіть можете зробити кілька кроків далі. Це дозволяє отримати більше динаміки. По-перше, ви хочете мати інструмент для перетворення між об'єктами Java та рядками JSON. Їх також багато ( огляд див у нижній частині цієї сторінки ). Мій особистий фаворит - Google Gson . Завантажте і покладіть його файл JAR у /WEB-INF/libпапку вашої веб-програми.

Ось приклад, який відображається List<String>як <ul><li>. Сервлет:

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

Код 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>.
        });
    });
});

Зауважте, що jQuery автоматично аналізує відповідь як JSON і надає вам безпосередньо об'єкт JSON ( responseJson) як аргумент функції, коли ви встановлюєте тип вмісту відповіді application/json. Якщо ви забули встановити його або покладатися на значення по замовчуванням text/plainабо text/html, то responseJsonаргумент не дасть вам JSON об'єкт, але звичайний рядок ванілі і вам потрібно вручну возитися зJSON.parse() потім, що , таким чином , абсолютно НЕ потрібно , якщо вам встановіть тип вмісту на перше місце.

Повернення Map<String, String>як JSON

Ось ще один приклад, який відображається Map<String, String>як <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);
}

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

з

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

Повернення List<Entity>як JSON

Ось приклад, який відображає List<Product>в а, <table>де Productклас має властивості Long id, String nameі BigDecimal price. Сервлет:

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

Код 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>.
        });
    });
});

Повернення List<Entity> як XML

Ось приклад, який фактично робить те саме, що і попередній приклад, але тоді з XML замість JSON. Використовуючи JSP як генератор вихідних даних XML, ви побачите, що кодувати таблицю та все менше втомливо. JSTL цей спосіб набагато корисніший, оскільки ви можете фактично використовувати його для повторення результатів та проведення форматування даних на стороні сервера. Сервлет:

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

Код JSP (зауважте: якщо ви вводите <table>a <jsp:include>, він може бути повторно використаний в іншому місці у не-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>

Код 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".
    });
});

Ви вже напевно зрозумієте, чому XML настільки потужніший, ніж JSON, для конкретної мети оновлення документа HTML за допомогою Ajax. JSON - це смішно, але в цілому корисно лише для так званих "публічних веб-сервісів". Структури MVC типу JSF використовують XML під обкладинками для своєї магії ajax.

Аяксифікація існуючої форми

Ви можете використовувати jQuery $.serialize()для легкої аяксифікації існуючих форм POST, не обмінюючись збиранням та передачею вхідних параметрів окремих форм. Припускаючи існуючу форму, яка прекрасно працює без JavaScript / jQuery (і таким чином витончено погіршується, коли у enduser відключений 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>

Ви можете прогресивно покращувати його за допомогою ajax, як показано нижче:

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

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

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

Ви можете в сервлеті розрізняти звичайні запити та запити ajax, як показано нижче:

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

Плагін JQuery форма робить менше або більше такої ж , як вище , наприклад JQuery, але вона має додаткову прозору підтримкуmultipart/form-data форм відповідно з вимогами завантаження файлів.

Вручну надсилання параметрів запиту на сервлет

Якщо у вас взагалі немає форми, а ви просто хотіли взаємодіяти з сервлетом "у фоновому режимі", за допомогою якого ви хочете розмістити деякі дані, тоді ви можете використовувати jQuery, $.param()щоб легко перетворити об'єкт JSON в закодований URL рядок запиту

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

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

Той же doPost()метод, що показаний тут, можна повторно використовувати. Зауважте, що вище синтаксис також працює з $.get()jQuery та doGet()сервлетом.

Відправлення JSON-об’єкта вручну в сервлет

Якщо ви хочете з якоїсь причини надіслати об'єкт JSON в цілому замість окремих параметрів запиту, вам знадобиться серіалізувати його до рядка, використовуючи JSON.stringify()(не частина jQuery), і доручити jQuery встановити тип вмісту запиту application/jsonзамість з (за замовчуванням) application/x-www-form-urlencoded. Це неможливо зробити за допомогою $.post()функції зручності, але це потрібно зробити, $.ajax()як показано нижче.

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

Зверніть увагу , що багато стартерів змішатися contentTypeз dataType. contentTypeЯвляє тип запиту органу. dataTypeЯвляє (очікуваний) тип реакції тіла, яке, як правило , немає необхідності , оскільки JQuery вже автоматично визначає його на основі відповідних роківContent-Type заголовку.

Потім, щоб обробити об'єкт JSON в сервлеті, який не надсилається як індивідуальні параметри запиту, але як цілий рядок JSON вище, вам потрібно лише вручну проаналізувати тіло запиту за допомогою інструмента JSON, а не використовувати getParameter()звичайний шлях. А саме сервлети не підтримують application/jsonформатовані запити, а лише application/x-www-form-urlencodedабо multipart/form-dataвідформатовані запити. Gson також підтримує розбір рядка JSON в об'єкт 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();
// ...

Зверніть увагу, що це все більш незграбно, ніж просто використання $.param(). Зазвичай, ви хочете використовувати JSON.stringify()лише в тому випадку, якщо цільова служба - це, наприклад, сервіс JAX-RS (RESTful), який чомусь здатний споживати рядки JSON, а не регулярні параметри запиту.

Надсилання переадресації з сервлета

Важливо усвідомити і зрозуміти, що будь-який sendRedirect()і forward()виклик сервлета на запит ajax буде пересилати або перенаправляти сам запит ajax, а не головний документ / вікно, звідки походив запит ajax. У такому випадку JavaScript / jQuery отримує лише перенаправлену / переслану відповідь як responseTextзмінну у функції зворотного виклику. Якщо він представляє цілу сторінку HTML, а не відповідь, характерний для ajax XML або JSON, то все, що ви могли зробити, це замінити поточний документ на нього.

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

Зауважте, що це не змінює URL-адресу, як він бачить в адресному рядку браузера. Тож виникають проблеми з закладкою. Тому набагато краще просто повернути "інструкцію" для JavaScript / jQuery для виконання переадресації, а не повернення всього вмісту перенаправленої сторінки. Наприклад, повернувши булеву або 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;
    }

    // ...
}

Дивись також:


потрібно розібрати json на останньому прикладі.
shinzou

4
@kuhaku: ні. Якщо ви читаєте публікацію зверху вниз, ви дізнаєтеся чому.
BalusC

1
Ця відповідь була моїм життєвим колом протягом останнього місяця або близько того, хаха. Дізнатися з нього купу. Я люблю приклад XML Дякуємо, що це зробили разом! Одне запитання нуб, якщо у вас є час. Чи є причина для розміщення папки xml у WEB-INF?
Джонатан Лаліберте

1
@JonathanLaliberte: Тому користувачі не можуть їх завантажувати.
BalusC

@BalusC, ваш XML-приклад чудовий, дякую. Але я отримую "Неможливо отримати властивість" замінити "невизначеною або нульовою посиланням" для $("#somediv").html($(responseXml).find("data").html())цього рядка. У ньому також написано "Неправильна кількість аргументів або присвоєння недійсних властивостей". Я також можу бачити, що мій XML заповнений даними, коли я його налагоджую. Будь-які ідеї?
629

14

Правильний спосіб оновити сторінку, яка наразі відображається в браузері користувача (не перезавантажуючи її), - це виконати якийсь код, виконаний у браузері, оновити DOM сторінки.

Цей код, як правило, JavaScript, вбудований або пов'язаний зі сторінки HTML, звідси пропозиція AJAX. (Насправді, якщо припустити, що оновлений текст надходить із сервера через HTTP-запит, це класичний AJAX.)

Можливо також реалізувати подібні речі за допомогою плагіна чи доповнення для браузера, хоча плагін може потрапити в структури даних браузера для оновлення DOM. (Плагіни кодового коду зазвичай записують на якийсь графічний кадр, вбудований у сторінку.)


13

Я покажу вам цілий приклад сервлета та як дзвонити в Ajax.

Тут ми збираємось створити простий приклад для створення форми входу за допомогою сервлета.

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>  

Ось зразок ajax

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

Код сервлета сервера: -

    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 (також AJAX) - абревіатура для асинхронного JavaScript та XML) - це група взаємопов'язаних методів веб-розробки, що використовуються на стороні клієнта для створення асинхронних веб-додатків. За допомогою Ajax веб-додатки можуть асинхронно надсилати дані на сервер і отримувати дані з сервера. Нижче наведено приклад коду:

Функція сценарію Java Jsp page для подання даних у сервлет із двома змінними firstName та 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);

    }

Сервлет для зчитування даних повертається до jsp у форматі xml (Ви також можете використовувати текст. Просто потрібно змінити вміст відповіді на текст та надати дані на функції 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

Зазвичай ви не можете оновити сторінку із сервлета. Клієнт (браузер) повинен запитувати оновлення. Клієнт Eiter завантажує цілком нову сторінку або він вимагає оновлення частини існуючої сторінки. Ця техніка називається Аякс.


4

Використання завантажувальної програми multi select

Аякс

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

В Сервлет

request.getParameter("input")
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.