Как использовать сервлеты и Ajax?

277

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

Всякий раз, когда я печатаю что-то внутри сервлета и вызываю его с помощью веб-браузера, он возвращает новую страницу, содержащую этот текст. Есть ли способ распечатать текст на текущей странице с помощью Ajax?

Теги:
jsp
servlets

7 ответов

531
Лучший ответ

Действительно, ключевым словом является "ajax": асинхронный JavaScript и XML. Однако в последние годы это чаще, чем асинхронный JavaScript и JSON. В принципе, вы позволяете JS выполнять асинхронный HTTP-запрос и обновлять дерево DOM HTML на основе данных ответа.

Поскольку это довольно утомительная работа, чтобы заставить его работать во всех браузерах (особенно 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="/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 свободен по вашему выбору, но вам нужно будет изменить URL someservlet в примерах кода 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> в <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 Form делает меньше или больше того же, что и выше, пример jQuery, но имеет дополнительную прозрачную поддержку форм multipart/form-data по мере необходимости по загрузке файлов.

Вручную отправка параметров запроса в сервлет

Если у вас нет формы вообще, но просто захотелось взаимодействовать с сервлетами "в фоновом режиме", в соответствии с которым вы хотели бы POST некоторые данные, вы можете использовать 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 представляет (ожидаемый) тип тела response, который обычно не нужен, поскольку 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-адрес, поскольку enduser видит в адресной строке браузера. Таким образом, есть проблемы с возможностью закладки. Поэтому гораздо лучше просто вернуть "инструкцию" для 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;
    }

    // ...
}

См. также:

  • 0
    нужно разобрать json на последнем примере.
  • 4
    @kuhaku: Нет. Если вы прочитаете пост сверху вниз, вы узнаете почему.
Показать ещё 5 комментариев
13

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

Этот код, как правило, представляет собой javascript, встроенный или связанный с HTML-страницей, следовательно, предложение AJAX. (На самом деле, если предположить, что обновленный текст поступает с сервера через HTTP-запрос, это классический AJAX.)

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

11

Я покажу вам целый пример сервлета и как сделать 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);           
            }           
        });

Код сервлета 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);
        } 
    }
}
6

Ajax (также AJAX) - аббревиатура для асинхронного JavaScript и XML) - это группа взаимосвязанных методов веб-разработки, используемых на стороне клиента для создания асинхронных веб-приложений. С помощью Ajax веб-приложения могут отправлять данные и извлекать данные с сервера асинхронно Ниже приведен пример кода:

Jsp page java script функция для отправки данных в сервлет с двумя переменными 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>");
}
6
$.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);
 }
});
4

Обычно вы не можете обновить страницу из сервлета. Клиент (браузер) должен запросить обновление. Клиент Eiter загружает всю новую страницу или запрашивает обновление части существующей страницы. Этот метод называется Ajax.

3

Использование выбора bootstrap multi

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

В сервлете

request.getParameter("input")

Ещё вопросы

Сообщество Overcoder
Наверх
Меню