フォームからのデータをサーブレットで受け取る
8.4 フォームからのデータをサーブレットで受け取る
前節では、別画面から送信された入力データをJSPで受け取る方法について学習しました。本節では、別画面から送信された入力データをサーブレットで受け取る方法について学習します。
JSPではPOST送信データもGET送信データも同じように扱うことが可能でしたが、サーブレットの場合はPOST送信データとGET送信データではプログラムの動きが異なります。この点に注意して、学習していきましょう。
8.4.1 doGet()メソッドとdoPost()メソッド
これまで、サーブレットを作成する場合は、doGet()メソッドをオーバーライドしていました。このdoGet()メソッドは以下のような場合に実行されます。
・ ブラウザのアドレスバーに直接URLを入力して画面を表示した場合。
・ リンクをクリックして画面を表示した場合。
・ フォームの実行(submit)ボタンからGET送信で画面を表示した場合。
これまで作成したサーブレットでは、ブラウザのアドレスバーに直接URLを入力していたため、doGet()メソッドに処理を記述していましたが、POST送信で画面を表示する場合は、doGet()メソッドではなくdoPost()メソッドを利用します。
サーブレットへのアクセス方式と、呼び出されるメソッドの関係は次の表のようになります。
表 8.4.1:アクセス方法とサーブレットのメソッドの関係
8.4.2 送信データをサーブレットで扱う方法
Web画面からPOST送信されたデータをサーブレットで扱う場合、doGet()メソッドではなく、doPost()メソッドをオーバーライドします。HttpServletクラスからオーバーライドするメソッドなので、doGet()メソッド同様にメソッド名や引数などを正確に記述する必要があります。
書式:doPost()メソッド
また、送信されたデータを取得するには、JSPと同じようにgetParameter()メソッドを利用します。
サーブレットにおけるPOST送信アクセスとGET送信アクセスの違いは、doPost()メソッドが実行されるか、doGet()メソッドが実行されるかの違いだけで、実際の値の取得方法に違いはありません。
なお、サーブレットで実行するgetParameter()メソッドは、doPost()メソッドやdoGet()メソッドの引数に渡されてくるHttpServletRequestクラスの変数から利用することが可能です。
実行結果
アプリケーション構成
➢ postForm.jsp① 親フォルダの入力または選択 :web_basic/view/ch08
② ファイル名 :postForm.jsp
③ アクセスURL :http://localhost:8080/web_basic/view/ch08/postForm.jsp
<%@page contentType= "text/html; charset=UTF-8" %> <html> <head> <title>POST送信データを扱うサーブレット</title> </head> <body> <h2>POST送信フォーム</h2> <form action="<%= request.getContextPath() %>/PostReceiptServlet" method="post"> お名前:<input type="text" name="onamae"> <input type="submit" value="送信"> </form> </body> </html>
➢ PostReceiptServlet.java① ソース・フォルダ :web_basic/WEB-INF/src
② パッケージ :ch08
③ 名前 :PostReceiptServlet
④ スーパークラス :javax.servlet.http.HttpServlet
⑤ アクセスURL :postForm.jspからの画面遷移でアクセスされる
package ch08; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class PostReceiptServlet extends HttpServlet { //doPost()メソッド public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //パラメータの取得 String name = request.getParameter("onamae"); //コンテンツタイプの設定 response.setContentType("text/html; charset=UTF-8"); //画面出力 PrintWriter out = response.getWriter(); out.println("お名前は" + name + "さんですね。"); } }➢ web.xml
<servlet> <servlet-name>PostReceiptServletMapping</servlet-name> <servlet-class>ch08.PostReceiptServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>PostReceiptServletMapping</servlet-name> <url-pattern>/PostReceiptServlet</url-pattern> </servlet-mapping>
解説
今回のプログラムは、データを入力するWeb画面の「postForm.jsp」と、データの受け取り先のサーブレット「PostReceiptServlet.java」の2つのファイルから構成されています。
データの送信元である「postForm.jsp」は、前節で作成した「jspForm.jsp」のPOST送信部分と全く同じ内容なので、ここでの説明は省略し、データの受け取り先の「PostReceiptServlet.java」の処理について説明を行います。
「PostReceiptServlet.java」では、今までのサーブレットとは異なり、10行目と11行目でdoPost()メソッドをオーバーライドしています。「postForm.jsp」からデータがPOST送信されているためdoPost()メソッドが呼び出され実行されます。
14行目では、送信されたデータの取得を行なっています。getParameter()メソッドを使用し引数に部品名を渡す処理は、前節で作成したJSPでの受け取り方法と全く変わりません。
このプログラムはPOST送信アクセスを前提に作成されているため、doGet()メソッドが存在しません。この状態でGET送信アクセスをするとエラーになってしまうので、注意が必要です。
試しに、「postForm.jsp」の9行目にある「method=”post”」を「method=”get”」に変えて実行してみましょう。
図 8.4.1:methodの変更
methodをgetに変更し実行すると、図のようにエラーが表示されます。このように、doPost()メソッドのみのサーブレットの場合は、GET送信アクセスを受けることができないので注意しておきましょう。
図 8.4.2:GETメソッドがサポートされていないエラー
次にdoGet()メソッドのみを使ったサーブレットの例も見てみましょう。
doGet()メソッドを利用するサーブレット
別画面(送信元)からGET送信された入力データを送信先のサーブレットで受け取り、Webブラウザに表示します。doGet()メソッドが動作しデータが画面に表示されることを確認しましょう。
実行結果
アプリケーション構成
➢ getForm.jsp① 親フォルダの入力または選択 :web_basic/view/ch08
② ファイル名 :getForm.jsp
③ アクセスURL :http://localhost:8080/web_basic/view/ch08/getForm.jsp
<%@page contentType= "text/html; charset=UTF-8" %> <html> <head> <title>GET送信データを扱うサーブレット</title> </head> <body> <h2>GET送信フォーム</h2> <form action="<%= request.getContextPath() %>/GetReceiptServlet" method="get"> お名前:<input type="text" name="onamae"> <input type="submit" value="送信"> </form> </body> </html>
➢ GetReceiptServlet.java① ソース・フォルダ :web_basic/WEB-INF/src
② パッケージ :ch08
③ 名前 :GetReceiptServlet
④ スーパークラス :javax.servlet.http.HttpServlet
⑤ アクセスURL :getForm.jspからの画面遷移でアクセスされる
package ch08; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class GetReceiptServlet extends HttpServlet { //doGetメソッド public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //パラメータの取得 String name = request.getParameter("onamae"); //コンテンツタイプの設定 response.setContentType("text/html; charset=UTF-8"); //画面出力 PrintWriter out = response.getWriter(); out.println("お名前は" + name + "さんですね。"); } }➢ web.xml
<servlet> <servlet-name>GetReceiptServletMapping</servlet-name> <servlet-class>ch08.GetReceiptServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>GetReceiptServletMapping</servlet-name> <url-pattern>/GetReceiptServlet</url-pattern> </servlet-mapping>
解説
このプログラムは、POST送信データを扱う「postForm.jsp」と「PostReceiptServlet.java」の2つのファイルをGET送信データを扱うように変更したものです。
10行目と11行目でdoPost()メソッドの代わりにdoGet()メソッドをオーバーライドしています
14行目では送信されたデータの取得を行なっています。getParameter()メソッドを使用し引数に部品名を渡す処理は、POST送信データの受け取り方法と全く変わりません。
このプログラムはGET送信アクセスを前提に作成されているため、doPost ()メソッドが存在しません。この状態でPOST送信アクセスをすると「PostReceiptServlet.java」と同様のエラーが発生します。
「PostReceiptServlet.java」で試した方法と同じように、「getForm.jsp」の9行目にある「method=”get”」を「method=”post”」に変えて実行してみましょう。
図 8.4.3:methodの変更
methodをpostに変更し実行すると、図のようにとエラーが表示されます。このようにdoGet()メソッドのみのサーブレットの場合は、POST送信アクセスを受けることができません。
図 8.4.4:GETメソッドがサポートされていないエラー
もし、POST送信とGET送信のどちらからもアクセスを受けて処理を行う必要がある場合は、どのように記述すれば良いでしょうか。次のプログラムは、doPost()メソッドとdoGet()メソッドの両方を使ったサーブレットの例です。
doPost()メソッドとdoGet()メソッドの両方を利用するサーブレット
別画面(送信元)からGET送信、もしくはPOST送信された入力データを送信先のサーブレットで受け取り、Webブラウザに表示します。どちらの送信方式であってもデータが画面に表示されることを確認しましょう。
アプリケーション構成
➢ commonForm1.jsp① 親フォルダの入力または選択 :web_basic/view/ch08
② ファイル名 :commonForm1.jsp
③ アクセスURL :http://localhost:8080/web_basic/view/ch08/commonForm1.jsp
<%@page contentType= "text/html; charset=UTF-8" %> <html> <head> <title>送信データを扱うサーブレット</title> </head> <body> <h2>POST送信フォーム</h2> <form action="<%= request.getContextPath() %>/CommonReceiptServlet1" method="post"> お名前:<input type="text" name="onamae"> <input type="submit" value="送信"> </form> <h2>GET送信フォーム</h2> <form action="<%= request.getContextPath() %>/CommonReceiptServlet1" method="get"> お名前:<input type="text" name="onamae"> <input type="submit" value="送信"> </form> <a href="<%= request.getContextPath() %>/CommonReceiptServlet1?onamae=kanda">リンクで送信</a> </body> </html>
➢ CommonReceiptServlet1.java① ソース・フォルダ :web_basic/WEB-INF/src
② パッケージ :ch08
③ 名前 :CommonReceiptServlet1
④ スーパークラス :javax.servlet.http.HttpServlet
⑤ アクセスURL :commonForm1.jspからの画面遷移でアクセスされる
package ch08; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class CommonReceiptServlet1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //共通処理メソッドの呼び出し commonProcess(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //共通処理メソッドの呼び出し commonProcess(request, response); } //共通処理メソッド private void commonProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("onamae"); response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("お名前は" + name + "さんですね。"); } }➢ web.xml
<servlet> <servlet-name>CommonReceiptServlet1Mapping</servlet-name> <servlet-class>ch08.CommonReceiptServlet1</servlet-class> </servlet> <servlet-mapping> <servlet-name>CommonReceiptServlet1Mapping</servlet-name> <url-pattern>/CommonReceiptServlet1</url-pattern> </servlet-mapping>
実行結果
解説
このプログラムでは、以下の3つの方法でサーブレットを呼び出しています。
・ フォームの実行(submit)ボタンからPOST送信
・ フォームの実行(submit)ボタンからGET送信
・ リンクからのGET送信
「CommonReceiptServlet1.java」では、POST送信データとGET送信データのどちらからのアクセスでもプログラムが動くように、doPost()メソッドとdoGet()メソッドを実装しています。
この2つのメソッド内では、どちらもcommonProcess()メソッドを呼び出しています。
24行目から32行目に記述されたcommonProcess()メソッドでは、doPost()メソッドとdoGet()メソッドの共通処理である、データの取得と画面への出力を行なっています。
この共通処理を行うメソッドの名前は任意で設定して問題ありませんが、メソッド内で処理を行うために、引数にはHttpServletRequestオブジェクトとHttpServletResponseオブジェクトが必要になります。
このプログラムは以下のような構成をしています。
図 8.4.5:POSTデータを送信
このように、サーブレットで送信データを扱う場合は、サーブレットのどのメソッドが呼び出されるのかを考慮した作りが必要になりますので注意してください。
8.4.3 日本語を入力してみよう
ここまで作成したフォーム画面は、日本語入力をすると、以下のように文字化けが発生します。
図 8.4.6: 入力データの文字化け
日本語をブラウザに表示する際に発生した文字化けと同様に、ブラウザから入力された文字列もそのままの状態でWebサーバに送られているわけではなく、デフォルト文字コードである「ISO-8859-1(Latin1)」のデータに変換されてWebサーバ側に送信されます。
そのため、ブラウザからWebサーバに送るための設定を行なっていないプログラムでは、この文字化けが発生してしまいます。
ブラウザから入力されたデータをWebサーバへ送信する際の文字化けが発生する流れは、下の図のようになります。
図 8.4.7: 文字化けの流れ
この文字化けを防ぐには、文字エンコーディングを指定する必要があります。
文字エンコーディングは、以下の書式でサーブレット内の処理でデータを取得する前に定義します。
なお、5章で学習したresponse.setContentType()メソッドの文字エンコーディングは「出力する文字の文字コード」を指定するもので、この章で学習するrequest.setCharacterEncoding()メソッドは「フォームから受け取るデータの文字コード」を指定するものです。2つの文字コードの設定は別であることに注意してください。
では、文字エンコーディングを設定するプログラムを作成しましょう。
日本語を入力し正常に表示するプログラム
Webブラウザで英文字と日本語を表示するプログラムを作成して、日本語が正しく表示されることを確認します。
実行結果
アプリケーション構成
➢ commonForm2.jsp① 親フォルダの入力または選択 :web_basic/view/ch08
② ファイル名 :commonForm2.jsp
③ アクセスURL :http://localhost:8080/web_basic/view/ch08/commonForm2.jsp
<%@page contentType= "text/html; charset=UTF-8" %> <html> <head> <title>日本語の送信データを扱うサーブレット</title> </head> <body> <h2>POST送信フォーム</h2> <form action="<%= request.getContextPath() %>/CommonReceiptServlet2" method="post"> お名前:<input type="text" name="onamae"> <input type="submit" value="送信"> </form> <h2>GET送信フォーム</h2> <form action="<%= request.getContextPath() %>/CommonReceiptServlet2" method="get"> お名前:<input type="text" name="onamae"> <input type="submit" value="送信"> </form> </body> </html>
➢ CommonReceiptServlet2.java① ソース・フォルダ :web_basic/WEB-INF/src
② パッケージ :ch08
③ 名前 :CommonReceiptServlet2
④ スーパークラス :javax.servlet.http.HttpServlet
⑤ アクセスURL :commonForm2.jspからの画面遷移でアクセスされる
package ch08; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class CommonReceiptServlet2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //共通処理メソッドの呼び出し commonProcess(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //共通処理メソッドの呼び出し commonProcess(request, response); } //共通処理メソッド private void commonProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //入力データの文字コードの指定 request.setCharacterEncoding("UTF-8"); String name = request.getParameter("onamae"); response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("お名前は" + name + "さんですね。"); } }➢ web.xml
<servlet> <servlet-name>CommonReceiptServlet2Mapping</servlet-name> <servlet-class>ch08.CommonReceiptServlet2</servlet-class> </servlet> <servlet-mapping> <servlet-name>CommonReceiptServlet2Mapping</servlet-name> <url-pattern>/CommonReceiptServlet2</url-pattern> </servlet-mapping>
解説
このプログラムのポイントは、setCharacterEncoding()メソッドを使うことによって正しく日本語が表示されるようになった点です。
26行目で、日本語に対応した「UTF-8」の文字コードを指定しています。
実行結果からもわかるように、日本語に対応した文字エンコーディングを記述したことで、文字化けしていた部分が正しい日本語で表示されるようになりました。
なお、setCharacterEncoding()メソッドは取得する文字の文字コードを設定するため、getParameter()メソッドより前に実行する必要があります。
図 8.4.8: 文字化けの流れ
TomcatのGET送信時のデコード(復号化)の設定Tomcat5以降では、GET送信でデータを送る場合、デフォルトの設定では「ISO-8859-1(Latin1)」でデコードされます。そのため、受け取り側のプログラム内でsetCharacterEncoding()メソッドで文字エンコーディングを指定してもデフォルトでは無視されてしまい、文字化けが発生します。
このデフォルト設定を変更するには以下のファイルを編集する必要があります。なお、当スクールの環境ではすでに設定済みですので編集する必要はありません。
C:\usr\kis_java_pkg_ver4.8\pleiades\tomcat\8\conf\server.xml
このファイルはTomcatの動作を設定するためのファイルで、図の70行目にある「useBodyEncodingForURL=”true”」を指定することで、GET送信時の文字エンコーディングをsetCharacterEncoding()メソッドで指定できるようになります。