Memang, kata kuncinya adalah "ajax": Asynchronous JavaScript and XML . Namun, tahun-tahun terakhir ini lebih sering Asynchronous JavaScript dan JSON . Pada dasarnya, Anda membiarkan JS mengeksekusi permintaan HTTP asinkron dan memperbarui pohon DOM HTML berdasarkan data respons.
Karena cukup membosankan untuk membuatnya bekerja di semua browser (terutama Internet Explorer versus yang lain), ada banyak pustaka JavaScript yang menyederhanakan ini dalam fungsi tunggal dan mencakup sebanyak mungkin bug / quirks khusus browser di bawah tenda. , seperti jQuery , Prototype , Mootools . Karena jQuery paling populer akhir-akhir ini, saya akan menggunakannya dalam contoh di bawah ini.
Contoh kickoff kembali String
sebagai teks biasa
Buat /some.jsp
seperti di bawah ini (catatan: kode tidak mengharapkan file JSP ditempatkan di subfolder, jika Anda melakukannya, ubah URL servlet yang sesuai):
<!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>
Buat servlet dengan doGet()
metode yang terlihat seperti ini:
@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.
}
Petakan servlet ini pada pola URL /someservlet
atau /someservlet/*
seperti di bawah ini (jelas, pola URL bebas untuk pilihan Anda, tetapi Anda harus mengubah someservlet
URL dalam contoh kode JS di semua tempat yang sesuai):
@WebServlet("/someservlet/*")
public class SomeServlet extends HttpServlet {
// ...
}
Atau, ketika Anda belum menggunakan wadah yang kompatibel dengan Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6, dll atau yang lebih baru), maka petakan dengan web.xml
cara lama (lihat juga halaman wiki Servlets kami ):
<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>
Sekarang buka http: // localhost: 8080 / context / test.jsp di browser dan tekan tombol. Anda akan melihat bahwa konten div diperbarui dengan respons servlet.
Kembali List<String>
sebagai JSON
Dengan JSON alih-alih plaintext sebagai format respons Anda bahkan bisa mendapatkan beberapa langkah lebih lanjut. Ini memungkinkan lebih banyak dinamika. Pertama, Anda ingin memiliki alat untuk mengkonversi antara objek Java dan string JSON. Ada banyak juga (lihat bagian bawah halaman ini untuk ikhtisar). Favorit pribadi saya adalah Google Gson . Unduh dan letakkan file JAR-nya di /WEB-INF/lib
folder aplikasi web Anda.
Berikut ini contoh yang ditampilkan List<String>
sebagai <ul><li>
. Servlet:
@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);
}
Kode 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>.
});
});
});
Perhatikan bahwa jQuery secara otomatis mem-parsing respons sebagai JSON dan memberi Anda secara langsung objek JSON ( responseJson
) sebagai argumen fungsi ketika Anda mengatur tipe konten respons application/json
. Jika Anda lupa untuk mengatur atau mengandalkan default text/plain
atau text/html
, maka responseJson
argumen tidak akan memberi Anda objek JSON, tetapi string vanilla polos dan Anda harus bermain-main dengan secara manual JSON.parse()
setelah itu, yang dengan demikian sama sekali tidak perlu jika Anda atur jenis konten di tempat pertama.
Kembali Map<String, String>
sebagai JSON
Berikut ini contoh lain yang ditampilkan Map<String, String>
sebagai <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);
}
Dan 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>.
});
});
});
dengan
<select id="someselect"></select>
Kembali List<Entity>
sebagai JSON
Berikut adalah contoh yang menampilkan List<Product>
di <table>
mana Product
kelas memiliki properti Long id
, String name
dan BigDecimal price
. Servlet:
@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);
}
Kode 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>.
});
});
});
Kembali List<Entity>
sebagai XML
Berikut ini adalah contoh yang secara efektif sama dengan contoh sebelumnya, tetapi kemudian dengan XML dan bukan JSON. Saat menggunakan JSP sebagai generator keluaran XML, Anda akan melihat bahwa tidak terlalu membosankan untuk mengkodekan tabel dan semuanya. JSTL adalah cara ini jauh lebih bermanfaat karena Anda benar-benar dapat menggunakannya untuk beralih pada hasil dan melakukan format data sisi server. Servlet:
@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);
}
Kode JSP (catatan: jika Anda memasukkan <table>
a <jsp:include>
, mungkin dapat digunakan kembali di tempat lain dalam respons non-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>
Kode 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".
});
});
Anda sekarang mungkin akan menyadari mengapa XML jauh lebih kuat daripada JSON untuk tujuan memperbarui dokumen HTML menggunakan Ajax. JSON memang lucu, tetapi bagaimanapun umumnya hanya berguna untuk apa yang disebut "layanan web publik". Kerangka MVC seperti JSF menggunakan XML di bawah selimut untuk sihir ajax mereka.
Ajaxifikasi formulir yang ada
Anda dapat menggunakan jQuery $.serialize()
untuk dengan mudah melakukan ajaxify formulir POST yang ada tanpa mengotak-atik pengumpulan dan melewati parameter input formulir individual. Dengan asumsi bentuk yang ada yang berfungsi dengan baik tanpa JavaScript / jQuery (dan karenanya terdegradasi dengan anggun ketika pengguna akhir JavaScript dinonaktifkan):
<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>
Anda dapat semakin meningkatkannya dengan ajax seperti di bawah ini:
$(document).on("submit", "#someform", function(event) {
var $form = $(this);
$.post($form.attr("action"), $form.serialize(), function(response) {
// ...
});
event.preventDefault(); // Important! Prevents submitting the form.
});
Anda dapat di servlet membedakan antara permintaan normal dan permintaan ajax seperti di bawah ini:
@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.
}
}
The jQuery Form Plugin tidak kurang atau lebih sama seperti di atas jQuery contoh, tetapi memiliki dukungan transparan tambahan untuk multipart/form-data
bentuk seperti yang dipersyaratkan oleh file upload.
Secara manual mengirim parameter permintaan ke servlet
Jika Anda tidak memiliki formulir sama sekali, tetapi hanya ingin berinteraksi dengan servlet "di latar belakang" di mana Anda ingin POST beberapa data, maka Anda dapat menggunakan jQuery $.param()
untuk dengan mudah mengkonversi objek JSON ke URL yang dikodekan. string kueri.
var params = {
foo: "fooValue",
bar: "barValue",
baz: "bazValue"
};
$.post("someservlet", $.param(params), function(response) {
// ...
});
doPost()
Metode yang sama seperti yang ditunjukkan di sini di atas dapat digunakan kembali. Perhatikan bahwa sintaks di atas juga berfungsi dengan $.get()
di jQuery dan doGet()
di servlet.
Mengirim objek JSON secara manual ke servlet
Namun, jika Anda berniat untuk mengirim objek JSON secara keseluruhan alih-alih sebagai parameter permintaan individu untuk beberapa alasan, maka Anda perlu membuat serialisasi ke string menggunakan JSON.stringify()
(bukan bagian dari jQuery) dan menginstruksikan jQuery untuk mengatur tipe konten permintaan application/json
sebagai gantinya dari (default) application/x-www-form-urlencoded
. Ini tidak dapat dilakukan melalui $.post()
fungsi kenyamanan, tetapi perlu dilakukan melalui $.ajax()
seperti di bawah ini.
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) {
// ...
}
});
Apakah dicatat bahwa banyak pemula campuran contentType
dengan dataType
. The contentType
mewakili tipe dari permintaan tubuh. The dataType
mewakili (diharapkan) tipe respon tubuh, yang biasanya tidak diperlukan sebagai jQuery sudah autodetects itu berdasarkan respon ini Content-Type
sundulan.
Kemudian, untuk memproses objek JSON dalam servlet yang tidak dikirim sebagai parameter permintaan individu tetapi sebagai keseluruhan string JSON dengan cara di atas, Anda hanya perlu mengurai tubuh permintaan secara manual menggunakan alat JSON alih-alih menggunakan getParameter()
yang biasa cara. Yakni, servlets tidak mendukung application/json
permintaan diformat, tetapi hanya application/x-www-form-urlencoded
atau multipart/form-data
permintaan diformat. Gson juga mendukung parsing string JSON menjadi objek 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();
// ...
Perhatikan bahwa ini semua lebih canggung daripada hanya menggunakan $.param()
. Biasanya, Anda hanya ingin menggunakan JSON.stringify()
jika layanan target mis. Layanan JAX-RS (RESTful) yang karena alasan tertentu hanya mampu mengkonsumsi string JSON dan bukan parameter permintaan reguler.
Mengirim redirect dari servlet
Penting untuk disadari dan dipahami adalah bahwa siapa pun sendRedirect()
dan forward()
panggilan oleh servlet pada permintaan ajax hanya akan meneruskan atau mengarahkan permintaan ajax itu sendiri dan bukan dokumen / jendela utama tempat permintaan ajax berasal. JavaScript / jQuery dalam hal demikian hanya akan mengambil respons yang dialihkan / diteruskan sebagai responseText
variabel dalam fungsi panggilan balik. Jika itu mewakili seluruh halaman HTML dan bukan respons XML atau JSON khusus ajax, maka yang dapat Anda lakukan hanyalah mengganti dokumen saat ini dengannya.
document.open();
document.write(responseText);
document.close();
Perhatikan bahwa ini tidak mengubah URL seperti yang dilihat pengguna di bilah alamat browser. Jadi ada masalah dengan kemampuan bookmark. Oleh karena itu, jauh lebih baik untuk mengembalikan "instruksi" untuk JavaScript / jQuery untuk melakukan pengalihan alih-alih mengembalikan seluruh konten halaman yang diarahkan. Misalnya dengan mengembalikan boolean, atau 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;
}
// ...
}
Lihat juga: