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

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

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

7 ответов

Решение

Действительно, ключевое слово "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="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 свободен по вашему выбору, но вам необходимо изменить someservlet URL в примерах кода JS по всему месту соответственно):

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

Или, если вы еще не находитесь в контейнере, совместимом с Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6 и т. Д. Или более поздней версии), то отобразите его в web.xml по старинке (см. также нашу вики-страницу Servlets):

<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 формы, необходимые для загрузки файлов.

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

Если у вас вообще нет формы, но вы просто хотите взаимодействовать с сервлетом "в фоновом режиме", с помощью которого вы хотите разместить некоторые данные, тогда вы можете использовать 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;
    }

    // ...
}

Смотрите также:

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

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

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

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

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

JSP-страница Javascript функция для отправки данных в сервлет с двумя переменными 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>");
}

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

Использование начальной загрузки

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")
Другие вопросы по тегам