web-dev-qa-db-ja.com

サーブレットとAjaxの使い方

私はWebアプリケーションとサーブレットにとても不慣れで、次の質問があります。

サーブレット内で何かを印刷してWebブラウザで呼び出すと、そのテキストを含む新しいページが返されます。 Ajaxを使って現在のページのテキストを印刷する方法はありますか?

318
Amir Rachum

実際、キーワードは「ajax」です:Asynchronous JavaScript and XML。ただし、昨年は頻繁に非同期JavaScriptとJSONを使用しています。基本的に、JSに非同期HTTP要求を実行させ、応答データに基づいてHTML DOMツリーを更新します。

すべてのブラウザ(特にInternet Explorerと他のブラウザ)で動作するようにするのはかなり 退屈 なので、単一の機能でこれを単純化し、可能な限り多くのブラウザをカバーするJavaScriptライブラリがたくさんあります。 jQueryプロトタイプMootools など、内部の特定のバグ/癖。 jQueryは最近最も人気があるため、以下の例で使用します。

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.
}

以下のように、このサーブレットを/someservletまたは/someservlet/*のURLパターンにマッピングします(明らかに、URLパターンは自由に選択できますが、JSコードのsomeservlet URLを変更する必要がありますそれに応じてすべての場所の例):

@WebServlet("/someservlet/*")
public class SomeServlet extends HttpServlet {
    // ...
}

または、サーブレット3.0互換のコンテナ(Tomcat 7、Glassfish 3、JBoss AS 6など)をまだ使用していない場合は、web.xmlに昔ながらの方法でマッピングします( も参照)サーブレットwikiページ ):

<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アプリケーションの/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として自動的に解析し、応答コンテンツタイプをapplication/jsonに設定すると、関数引数としてJSONオブジェクト(responseJson)を直接提供することに注意してください。設定を忘れたり、デフォルトの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 idString 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として返す

これは、前の例と事実上同じですが、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="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".
    });
});

Ajaxを使用してHTML文書を更新するという特定の目的のために、XMLがJSONよりもはるかに強力である理由をおそらくご存知でしょう。 JSONはおもしろいですが、結局のところ、一般にいわゆる「パブリックWebサービス」にのみ有用です。 JSF のようなMVCフレームワークは、Ajaxマジックの裏でXMLを使用します。

既存のフォームのAjaxifying

JQuery $.serialize() を使用して、個々のフォーム入力パラメーターを収集して渡すことなく、既存のPOSTフォームを簡単にajaxifyできます。 JavaScript/jQueryがなくても完全に正常に動作する既存のフォームを想定します(したがって、エンドユーザーが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()メソッドを再利用できます。上記の構文は、jQueryの$.get()およびサーブレットのdoGet()でも機能することに注意してください。

JSONオブジェクトをサーブレットに手動で送信する

ただし、何らかの理由で個別のリクエストパラメータとしてではなく、JSONオブジェクト全体を送信する場合は、 JSON.stringify() (jQueryの一部ではない)を使用して文字列にシリアル化する必要があります。要求コンテンツタイプを(デフォルト)application/jsonではなくapplication/x-www-form-urlencodedに設定するjQuery。これは$.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) {
        // ...
    }
});

多くのスターターがcontentTypedataTypeを組み合わせていることに注意してください。 contentTypeは、requestボディのタイプを表します。 dataTypeは、response本文の(予想される)タイプを表します。これは通常、jQueryが応答の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リクエストでサーブレットによるsendRedirect()およびforward()の呼び出しは、ajaxリクエスト自体を転送またはリダイレクトするだけであり、ajaxのメインドキュメント/ウィンドウではないことです要求が発信されました。このような場合、JavaScript/jQueryは、コールバック関数のresponseText変数としてリダイレクト/転送された応答のみを取得します。それがajax固有のXMLまたはJSON応答ではなくHTMLページ全体を表す場合、できることは現在のドキュメントをそれに置き換えるだけです。

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;
    }

    // ...
}

こちらもご覧ください:

545
BalusC

ユーザーのブラウザに現在表示されているページを更新する正しい方法は(再ロードせずに)、ブラウザで実行されているコードにページのDOMを更新させることです。

そのコードは通常、HTMLページに埋め込まれているか、HTMLページからリンクされているJavaScriptです。したがって、AJAXの提案です。 (実際、更新されたテキストがHTTPリクエストを介してサーバーから送られてくると仮定すると、これは古典的なAJAXです。)

DOMを更新するためにプラグインがブラウザのデータ構造に到達するのは難しいかもしれませんが、何らかのブラウザプラグインやアドオンを使ってこの種のことを実装することも可能です。 (ネイティブコードプラグインは通常、ページに埋め込まれているグラフィックフレームに書き込みます。)

14
Stephen C

私はあなたにサーブレットの全体の例とどのように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);
        } 
    }
}
13
$.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);
 }
});
7
SUBZ

Ajax(またはAJAX)(Asynchronous JavaScript and XMLの頭字語)は、非同期Webアプリケーションを作成するためにクライアント側で使用される、相互に関連したWeb開発技術のグループです。 Ajaxを使用すると、Webアプリケーションはサーバーに非同期にデータを送信したり、サーバーからデータを取得したりできます。以下にコード例を示します。

2つの変数firstNameとlastNameを使用してサーブレットにデータを送信するためのJSPページのJavaスクリプト関数。

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);

    }

Xml形式でjspに送り返されるデータを読み取るサーブレット(テキストを使用することもできます。応答コンテンツをテキストに変更し、データを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>");
}
7
user3468976

通常、サーブレットからページを更新することはできません。クライアント(ブラウザ)はアップデートを要求しなければなりません。 Eiterクライアントが新しいページ全体をロードするか、既存のページの一部に対する更新を要求します。この手法はAjaxと呼ばれています。

5
Peter Knego

ブートストラップマルチセレクトの使用

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")
4