Я очень новичок в веб-приложениях и сервлетах, и у меня есть следующий вопрос:
Всякий раз, когда я печатаю что-то внутри сервлета и вызываю его с помощью веб-браузера, он возвращает новую страницу, содержащую этот текст. Есть ли способ распечатать текст на текущей странице с помощью Ajax?
Действительно, ключевым словом является "ajax": асинхронный JavaScript и XML. Однако в последние годы это чаще, чем асинхронный JavaScript и JSON. В принципе, вы позволяете JS выполнять асинхронный HTTP-запрос и обновлять дерево DOM HTML на основе данных ответа.
Поскольку это довольно утомительная работа, чтобы заставить его работать во всех браузерах (особенно Internet Explorer и других), существует множество библиотек JavaScript который упрощает это в одиночных функциях и охватывает как можно больше ошибок/причуд для браузера под капотами, таких как jQuery, Prototype, Mootools. Поскольку jQuery наиболее популярен в наши дни, я буду использовать его в приведенных ниже примерах.
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.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;
}
// ...
}
Правильный способ обновления страницы, отображаемой в настоящее время в браузере пользователя (без перезагрузки), заключается в том, чтобы выполнить некоторый код в браузере, обновив страницу 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);
}
});
Код сервлета 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);
}
}
}
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>");
}
$.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);
}
});
Обычно вы не можете обновить страницу из сервлета. Клиент (браузер) должен запросить обновление. Клиент Eiter загружает всю новую страницу или запрашивает обновление части существующей страницы. Этот метод называется Ajax.
Использование выбора 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")