Как использовать сервлеты и 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;
    }

    // ...
}

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

BalusC
источник
нужно разобрать 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);
 }
});
SUBZ
источник
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>");
}
user3468976
источник
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")
Thakhani Tharage
источник