サーブレット内で何かを印刷し、それを Web ブラウザーで呼び出すと、そのテキストを含む新しいページが返されます。Ajax を使用して現在のページのテキストを印刷する方法はありますか?
私は Web アプリケーションとサーブレットについてはまったくの初心者です。
ベストアンサー1
確かに、キーワードは「Ajax」、つまり非同期 JavaScript と XMLです。ただし、昨年は非同期 JavaScript と JSON が使われることが多くなりました。基本的には、JavaScript に非同期 HTTP リクエストを実行させ、応答データに基づいて HTML DOM ツリーを更新させます。
きれいなので仕事に行くのに退屈な仕事すべてのブラウザ(特にInternet Explorerと他のブラウザ)で、これを単一の関数に簡素化し、可能な限り多くのブラウザ固有のバグや癖をカバーするJavaScriptライブラリがたくさんあります。jQuery、プロトタイプ、ムーツール最近はjQueryが最も人気があるので、以下の例ではjQueryを使用します。
キックオフの例はString
プレーンテキストとして返されます
以下のようなものを作成します/some.jsp
:
<!DOCTYPE html>
<html lang="en">
<head>
<title>SO question 4112686</title>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
const yourServletURL = "${pageContext.request.contextPath}/yourServlet";
$(document).on("click", "#somebutton", function() { // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
$.get(yourServletURL, function(responseText) { // Execute Ajax GET request on your servlet URL 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()
次のようなメソッドを持つサーブレットを作成します。
@WebServlet("/yourServlet")
public class YourServlet extends HttpServlet {
@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 パターンは/yourServlet
自由に選択できますが、変更する場合は、それに応じて JS 変数/yourServlet
の文字列を変更する必要がありますyourServletURL
。
ブラウザで http://localhost:8080/context/test.jsp を開き、ボタンを押します。div のコンテンツがサーブレットの応答で更新されることがわかります。
List<String>
JSONとして返す
と翻訳応答形式としてプレーンテキストの代わりに、さらに一歩先へ進むことができます。これにより、よりダイナミックな処理が可能になります。まず、JavaオブジェクトとJSON文字列を変換するツールが必要です。そのようなツールも多数あります(このページ私のお気に入りはGoogle グーグル。
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);
}
JavaScript コード:
$(document).on("click", "#somebutton", function() { // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
$.get(yourServletURL, function(responseJson) { // Execute Ajax GET request on your servlet URL and execute the following function with Ajax response JSON...
const $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として自動的に解析し、responseJson
レスポンスコンテンツタイプを に設定すると、関数の引数としてJSONオブジェクト( )を直接渡すことに注意してください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(yourServletURL, function(responseJson) { // Execute Ajax GET request on your servlet URL and execute the following function with Ajax response JSON...
const $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(yourServletURL, function(responseJson) { // Execute Ajax GET request on your servlet URL and execute the following function with Ajax response JSON...
const $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として返す
これは、前の例と実質的に同じことをする例ですが、JSON ではなく XML を使用します。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="jakarta.tags.core" %>
<%@taglib prefix="fmt" uri="jakarta.tags.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>
JavaScript コード:
$(document).on("click", "#somebutton", function() { // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
$.get(yourServletURL, function(responseXml) { // Execute Ajax GET request on your servlet URL 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".
});
});
おそらく、Ajaxを使用してHTML文書を更新するという特定の目的において、XMLがJSONよりもはるかに強力である理由がお分かりでしょう。JSONは面白いですが、結局のところ、いわゆる「パブリックWebサービス」にしか役に立ちません。MVCフレームワークのようなJSFAjax マジックのために、裏で XML を使用します。
既存のフォームをAjax化する
jQueryを使うことができます$.serialize()
個々のフォーム入力パラメータを収集して渡す手間をかけずに、既存の POST フォームを簡単に Ajax 化します。JavaScript/jQuery なしでも完全に正常に動作する既存のフォーム (したがって、エンド ユーザーが JavaScript を無効にした場合は適切に機能が低下します) を想定します。
<form id="someform" action="${pageContext.request.contextPath}/yourServletURL" 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) {
const $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
ファイルのアップロードに必要なフォームの透過的なサポートが追加されています。
サーブレットにリクエストパラメータを手動で送信する
フォームがまったくなく、単に「バックグラウンドで」サーブレットとやりとりしてデータをPOSTしたい場合は、jQueryを使用できます。$.param()
application/x-www-form-urlencoded
通常の HTML フォームで使用されるのとまったく同じように、JSON オブジェクトをコンテンツ タイプごとに URL エンコードされたクエリ文字列に簡単に変換できるため、引き続き使用してrequest.getParameter(name)
データを抽出できます。
const params = {
foo: "fooValue",
bar: "barValue",
baz: "bazValue"
};
$.post(yourServletURL, $.param(params), function(response) {
// ...
});
の$.post()
基本的には次の略語である$.ajax()
電話。
$.ajax({
type: "POST",
url: yourServletURL,
data: $.param(params),
success: function(response) {
// ...
}
});
doPost()
前のセクションで示したのと同じメソッドを再利用できます。上記の$.post()
構文は、$.get()
jQuery とdoGet()
サーブレットで。
JSONオブジェクトをサーブレットに手動で送信する
しかし、何らかの理由でJSONオブジェクトを個別のリクエストパラメータとしてではなく全体として送信する場合は、次のようにして文字列にシリアル化する必要があります。JSON.stringify()
(jQuery の一部ではありません) であり、jQuery にリクエスト コンテンツ タイプをapplication/json
(default) の代わりにに設定するように指示しますapplication/x-www-form-urlencoded
。これは便利な関数では実行できません$.post()
が、以下のように実行する必要があります$.ajax()
。
const data = {
foo: "fooValue",
bar: "barValue",
baz: "bazValue"
};
$.ajax({
type: "POST",
url: yourServletURL,
contentType: "application/json", // NOT dataType!
data: JSON.stringify(data),
success: function(response) {
// ...
}
});
多くのスターターはcontentType
を混在させていることに注意してくださいdataType
。 はリクエストcontentType
本体のタイプを表します。 はレスポンス本体の(予想される)タイプを表しますが、jQuery はレスポンスのヘッダーに基づいて既に自動検出しているため、通常は必要ありません。dataType
Content-Type
次に、個々のリクエスト パラメータとしてではなく、上記の方法で JSON 文字列全体として送信される JSON オブジェクトをサーブレットで処理するには、getParameter()
通常の方法を使用する代わりに、JSON ツールを使用してリクエスト本文を手動で解析するだけです。つまり、サーブレットは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()
ターゲット サービスが、何らかの理由で JSON 文字列しか使用できず、通常のリクエスト パラメータを使用できない JAX-RS (RESTful) サービスなどの場合にのみ、 を使用します。
サーブレットからリダイレクトを送信する
認識して理解しておくべき重要な点は、Ajax リクエストでのサーブレットによるanysendRedirect()
および呼び出しは、Ajax リクエスト自体のみを転送またはリダイレクトし、Ajax リクエストの発信元であるメインのドキュメント/ウィンドウは転送またはリダイレクトしないということです。このような場合、JavaScript/jQuery は、コールバック関数の変数としてリダイレクト/転送された応答のみを取得します。それが HTML ページ全体を表しており、Ajax 固有の XML または JSON 応答ではない場合、実行できる操作は、現在のドキュメントをそれに置き換えることだけです。forward()
responseText
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;
}
// ...
}