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


334

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

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

Ответы:


561

Действительно, ключевое слово «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 является бесплатным по вашему выбору, но вам необходимо изменить someservletURL в примерах кода 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 форма делает больше или меньше такой же , как описано выше , например 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 веб-приложения могут отправлять данные и получать данные с сервера асинхронно. Ниже приведен пример кода:

JSP-страница java-скрипт для отправки данных сервлету с двумя переменными 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 загружает целую новую страницу или запрашивает обновление части существующей страницы. Эта техника называется Ajax.


4

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

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")
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.