サーブレットとAjaxはどのように使用すればよいですか? 質問する

サーブレットとAjaxはどのように使用すればよいですか? 質問する

サーブレット内で何かを印刷し、それを 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>ProductLong idString nameBigDecimal 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 はレスポンスのヘッダーに基づいて既に自動検出しているため、通常は必要ありません。dataTypeContent-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;
    }

    // ...
}

参照:

おすすめ記事