ネットワークプログラミング論 平成 27 年 11 月 23 日 第8章.オブジェクトのスコープ -リクエストとセッション 【学習のねらい】 ① フォワード(forward)によってサーブレットや JSP 間でデータの受け渡しを行う際、 受け渡しが可能な範囲(スコープ)があることを理解する。 ② リクエストスコープとセッションスコープの違いを、実例を通じて理解する。 <先週の復習> 講義で示された【基礎課題 8-1】に解答して下さい。 8-1.リクエスト属性の受け渡し 本章では、まず次のような Web アプリケーショ ンを作成しましょう。 所定の JSP に接続すると、次のような画面が 現れるので、ここで、購入したい商品を選択す る( 【基礎課題 6-7】で作成した JSP と同様) 。 選択後、 [送信]ボタンをクリックする。 すると、今度は次の画面に移るので、ここ では購入したい書籍を選択する。 [送信]ボタンクリック後、全購入品目が まとめて表示された画面に移動する。 105 ネットワークプログラミング論 平成 27 年 11 月 23 日 この Web アプリケーションを、ここでは次のような流れ(構成)で作ります。 forward リクエスト1 購入画面1 kounyu1.jsp サーブレット1 (購入商品1) KounyuServlet1.java 購入画面2 (購入商品1) kounyu2.jsp リクエスト2 (購入商品2) レスポンス ブラウザ サーブレット2 購入商品ページ KounyuServlet2.java この Web アプリケーションのポイントは、 「購入画面1」で指定した商品データ(購入商 品1)をサーブレット2まで保持しておくということです。そのために、サーブレット 1 を用意し、 (第 7 章で学習したように) 「購入商品1」のデータをリクエスト属性に保管し 転送(forward)しています。「購入画面1」および「購入画面2」からの入力データの受 け取りは第 6 章で学習した通りにやればできます。この方針にしたがって、次のように各 JSP およびサーブレットを作成してみましょう。 ① 【基礎課題 6-7】で作成した「checkbox.jsp」を次のように修正して「kounyu1.jsp」 と別名保管してください。 <kounyu1.jsp> <%@page contentType="text/html; charset=Windows-31J"%> <HTML> <BODY> <H2>購入画面1</H2> 購入したい商品を選んで下さい。<br> <FORM ACTION="../KounyuServlet1" METHOD="POST"> <INPUT TYPE="CHECKBOX" NAME="Shohin1" VALUE="ノート PC">ノート PC <INPUT TYPE="CHECKBOX" NAME="Shohin1" VALUE="iPhone 6">iPhone 6 <INPUT TYPE="CHECKBOX" NAME="Shohin1" VALUE="任天堂 Wii U"> 任天堂 Wii U<br><br> <INPUT TYPE="SUBMIT" VALUE="送信"> <INPUT TYPE="RESET"> </FORM> </BODY> </HTML> ② 次に同じく【基礎課題 6-7】で作成した「CheckBoxServlet.java」を次のように修正し て「KounyuServlet1.java」と別名保管してください。 106 ネットワークプログラミング論 平成 27 年 11 月 23 日 package input; import java.io.IOException; import java.io.PrintWriter; import import import import import <KounyuServlet1.java> 追加 javax.servlet.RequestDispatcher; javax.servlet.ServletException; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; public class KounyuServlet1 extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("Windows-31J"); response.setContentType("text/html;charset=Windows-31J"); (ア) String[] values1=request.getParameterValues("Shohin1"); (ウ) request.setAttribute("Shohin1", values1); RequestDispatcher dispatcher= (イ) request.getRequestDispatcher("/input/kounyu2.jsp"); dispatcher.forward(request,response); } } ※ (ア)は p.82 の【解説】 、 (イ)は p.88、そして(ウ)は p.93 の【解説】参照 ③ 「kounyu1.jsp」を次のように修正して「kounyu2.jsp」と別名保管してください。 <%@page contentType="text/html; charset=Windows-31J"%> <HTML> <kounyu2.jsp> <BODY> <H2>購入画面2</H2> 購入したい書籍を選んで下さい。<br> <FORM ACTION="KounyuServlet2" METHOD="POST"> <INPUT TYPE="CHECKBOX" NAME="Shohin2" VALUE="基礎からのサーブレット/JSP">基礎からのサーブレット/JSP <INPUT TYPE="CHECKBOX" NAME="Shohin2" VALUE="プロになるための Web 技術入門">プロになるための Web 技術入門 <INPUT TYPE="CHECKBOX" NAME="Shohin2" VALUE="Web アプリケーションの常識">Web アプリケーションの常識<br><br> <INPUT TYPE="SUBMIT" VALUE="送信"> <INPUT TYPE="RESET"> </FORM> </BODY> </HTML> 107 ネットワークプログラミング論 平成 27 年 11 月 23 日 ④ 「KounyuServlet1.java」を次のように修正して「KounyuServlet2.java」と別名保管 してください。 <KounyuServlet2.java> package input; ・・・ public class KounyuServlet2 extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("Windows-31J"); response.setContentType("text/html;charset=Windows-31J"); PrintWriter out=response.getWriter(); out.println("<HTML>"); out.println("<HEAD><TITLE>購入商品ページ</TITLE></HEAD>"); out.println("<BODY>"); out.println("<H2>購入商品ページ</H2>"); out.println("あなたが購入した商品は以下の通りです。<br>"); out.println("<H3><コンピュータ家電機器></H3>"); String[] values1=(String[]) request.getAttribute("Shohin1"); if(values1==null) { out.println("何も購入していません。<br>"); } else { for(int i=0;i<values1.length;i++) { out.println(values1[i]+"<br>"); } } String[] values2=request.getParameterValues("Shohin2"); out.println("<H3><書籍></H3>"); if(values2==null) { out.println("何も購入していません。<br>"); } else { for(int i=0;i<values2.length;i++) { out.println(values2[i]+"<br>"); } } out.println("</BODY>" ); out.println("</HTML>" ); } } 108 ネットワークプログラミング論 平成 27 年 11 月 23 日 ⑤ 最後に「web.xml」に次のように追加し、新たに作成したサーブレットを登録してくだ さい。 <web.xml> <web-app> ・・・ <servlet> <servlet-name>KounyuServlet1</servlet-name> <servlet-class>input.KounyuServlet1</servlet-class> </servlet> <servlet> <servlet-name>KounyuServlet2</servlet-name> <servlet-class>input.KounyuServlet2</servlet-class> </servlet> ・・・ <servlet-mapping> <servlet-name>KounyuServlet1</servlet-name> <url-pattern>/KounyuServlet1</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>KounyuServlet2</servlet-name> <url-pattern>/KounyuServlet2</url-pattern> </servlet-mapping> </web-app> 作成したら、p.105 のように商品を選択して「購入商品ページ」を確認してください。う まく表示されたでしょうか・・・? 実は、表示結果は次のようになり、購入画面1で選択 した商品は表示されないはずです。 この原因はサーブレット1(KounyuServlet1.java) の(ウ)の部分 request.setAttribute("Shohin1", values1); によってリクエスト属性として保管した「購入商品1」 の情報が、サーブレット2(KounyuServlet2.java)ま で届かないことにあります。 この事情を説明しましょう。実は、リクエスト属性は 1 回のリクエストの範囲で有効で、その次に新たなリクエストがあると、内容は消えてしま います。そのため、次の図に示すように「サーブレット1」で保管したリクエスト属性は 「購入画面2」までは有効ですが、リクエスト2が発生した段階で消えてしまうのです。 109 ネットワークプログラミング論 平成 27 年 11 月 23 日 <リクエスト属性の有効範囲(スコープ)> リクエスト属性(購入商品1)は有効 forward リクエスト1 購入画面1 kounyu1.jsp サーブレット1 (購入商品1) KounyuServlet1.java 購入画面2 (購入商品1) kounyu2.jsp リクエスト2 (購入商品2) リクエスト2が発生した段階で、これ 以前のリクエスト属性は破棄される。 レスポンス ブラウザ サーブレット2 購入商品ページ KounyuServlet2.java このような有効範囲をスコープと言います。リクエストのスコープは、1 回のリクエスト の範囲です。今の場合は、複数のリクエストをまたいで有効な属性が必要になります。そ れについて次節で学習しましょう。 【基礎課題 8-2】 上の動作を確認してください。購入画面1で指定した商品の情報が残らないことを確認 したら、 「リクエスト属性を用いた場合、リクエストをまたいでデータを伝えられないこと を確認しました。 」と記述して提出してください。 8-2.セッション属性の利用 リクエストよりもスコープの広いものとして、セッションがあります。このセッション に保管したデータつまりセッション属性は、ブラウザを閉じるまで有効です。セッション はセッション ID によって管理されます。あるユーザ(クライアント)が Web アプリケー ションに接続した際に、セッション ID が割り振られます。このセッション ID はクライア ントがブラウザを閉じるまで(ユーザ認証している時にはログアウトするまで)有効なの で、その間はセッション属性が保持されるようになっています。 それでは、以下の手順にしたがって、前節のサーブレットを改良しましょう。変更点は リクエストをセッションに変更する部分のみです。 ① 「KounyuServlet1.java」を次のように修正してください。下線部が修正箇所です。 110 ネットワークプログラミング論 平成 27 年 11 月 23 日 <KounyuServlet1.java> package input; HttpSession クラスをインポートする ・・・ import javax.servlet.http.HttpSession; public class KounyuServlet1 extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("Windows-31J"); response.setContentType("text/html;charset=Windows-31J"); String[] values1=request.getParameterValues("Shohin1"); これで、セッションオブジェクトを生成する HttpSession session=request.getSession(); セッション属性への保管の仕方はリクエスト属性と同じ session.setAttribute("Shohin1", values1); request.setAttribute("Shohin1", values1); RequestDispatcher dispatcher= request.getRequestDispatcher("/input/kounyu2.jsp"); dispatcher.forward(request,response); } } ② 次に「KounyuServlet2.java」を次のように修正してください。下線部が修正箇所です。 package input; ・・・ import javax.servlet.http.HttpSession; public class KounyuServlet2 extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("Windows-31J"); ・・・ out.println("<H3><コンピュータ家電機器></H3>"); HttpSession session=request.getSession(); String[] values1=(String[]) session.getAttribute("Shohin1"); String[] values1=(String[]) request.getAttribute("Shohin1"); if(values1==null) { out.println("何も購入していません。<br>"); } ・・・ } } 111 ネットワークプログラミング論 平成 27 年 11 月 23 日 【基礎課題 8-3】 作成したら表示結果を確認して下さい。表示結果を確認したら、 「セッション属性を用い る事で、購入画面1でチェックした商品もきちんと表示されることを確認しました。 」と記 述して提出して下さい。 【基礎課題 8-4】 ブラウザを閉じるまで、セッション属性が有効であることを改めて確認してみましょう。 ① まず、 「購入画面 1」に接続します。ここで、適当に商品を選んで[送信]ボタンをク リックします。 ② この後、 「購入画面2」へ進みます。しかし、ここではまだ何も選択しませず他の Web アプリケーションに接続してみます。 ③ 例えば、 【基礎課題 6-3】で作成した JSP(input.jsp)へ接続してください。そして、 次のように氏名を入力し「送信」ボタンをクリックします。 112 ネットワークプログラミング論 平成 27 年 11 月 23 日 ④ すると、次のように表示されます。 ⑤ ここで、 [戻る]ボタンを使って、②の「購入画面2」まで戻ってください。ここで、 適当に商品(書籍)を選び[送信]ボタンをクリックします。 ⑥ すると、①で指定した商品もきちんと表示されます。 上の動作を確認したら、 「動作の途中で他の Web アプリケーションを動作させても、セッ ション属性として保管したデータが保持されることを確認しました。 」と記述して提出して 下さい。 113 ネットワークプログラミング論 平成 27 年 11 月 23 日 8-3.応用課題 【応用課題 8-A】 セッション属性を利用して次のような、訪問回数をカウントする Web アプリケーション を作成しましょう。 初めて接続した時には左のように表示され る。 以降は、ブラウザをリロード(更新)する 度に 1 回ずつ訪問回数が増えて表示され る。 このサーブレットの作成を「KounyuServlet2.java」を修正することで行いましょう。 「KounyuServlet2.java」を次ページのように修正して「SessionCounterServlet.java」と 別名保管してください。また、 「web.xml」にそのサーブレットを登録してください。 作成したら表示結果を確認して下さい。表示結果を確認したら、 「更新(リロード)する 毎に、訪問回数が増えることを確認しました。」と記述して提出して下さい。 【基礎課題 8-B】 次の実験を行ってください。 ① ブラウザを二つ起動させる(ブラウザ A、ブラウザBとする)。同種であればインター ネットエクスプローラや FireFox など何でも構いません。 ② ブラウザ A で上のサーブレットに接続して訪問回数が3となるまでリロード(更新) する。 ③ その後、もう一方のブラウザBで同じく上のサーブレットに接続する。 このとき、ブラウザBの訪問回数は何になっていますか?その解答を、使用したブラウ ザの種類と共に記述して提出してください。 114 ネットワークプログラミング論 平成 27 年 11 月 23 日 <SessionCounterServlet.java> package input; ・・・ ブラウザをリロード(更新)した時には GET リクエストが発生する ので、 (doPost()ではなく)doGet()メソッドで受けます。 public class SessionCounterServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("Windows-31J"); response.setContentType("text/html;charset=Windows-31J"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println( "<HEAD><TITLE>セッションカウンタ</TITLE></HEAD>"); out.println("<BODY>"); out.println("<H2>セッションカウンタ</H2>"); HttpSession session=request.getSession(); String NumStr=(String) session.getAttribute("Num"); int Num; //訪問回数 初めて接続するとき if(NumStr==null) { out.println("初めまして!ようこそ本ページへ"); Num=1; } 2 回目以降の接続の場合 else { Num=(int) Integer.parseInt(NumStr); Num++; out.println("あなたは"+Num+"回目の訪問ですね。"); } out.println("</BODY>"); out.println("</HTML>"); session.setAttribute("Num", String.valueOf(Num)); } データの値としては整数型や実数型などの基本型は許されない } ので、文字列型に変換している。 115
© Copyright 2024 ExpyDoc