前回は、サーブレットからJSPにデータを渡して表示するところまでをやりました。

今回は、多くのWebアプリケーションでその前処理にあたる部分、すなわちフォームからデータをサーブレットに渡すところをやってみます。

1. フォームの復習

HTMLのフォームの復習です。

下図4.1のように新しく「04Form」というフォルダを用意してその中にウェルカムファイル「index.html」を用意してください。

図4.1 フォルダ構成

以下のフォームを用意します。

  • このフォームのメソッドは何ですか?
あなたの答え:
  • このメソッドの指定は省略できますか?
あなたの答え:
  • フォームの中の部品はいくつありますか?
あなたの答え:
  • それぞれどのような部品でしょうか?
あなたの答え:
  • また、名前の付いた部品はいくつあって、それぞれ何という名前が付けられていますか?
あなたの答え:

答えられなかった人はHTMLに戻って復習の必要があります。

2. サーブレットの復習

次に下図4.2のようにサーブレットを用意します。

「p04」というパッケージを作って「AddServlet.java」としました。

AddServlet
図4.2 ソースパッケージの構成

ソースコードは以下のとおりです。

  • このサーブレットはどのようなurlPatternで呼び出されますか?
あなたの答え:

urlPatterns = {"/Add"}ということでJavaのクラス名のAddServletではない点に注意してください。

  • リクエスト属性にはどの様な値がどの様な名前で格納されますか?
あなたの答え:
  • フォワード先のJSPのパス名とファイル名をそれぞれ答えなさい。
あなたの答え:

※今回は3章(03Servlet)のJSPを再利用しているわけですね。

  • フォワードした後のアドレスバーの表記はどうなりますか?
    ただし、フォームにはそれぞれ1と2を入力したものとします。
あなたの答え:http://localhost:8080/

これらに答えられなかった方は前回の内容を復習する必要があります。

2.1.フォームからサーブレットを呼び出す際の記述方法

今回のポイントはHTMLの9行目、actionで指定している送信先です。

<form action="/03_JavaWebText/AddServlet">

/プロジェクト名(コンテキストルート)/URLPatternとなっています。

このようにサーブレットはパッケージ名やクラス名とは無関係に URLPattern で呼び出すことができます

決して、以下のようにパッケージ名は必要ではありませんから注意してください。

<form action="/03_JavaWebText/p04/AddServlet">

実験1

ひとまず上記の書き方を知っていただければ結構ですが、もう一つ次のような相対パスを使った書き方があります。

<form action="../AddServlet">

この書き方を理解するには、下図4.3のようなWebページフォルダのフォルダ構成を理解する必要があります。

カレントディレクトリから1つ階層を上がってWebページフォルダから URLPattern で呼び出す必要があるのです。

図4.3 相対パス

試してみてください。

試した結果:

3. httpリクエストの読み方

ここでは下図4.4を使いhttpリクエスト の読み方について解説します。

①は通信プロトコルです。

②はFQDN【Fully Qualified Domain Name】で絶対ドメイン名と呼ばれます。
 ホスト名とドメイン名からなっていてホスト名はインターネットでよくwwwという表記を見かけると思います。 
 なお、ここは直接IPアドレス(例.192.168.0.1)を指定することもできます。

③はポート番号です。8080番はGlassfishやTomcatでデフォルトで使用され、httpの80番に見た目が似ていること、ウェルノウンポート以外であることから使われています。

④コンテキスト名はWebアプリケーションの名前です。Netbeansを使っている場合プロジェクト名がそのままコンテキスト名になります。

⑤URLパターンはサーブレットが呼び出される際の名前でした。本研修では@WebServletアノテーションで設定しています。

⑥getリクエストの場合は最後にパラメータが付きます。

図4.4 httpリクエストの読み方

また、下図4.5(a)のとおり④と⑤の間の/をコンテキストルートと呼びます。

コンテキストルートはNetbeansの場合はWebページというフォルダを意味します。

そしてウェルカムファイルの場合はファイル名を省略できますからWebページフォルダの直下の「index.html」は下図4.5の(b)の方法でも指定できます。

混乱しがちなのがServletの指定方法です。

これはWebのパス指定とは無関係にURLパターンで指定すると考えてください。 (下図4.5の(c)

新人エンジニア研修でPath指定を説明
図4.5 Webページがコンテキストルートにあたる

なお、「WEB-INF」というディレクトリがあります。(下図4.5の(d)

このディレクトリには外部に公開しない内部処理用の重要なファイルを格納します。(時々操作を誤ってこのフォルダにファイルを移動してしまうことがありますので気をつけてください)

「WEB-INF」 は外部から直接アクセスできないようになっています。

4. getParameterメソッド

先程のサーブレットの18行目を見てください。

int num1 = Integer.parseInt(request.getParameter("num1"));

  • Integer.parseInt()はインスタンスメソッドでしょうか? それともクラス(スタティック)メソッドでしょうか?
あなたの答え:
  • このメソッドは引数の文字列を何に変換しますか?
あなたの答え:

忘れてしまった人は、Integerクラスまで戻って復習してください。

今回の注目点はこの部分です。

request.getParameter("num1")

requestのgetParameterメソッドを使っています。

のメソッド はフォームから送られたリクエストのインスタンスに入っている文字列を取り出すことができます。

ここでフォームから送られるデータはすべて文字列として送られることを思い出してください。

また、フォームから送られるデータは1つとは限りません。

そのため“num1”などのテキストフィールドに付けた名前で指定して受け取る必要があるのです。

今回の処理の概要を下図4.6にまとめておきます。

図4.6 計算処理の全体像

5. フォームに入力された日本語を表示する

今度はフォームに入力された日本語を表示するWebアプリケーションを作成してみます。

フォームに名前を入れると名前を呼んで「こんにちは」と表示するプログラムです。

入力:「今井」

出力:「こんにちは今井さん」

というイメージです。

まずは、入力フォームです。

  • 送信ボタンを押した際の飛び先はどこですか?
あなたの答え:
  • どのようなフォームを使ってどのような名前でデータを送っていますか?
あなたの答え:

次にControllerとしてのサーブレットです。

  • 18行目では何をしていますか?
あなたの答え:
  • 20行目では何をしていますか?
あなたの答え:
  • 21行目では何をしていますか?
あなたの答え:

最後にViewとしてのJSPです。

中身は特に今までと変わったところはありません。

ところがフォームから名前を入力すると以下のように文字化けが起きます。

「こんにちはやまざきさん」

どうしたら良いのでしょうか?

結論から言うとフィルタ【filter】という特別な役割を持ったクラスを作れば問題解決です。

ちょうど浄水器のフィルタが水道水をおいしい水に変えるように、フィルタを通すことでリクエストやレスポンスのデータに加工を施すことができます。

例えば、フィルタを使い暗号化したりログを取ったりといったことができるようになります。

しかも、フィルタは特定のサーブレット(含むJSP)にだけ施すこともできます。

  • あるサーブレットとの通信だけログを取る
  • あるサーブレットとの通信だけ暗号化する
  • あるサーブレットとの通信はログを取りつつ暗号化する

ということができます。

当社の新人エンジニア研修では、日本語の文字化け対策としてすべてのサーブレット(含むJSP)間の通信をUTF-8でエンコードする目的でのみフィルタを使用します。

下図4.7以降でNetBeans8.2を使ったフィルタの作り方を説明します。

1.ソース・パッケージに「filter」のような分かりやすい名前でパッケージを作ります。

2.作成したパッケージ上で右クリックして、「新規」-「フィルタ」を選択します。

図4.7 フィルタの作り方

3.下図4.8でクラス名を付けます。今回は「Japanese」としました。

図4.8

4.フィルタ・マッピングを指定します。

フィルタ・マッピングとはどのフィルタをどのサーブレットに適用するかという指定です。

今回は、この「Japanese」フィルタをすべて(/*)に適用します。

下図4.9の設定ができたら「終了」ボタンを押してください。

図4.9

5.doFilterメソッドを書き換えます。

100行目前後にdoFilterというメソッドがあります。

以下のようにdoFilterメソッドを書き換えてください。

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 文字コード設定
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=" + "UTF-8");
        chain.doFilter(request, response);
    }

以上でJavaWebアプリケーションで日本語を扱う設定は完了です。

このフィルタはプロジェクト全体に対してかかっています。

ですので、プロジェクトが変われば新しくフィルタを設定する必要があります。

今後の演習で新しいプロジェクトを作ったらこのフィルタをパッケージごとソース・パッケージにコピーすることを忘れないようにしてください。

6. XSS対策をする

実は上記のWebアプリケーションには入力フォームにJavaScriptを挿入されてXSS(クロスサイトスクリプティング: 【cross site scripting】)を実行されてしまうという脆弱性があります。

おそらく最近もXSSの被害事例があると思いますのでリンクをたどってみてください。

入力フォーム<japanese_form.html>の入力欄に次のようなJavaScriptを入力してみてください。

<script>alert("いけない情報");</script>

すると下図4.10のようなダイアログボックスが表示されたと思います。

図4.10 JavaScriptが実行されてしまう

HTMLのソースを見ると次のようになっています。

詳しくは述べませんが、入力フォームに流し込んだJavaScriptが実行できるということは、このWebアプリケーションではJavaScriptでできることは何でもできるということです。

JavaScriptが実行されるということはXSS攻撃にさらされる可能性があるということです。(とは言っても研修で使用する最新のブラウザですとほとんど問題ありませんが)

どうしたら良いのでしょうか?

出力先のJSPを次のようにしてみてください。

  • <japanese1.jsp> との違いを2点挙げてみてください。
あなたの答え:

「sun.com」とは何か?

「c:out」のcとは何か?

といった疑問が浮かぶかも知れません。

詳細は後ほど、「7.ELとJSTLで様々な表現ができるようになる」というテーマで扱います。

どうしても気になる方はインターネットで調べてください。

上記の実行結果は下図4.11のとおりになりました。

図4.11

HTMLのソースを見ると以下のようになっています。(抜粋)

<h1>こんにちは&lt;script&gt;alert(&#034;いけない情報&#034;);&lt;/script&gt;さん</h1>

つまり、<が&lt(【less than】の意味)、>が&gt(【greater than】の意味)のようにタグを変換してくれるのです。

なお、 &lt や &gt を文字実体参照と呼びます。

このようにプログラムでサニタイズsanitizeとは、JavaScriptなどの特別な意味を持つ可能性のある文字列を置き換えて無効化することをいいます。

サニタイズとはもともと消毒という意味の英語です。

Java以外の言語にもサニタイズの仕組みが備わっていますので、Webアプリケーションを作成する際は気をつけましょう。

7. エラー入力を適切に処理する

ここまで学ぶと下図4.12の通りMVCモデルの解説のところの数当てゲームも理解できるのではないでしょうか?

図4.12 答えが5で正解したケース

入力画面、ModelとViewは以下の通りでした。

このとき、入力値を0-9に制限するにはどのファイルのどの部分を変更すればよいでしょうか?

いろいろな方法が考えられますが、ひとまずservlet(と入力用HTML)だけに手を加える方法を試してみます。

確かにこれで想定外の整数値をエラーにすることができました。

しかし、フォームに「あ」のような文字列や「5.0」のような実数を入力されると下図4.13のNumberFormatExceptionがでます。

図4.13NumberFormatException

このような不適切な入力に対処するにはどうしたら良いのでしょうか?

JavaSEで学んだ例外処理が使えます。

※整数以外が入力された時の「答えは」という文言が気になる方は、後でJSTLを学ぶと条件に応じてこのような文字列を消せるようになりますのでしばらくお待ち下さい。

  • GameServlet2からGameServlet3の変更点を隣の席の人に説明してください。
あなたの答え:

ユーザーはエンジニアが想定しない使い方をするものです。

また、テストのところでも詳しくお話したいと思います。

8. ハイパーリンクを使って送られたデータを受け取る

ここでは、天気予報プログラムのプロトタイプを考えてみましょう。

全国のユーザーが現在の天気を送るとリアルタイムで全国の天気が分かり、また、予測も可能になるというシステムのプロトタイプです。

図4.14 天気予報サイトのイメージ

リンクを使ってデータを送ることができます。

以下のように?の後ろにリクエストパラメターを付けて送ります。

<a href="/03_JavaWebText/Weather2?weather= 晴れ ">晴れ</a>

このとき「?weather="晴れ"」のように文字列扱いしたくなりますが、 「?weather=晴れ」 で大丈夫です。

サーブレットとJSPには変更を加える必要はありません。

では、もしも仮に「Weather1.java」にdoGetメソッドの代わりにdoPostメソッドがあったとしたらどうなると思いますか?

下図4.15のようなエラーになりますので試してみてください。

図4.15 サポートされていないメソッドのエラー画面

aタグを使ったリンクは常にGETメソッドになることを覚えておいてください。

例題4

上記link.htmlに雪の場合を加えなさい。

例題5

これまで作成してきた数当てゲームをリンクを使って実現しなさい。

図4.16

9. ボタンを使って送られたデータを受け取る

ボタンを使ってデータを送ります。

サーブレットWeather1.javaには変更点はありませんが、念のため再掲しました。

例題6

上記button.htmlに雪の場合を加えなさい。

例題7

数当てゲームをボタンを使って実現しなさい。

図4.16

今回はフォームからデータをサーブレットに渡す方法について学びました。

フォームにはラジオボタンやセレクトボックスもあります。

最終課題でそれらのフォームも使いたい方は、以下の補講を見てください。

補講:その他のフォームからデータをサーブレットに渡す

次回は、ログイン処理の実装とセッション属性を学んでいきます。

ログイン処理が書けるとかなりWebアプリケーションらしくなります。

<まとめ:隣の人に正しく説明できたらチェックを付けましょう>

□ サーブレットはパッケージ名やクラス名とは無関係に URLPattern で呼び出すことができる

□ フォームから送られるデータはすべて文字列として送られるため数値にするにはInteger.parseIntメソッドを使う

□ requestのgetParameter はフォームから送られたリクエストのインスタンスに入っている文字列をname属性を手がかりに取り出す

□ 日本語の文字化け対策には今回作成したフィルタをプロジェクトのソース・パッケージにコピーすればよい

□ プログラムでサニタイズとは、JavaScriptなどの特別な意味を持つ可能性のある文字列を置き換えて無効化することをいう

□ if文や例外処理をつかって入力エラーを適切に処理する

□ aタグを使ったリンクは常にGETメソッドになる

JavaWebアプリケーション目次に戻る