第 12 章.データベースを 利 用 した Web アプリケーション 学 習 のねらい 1 Web アプリケーション 上 でデータベースを 利 用 する 方 法 を 学 習 する < 先 週 の 復 習 > 講 義 で 示 された 基 礎 課 題 12-1 に 解 答 して 下 さい 12-1.データベース 上 のデータを 表 示 する Web アプリケーション 11-2 節 では テーブル account のデータを 表 示 する Java アプリケーションを 学 習 し ました 本 節 では 同 様 の 処 理 をサーブレットから 行 う 方 法 を 学 習 します Web アプリケ ーションの 特 徴 に 起 因 する 違 いはありますが 基 本 的 な 部 分 は Java アプリケーションの 場 合 と 変 わりません 作 成 するのは 所 定 の URL に 接 続 すると 次 のように account のデータを 表 示 する Web アプリケーションです 以 下 の 手 順 にしたがって 作 成 してください 1 DBServlet.java を 第 11 章 で 作 成 したパッケージ dbsample 内 に 下 のように 新 規 作 成 してください プログラムの 内 容 は 次 ページの 通 りです 169
package dbsample; <DBServlet.java> import java.io.ioexception; import java.io.printwriter; import java.sql.connection; import java.sql.resultset; import java.sql.sqlexception; import java.sql.statement; import javax.servlet.servletexception; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; public class DBServlet extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("text/plain;charset=windows-31j"); PrintWriter out= response.getwriter(); String sql="select * from account"; Connection con=null; Statement smt=null; try { con=dbmanager.getconnection(); smt=con.createstatement(); ResultSet rs=smt.executequery(sql); while(rs.next()) { out.println("id="+rs.getint("id") +", 氏 名 ="+rs.getstring("name") +", 貯 蓄 額 ="+rs.getint("money") ); catch(sqlexception e) { throw new ServletException(e); finally { if(smt!= null) { try{smt.close(); catch(sqlexception ignore) { if(con!= null) { try{con.close(); catch(sqlexception ignore) { 170
解 説 基 本 的 には 11-2 節 で 学 習 した DBOperate.java と 同 じです 違 いは データ ベースと 接 続 するために 用 意 した Connection(コネクション)オブジェクトを ク ライアントからのリクエスト 毎 に 確 実 にクローズ( 解 放 )している 点 です その 理 由 を 簡 単 に 説 明 しましょう Java アプリケーションの 場 合 は データベースとの 接 続 は( 複 数 のデータベースを 同 時 利 用 するなどの 特 殊 な 用 途 を 除 いて) 基 本 的 に 一 つですが Web アプリケーショ ンの 場 合 サーバに 接 続 しているクライアントの 数 だけコネクション( 接 続 )が 発 生 します そのため 一 つのクライアントがコネクションを 維 持 してしまうと サーバ が 管 理 するコネクションの 数 が 増 大 し すぐに 処 理 できなくなってしまいます そこ で クライアントからのリクエストが 終 了 すると 即 座 にコネクション(およびステー トメント)をクローズして( 次 の 接 続 のために) 解 放 する という 処 理 が 必 須 になる のです その 解 放 処 理 を 確 実 に 行 うため try~catch~finally 文 を 用 いています 一 般 に try~catch~finally 文 は 次 の 形 で 記 述 します try { 例 外 (エラー)が 発 生 する 可 能 性 のある 処 理 catch ( 例 外 クラス 型 引 数 名 ) { 例 外 が 発 生 した 場 合 の 処 理 finally { 最 後 に 必 ず 実 行 する 処 理 ここに 例 外 (エラー)とはデータベース 接 続 時 のエラーや 接 続 後 に SQL 文 の 記 述 ミ スなどで 処 理 が 中 断 してしまう 場 合 を 指 します そのような 場 合 でも コネクション (データベースへの 接 続 )が 実 現 していれば finally 文 の 中 で 確 実 にクローズ( 解 放 )するようにします 最 初 は 複 雑 に 見 えるかも 知 れませんが これは Web アプリケ ーションでデータベースに 接 続 する 場 合 の 決 まり 文 句 と 思 ってください 2 サーブレットを 作 成 したので web.xml 文 で 当 該 サーブ レットを 登 録 する 必 要 があります WEB-INF フォル ダ 内 に web.xml を 新 規 作 成 ( 新 規 ファイル と 選 択 )し 次 ページのように 記 述 してください 171
<web-app> <web.xml> <servlet> <servlet-name>dbservlet</servlet-name> <servlet-class>dbsample.dbservlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>dbservlet</servlet-name> <url-pattern>/dbservlet</url-pattern> </servlet-mapping> </web-app> 作 成 したら p.169 のように 結 果 が 表 示 されることを 確 認 してください Tomcat の 起 動 を 忘 れないでください また p.153~154 で 説 明 した 通 り MySQL が Windows サービスとして 起 動 してい るか 確 認 し もし 停 止 状 態 だったら 開 始 させてください 基 礎 課 題 12-2 この Web アプリケーションの URL は 何 ですか? 空 欄 部 分 を 記 述 して 提 出 してください http://localhost:8080/ < 補 足 > web.xml をきちんと 記 述 しても 404 エラーが 出 る 場 合 Web アプリケーション DBWeb が Tomcat に 認 識 されていない 可 能 性 があります そ こで パッケージエクスプローラ 上 で DBweb を 右 ボタンクリックし Tomcat プロジ ェクト コンテキスト 定 義 を 更 新 を 選 択 してください web.xml になければ その 後 所 定 の URL に 接 続 するときちんと 表 示 されるはずです 172
12-2.サーブレットと JSP の 連 携 前 節 では テキスト 形 式 でテーブルの 内 容 (データ)を 表 示 しましたが これを 右 のように HTML の 表 の 形 式 で 表 示 す るように 改 善 しましょう これを サーブレットの 中 で HTML 形 式 の 文 書 を 記 述 して も 良 いのですが 第 7 章.サーブレット 間 の 連 携 で 学 習 した 方 法 を 用 いて 出 力 を JSP ファイルで 行 うようにしま しょう 次 の 手 順 にしたがって 作 成 してください 1 DBServlet.java を 次 ページのように 修 正 して DBServlet2.java と 別 名 保 管 してください 下 線 部 が 修 正 部 分 です(DBServlet.java の 結 果 表 示 部 分 は 削 除 さ れています) リクエスト 属 性 の forward 文 による 受 け 渡 しについては 第 7 章 で 学 習 しています ここで 新 たに 出 てきた 内 容 は 部 分 のみです これについては 下 の 解 説 を 参 照 してください 2 次 に 右 のように dbsample というフォルダを 作 成 しそ の 中 に display.jsp を 作 成 し p.175 のように 記 述 し ます これにより 結 果 が HTML 形 式 で 表 示 されます 3 web.xml に DBServlet2.java に 関 する 部 分 を p.175 のように 追 加 します 解 説 DBServlet2.java の 部 分 について 要 点 を 簡 潔 にまとめます ResultSet オ ブ ジ ェ ク ト を リ ク エ ス ト 属 性 に 保 管 し forward 文 で JSP ファイルに 転 送 する ということが p.174 の DBServlet2.java のポイントです しかし p.171 の 解 説 で 説 明 した 通 り コネクションおよびステートメントオブジェ クトは リクエストの 終 了 と 共 に つまり JSP ファイルへ 転 送 する 前 にクローズしな ければなりません ResultSet オブジェクトは コネクション+ステートメント オブジェクトがクロ ーズされると 自 動 的 にクローズされてしまいます つまり 破 棄 されてしまいます そこで ResultSet オブジェクトの 中 身 を 別 の 入 れ 物 に 移 し 替 える 必 要 が 生 じ ます その 入 れ 物 が CachedRowSetImpl クラスのオブジェクトです プログラムでは CachedRowSetImpl クラスのオブジェクト crs を 用 いて crs.populate(rs); としています これにより ResulSet オブジェクト rs の 内 容 が CachedRowSetImpl オブジェクト crs の 中 にコピーされます この crs は コネクションをクローズしても 残 りますから forward 文 により JSP ファイルに 転 送 することができます 173
package dbsample; <DBServlet2.java> import java.io.ioexception; import java.io.printwriter; import java.sql.connection; import java.sql.resultset; import java.sql.sqlexception; import java.sql.statement; import javax.servlet.requestdispatcher; import javax.servlet.servletexception; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import com.sun.rowset.cachedrowsetimpl; public class DBServlet2 extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("text/plain;charset=windows-31j"); PrintWriter out= response.getwriter(); String sql="select * from account"; Connection con=null; Statement smt=null; try { con=dbmanager.getconnection(); smt=con.createstatement(); ResultSet rs=smt.executequery(sql); CachedRowSetImpl crs=new CachedRowSetImpl(); crs.populate(rs); request.setattribute("crs",crs); catch(sqlexception e) { throw new ServletException(e); finally { if(smt!= null) { try{smt.close(); catch(sqlexception ignore) { if(con!= null) { try{con.close(); catch(sqlexception ignore) { RequestDispatcher dispatcher =request.getrequestdispatcher("/dbsample/display.jsp"); dispatcher.forward(request,response); 174
<display.jsp> <%@page contenttype="text/html; charset=windows-31j"%> <%@page import="java.sql.resultset" %> <HTML> <BODY> <TABLE BORDER="1"> リ ク エ ス ト 属 性 に 保 管 し た <TR> ( CachedRowSetImpl ) オ ブ ジ ェ ク ト を <TH>ID<TH> 氏 名 <TH> 貯 蓄 金 額 ResultSet オブジェクトして 受 け 取 る <% ResultSet rs=(resultset) request.getattribute("crs"); while(rs.next()) { %> <TR> <TD><%=rs.getInt("ID") %> <TD><%=rs.getString("Name") %> <TD><%=rs.getInt("Money") %> <% %> </TABLE> </BODY> </HTML> <web-app> <web.xml> <servlet> <servlet-name>dbservlet</servlet-name> <servlet-class>dbsample.dbservlet</servlet-class> </servlet> <servlet> <servlet-name>dbservlet2</servlet-name> <servlet-class>dbsample.dbservlet2</servlet-class> </servlet> <servlet-mapping> <servlet-name>dbservlet</servlet-name> <url-pattern>/dbservlet</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>dbservlet2</servlet-name> <url-pattern>/dbservlet2</url-pattern> </servlet-mapping> 追 加 部 分 </web-app> 175
基 礎 課 題 12-3 p.173 のように 結 果 が 表 示 されることを 確 認 したら ResultSet オブジェクトを CachedRowSetImpl オブジェクトに 詰 め 替 えることにより サーブレットから JSP へ ResulSet オブジェクトの 中 身 を 転 送 することができました と 記 述 して 提 出 してくださ い 12-3.データベースへのデータの 追 加 検 索 および 更 新 前 節 までのプログラムを 利 用 すれば データベースの 検 索 や 更 新 等 の 操 作 は 容 易 に 行 え ます 以 下 順 にデータの 追 加 検 索 更 新 を 行 ってみましょう 基 礎 課 題 12-4 データの 追 加 以 下 のように 新 たに 口 座 を 開 設 するページを 作 成 しましょう 所 定 の URL に 接 続 し 氏 名 と 振 り 込 み 金 額 を 入 力 して[ 送 信 ]ボタンをクリックすると 新 たに 口 座 が 開 設 ( 追 加 )され 全 データが 表 示 される 追 加 されたデータ 次 の 手 順 にしたがって 作 成 してください 1 DBServlet2.java を 修 正 して 次 ページの 様 に 記 述 し DBServletOpen.java と 別 名 保 管 してください 下 線 部 が 修 正 部 分 です また 氏 名 と 金 額 は JSP ファイルか ら 受 け 取 ることにしています 2 氏 名 と 金 額 の 入 力 画 面 を 用 意 し それらを 上 のサーブレット DBServletOpen.java に 受 け 渡 す JSP ファイル open.jsp を p.178 のように 記 述 してください 作 成 する 場 所 はフォルダ dbsample の 中 です p.178 の 図 を 確 認 してください 176
package dbsample; <DBServletOpen.java> import java.io.ioexception; 以 下 import 文 変 更 なし public class DBServletOpen extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("text/plain;charset=windows-31j"); request.setcharacterencoding("windows-31j"); PrintWriter out= response.getwriter(); int ID=0; String Shimei=request.getParameter("Shimei"); int Kingaku= Integer.parseInt(request.getParameter("Kingaku")); String sql="select * from account"; Connection con=null; Statement smt=null; try { con=dbmanager.getconnection(); smt=con.createstatement(); ResultSet rs=smt.executequery(sql); while(rs.next()) { データ 挿 入 のため insert into account ID=rs.getInt("ID"); values(id の 値, 氏 名, 金 額 ) という SQL ID=ID+1; 文 を 発 行 String sql2="insert into account values("+id +",'"+Shimei+"',"+Kingaku+")"; smt.executeupdate(sql2); rs=smt.executequery(sql); CachedRowSetImpl crs=new CachedRowSetImpl(); crs.populate(rs); request.setattribute("crs",crs); catch(sqlexception e) { throw new ServletException(e); finally { RequestDispatcher dispatcher =request.getrequestdispatcher("/dbsample/display.jsp"); dispatcher.forward(request,response); 177
open.jsp の 作 成 場 所 は 次 の 通 りです 現 時 点 でパッケー ジエクスプローラを 見 ると 右 のようになっているはず です 3 最 後 に web.xml を 下 のように 記 述 し 新 たに 作 成 した サーブレットを 登 録 します 作 成 したら JSP open.jsp ( 下 の URL)に 接 続 して p.176 のように 動 作 を 確 認 してください http://localhost:8080/dbweb/dbsample/open.jsp 新 しい 口 座 を 追 加 できたら 新 たに 口 座 をデータベースに 追 加 し 表 示 する 事 ができました 記 述 して 提 出 してくだ さい <open.jsp> <%@page contenttype="text/html; charset=windows-31j"%> <HTML> <BODY> <H2> 口 座 開 設 </H2> 氏 名 と 金 額 を 入 力 して 下 さい <BR> <FORM ACTION="../DBServletOpen"> 氏 名 <INPUT TYPE="TEXT" NAME="Shimei"> 金 額 <INPUT TYPE="TEXT" NAME="Kingaku"> <INPUT TYPE="SUBMIT" VALUE=" 送 信 "> </FORM> </BODY> </HTML> <web-app> <web.xml> 追 加 部 分 のみ 記 述 しています <servlet> <servlet-name>dbservletopen</servlet-name> <servlet-class>dbsample.dbservletopen</servlet-class> </servlet> <servlet-mapping> <servlet-name>dbservletopen</servlet-name> <url-pattern>/dbservletopen</url-pattern> </servlet-mapping> </web-app> 178
基 礎 課 題 12-5 データの 検 索 今 度 は 指 定 した ID( 口 座 番 号 )の 氏 名 と 貯 蓄 金 額 を 表 示 するページを 作 成 しましょう ID を 入 力 して[ 送 信 ]ボタンをクリック すると 指 定 した ID の 氏 名 と 貯 蓄 金 額 を 表 示 する 以 下 の 手 順 にしたがって 作 成 してください 1 DBServletOpen.java を 次 ページのように 修 正 して DBServletSelect.java と 別 名 保 管 してください 下 線 部 が 修 正 箇 所 です 2 次 に ID の 入 力 画 面 を 用 意 しその 値 をサーブレットに 受 け 渡 す JSP ファイル select.jsp を p.181 のように 記 述 してください 作 成 場 所 は open.jsp と 同 じくフ ォルダ dbsample の 中 です 3 最 後 に web.xml に p.181 のように 新 たに 作 成 したサーブレット DBServletSelect.java 登 録 部 分 を 追 加 します 作 成 したら 指 定 した ID の 口 座 が 表 示 されるかどうかを 確 認 してください 確 認 できた ら 指 定 した ID の 氏 名 と 金 額 を 表 示 させることを 確 認 しました と 記 述 して 提 出 してく ださい 179
package dbsample; <DBServletSelect.java> import java.io.ioexception; import 文 は 変 更 なし public class DBServletSelect extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("text/plain;charset=windows-31j"); request.setcharacterencoding("windows-31j"); PrintWriter out= response.getwriter(); int ID=Integer.parseInt(request.getParameter("ID")); String sql="select * from account"; Connection con=null; Statement smt=null; try { con=dbmanager.getconnection(); smt=con.createstatement(); ResultSet rs; sql="select * from account where ID="+ID; rs=smt.executequery(sql); CachedRowSetImpl crs=new CachedRowSetImpl(); crs.populate(rs); request.setattribute("crs",crs); catch(sqlexception e) { throw new ServletException(e); finally { 変 更 なし RequestDispatcher dispatcher =request.getrequestdispatcher("/dbsample/display.jsp"); dispatcher.forward(request,response); 180
<select.jsp> <%@page contenttype="text/html; charset=windows-31j"%> <HTML> <BODY> <H2> 口 座 確 認 </H2> ID( 口 座 番 号 )を 入 力 して 下 さい <BR> <FORM ACTION="../DBServletSelect"> ID<INPUT TYPE="TEXT" NAME="ID"> <INPUT TYPE="SUBMIT" VALUE=" 送 信 "> </FORM> </BODY> </HTML> <web-app> 追 加 部 分 のみ 記 述 しています <servlet> <servlet-name>dbservletselect</servlet-name> <servlet-class>dbsample.dbservletselect</servlet-class> </servlet> <servlet-mapping> <servlet-name>dbservletselect</servlet-name> <url-pattern>/dbservletselect</url-pattern> </servlet-mapping> </web-app> <web.xml> 181
基 礎 課 題 12-6 データの 更 新 最 後 に 次 のように 口 座 への 入 金 あるいは 引 き 出 しを 行 えるページを 作 成 しましょう 次 の 画 面 で 例 えば 入 金 と 選 択 し ID と 金 額 を 入 力 して[ 送 信 ]ボタンをクリックす ると 指 定 した 口 座 に 所 定 の 料 金 が 入 金 されて 表 示 される 次 の 手 順 にしたがって このページを 作 成 してください 1 DBServletSelect.java を 次 ページの 様 に 修 正 し DBServletUpdate.java と 別 名 保 管 し てください 下 線 部 と 点 線 枠 部 分 が 修 正 箇 所 です 2 select.jsp を p.184 のように 修 正 し update.jsp と 別 名 保 管 してください 3 最 後 に web.xml に p.184 の よ う に 新 た に 作 成 し た サ ー ブ レ ッ ト DBServletUpdate.java 登 録 部 分 を 追 加 します 作 成 したら 上 の 様 に 動 作 を 確 認 してください 確 認 できたら 指 定 した 口 座 (ID)に 入 金 (あるいは 引 き 出 し)を 行 えることを 確 認 しました と 記 述 して 提 出 してください 182
package dbsample; import java.io.ioexception; public class DBServletUpdate extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("text/plain;charset=windows-31j"); request.setcharacterencoding("windows-31j"); PrintWriter out= response.getwriter(); String InOut=request.getParameter("InOut"); int ID=Integer.parseInt(request.getParameter("ID")); int Kingaku= Integer.parseInt(request.getParameter("Kingaku")); String sql="select * from account where ID="+ID; Connection con=null; Statement smt=null; try { con=dbmanager.getconnection(); smt=con.createstatement(); ResultSet rs=smt.executequery(sql); rs.next(); if(inout.equals("nyukin")) { Kingaku=rs.getInt("Money")+Kingaku; else { Kingaku=rs.getInt("Money")-Kingaku; String sql2= "update account set Money="+Kingaku+" where ID="+ID; smt.executeupdate(sql2); sql="select * from account where ID="+ID; catch(sqlexception e) { throw new ServletException(e); finally { RequestDispatcher dispatcher =( 以 下 変 更 なし) 183
<%@page contenttype="text/html; charset=windows-31j"%> <HTML> <update.jsp> <BODY> <H2> 入 金 引 き 出 し</H2> 入 金 あるいは 引 き 出 しのいずれかを 選 択 し ID( 口 座 番 号 )と 金 額 を 入 力 して 下 さい <BR> <FORM ACTION="../DBServletUpdate"> <INPUT TYPE="RADIO" NAME="InOut" VALUE="Nyukin"> 入 金 <INPUT TYPE="RADIO" NAME="InOut" VALUE="HikiDashi"> 引 き 出 し <BR> ID<INPUT TYPE="TEXT" NAME="ID"> 金 額 <INPUT TYPE="TEXT" NAME="Kingaku"> <INPUT TYPE="SUBMIT" VALUE=" 送 信 "> </FORM> </BODY> </HTML> <web-app> <web.xml> 追 加 部 分 のみ 記 述 しています <servlet> <servlet-name>dbservletupdate</servlet-name> <servlet-class>dbsample.dbservletupdate</servlet-class> </servlet> <servlet-mapping> <servlet-name>dbservletupdate</servlet-name> <url-pattern>/dbservletupdate</url-pattern> </servlet-mapping> </web-app> 184