Strutsでwebアプリケーション初期化
webアプリケーションが起動するとき自動的に一回だけ実行されるあらかじめユーザーリストを表示させたい時など、DBから読み込んで
アプリケーションスコープなどに入れておくなどの使い方がある。
ソース → http://d.hatena.ne.jp/wani2000/20041205#p2(1)PlugInを実装するクラス Initを作成
(2)initをオーバーライドして、
(3)初期化で入れておきたい情報をスコープに入れる
(4)タグでstruts-config.xmlに登録する
Strutsでwebアプリケーション初期化 ソース Init.java
package jp.co.exercise.;import javax.servlet.ServletContext;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;public class Init implements PlugIn{
public void init( ActionServlet servlet, ModuleConfig config){
ServletContext application = servlet.getServletContext();
application.setAttribute("list", new ArticleList());
}
public void destroy(){}
}
スコープのまとめ
http://www.fk.urban.ne.jp/home/kishida/kouza/kishou/jsp05.htmlHttpServletRequest requestでリクエストを得る
・リクエストスコープに格納
HttpServletRequest request = request.get
request.setAttribute("userid", userid);//requestオブジェクトを、forwardメソッドで、次のリクエスト先に引継ぎ
RequestDispatcher rd = request.getRequestDispatcher("./xxx");
rd.forward(request, res);
・セッションスコープに格納
HttpSession session = request.getSession();
session.setAttribute("userid", userid);
・アプリケーションスコープに格納
ServletContext sc = getServletContext( );
sc.setAttribute("userid", userid);
struts-config.xml
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"> <struts-config> <!-- フォームBeanの登録 --> <form-beans> <form-bean name="registForm" type="sec2.exercise.RegistForm" /> <form-bean name="userRegistForm" type="sec5.example.UserRegistForm" /> </form-beans> <!-- アクションクラスの登録 --> <action-mappings> <action path="/regist" type="sec2.exercise.RegistAction" name="registForm"> <!-- name属性に関連するフォームBeanを入れる --> <forward name="success" path="/jsp/registFinish.jsp" /> <forward name="error" path="/jsp/registError.jsp" /> </action> <!-- validate()メソッドを利用した場合 --> <action path="/userRegist" type="sec5.example.UserRegistAction" name="userRegistForm" input="/jsp/userRegistForm.jsp" <!-- validatorでエラーした場合の遷移先 --> validate="true"> <!-- validatorを有効にする --> <forward name="success" path="/jsp/registFinish.jsp" /> </action> <!-- JSPからのリンク用 --> <action path="/exercise4_1" type="sec4.exercise.Exercise4_1"> <forward name="success" path="/jsp/exercise4_1.jsp" /> </action> </action-mappings> <message-resources parameter="resources.application"/> <!-- validatorプラグインの追加 --> <plug-in className="org.apache.struts.validator.ValidatorPlugIn"> <set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/> </plug-in> <!-- webアプリケーション初期化plug-inの追加 --> <plug-in className="sec7.exercise.Init" /> </struts-config>
コネクションプーリング
コネクションプーリングとはDBとの接続をいくつかはりっぱなしにしておいて、
そのひとつを利用してDB接続をすることで、接続の時間を短縮する
接続が早いアプリケーションがDBを閲覧するには
接続 → SQL送信 → レスポンス → 切断いちいち接続から行わないということ
http://interstage.fujitsu.com/jp/technical/sample/sam000005_02.html
validatorを使った妥当性のチェック
・良くある入力チェックはvalidatorを利用して実装する(1)フォームBeanでValidatorFormクラスを継承
(ValidatorFormはActionFormクラスのサブクラスなのでActionFormは継承しなくて良い)(2)エラーメッセージの登録 application.properties
参照 → http://d.hatena.ne.jp/wani2000/20041205#p8
(3)validation.xmlを作成する。
このファイルで、どのような検証を行うか設定する。
ファイル名は何でもいい
参照 → http://d.hatena.ne.jp/wani2000/20041205#p7
検証ルール 参照 → http://d.hatena.ne.jp/wani2000/20041205#p9(4)エラーメッセージを表示できるようにjspファイルを修正
・エラーをすべて表示
・name属性のエラーだけ表示
・javascriptでのチェックも行うことができる
(1)javascriptを利用することを宣言。フォームBean名を入れる
(2)フォームの送信先を指定。「return validateフォームBean名(this)とする」
(5)
タグでstruts-config.xmlに登録する
参照 → http://d.hatena.ne.jp/wani2000/20041205#p4
validation.xml
<?xml version="1.0" encoding="Shift_JIS" ?> <!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN" "http://jakarta.apache.org/commons/dtds/validator_1_0.dtd"> <form-validation> <formset> <form name="postForm"> <field property="name" depends="required"> <!-- 検証ルールの種類。複数の場合カンマで区切る --> <msg name="required" key="errors.text"/> <!-- 検証ルールの種類。エラーの際のメッセージのリソースファイルを指定 --> <arg0 key="名前" resource="false"/> <!-- メッセージリソースファイルに埋め込む内容 --> <arg1 key="1文字以上" resource="false"/> </field> <field property="body" depends="required"> <msg name="required" key="errors.text"/> <arg0 key="内容" resource="false"/> </field> </form> </formset> </form-validation>
application.properties
errors.header=<ul><font color="red"> errors.footer=</font></ul> errors.prefix=<li> errors.suffix=</li> errors.text={0}が入力されていません errors.age={0}が不正な値が入力されました errors.range={0}文字以上、{1}文字以内で入力してください
validatorの検証ルール
validation.xmlのdepends属性に入れることができる値 <field property="name" depends="required"> 参考 → http://struts.apache.org/userGuide/dev_validator.html required 未入力チェック byte byte型の範囲の数字かどうかチェック short short型の範囲の数字かどうかチェック integer int型の範囲の数字かどうかチェック float float型の範囲の数字かどうかチェック double double型の範囲の数字かどうかチェック date 日付の書式かチェック email メールアドレスの形式かチェック maxlength 文字列の長さをチェック 最大値 <var> <var-name>maxlength</var-name> <var-value>30</var-value> </var> minlength 文字列の長さをチェック 最小値 mask 指定した正規表現にマッチしているかチェック <var> <var-name>mask</var-name> <var-value>^[a-zA-Z]*$</var-value> </var> intRange 整数型として指定された範囲かをチェック <field property="age" depends="required,integer,intRange"> <arg0 key="employee.age"/> <arg1 name="intRange" key="${var:min}" resource="false"/> <arg2 name="intRange" key="${var:max}" resource="false"/> <var><var-name>min</var-name><var-value>18</var-value></var> <var><var-name>max</var-name><var-value>65</var-value></var> </field>
validate()メソッドを使った妥当性のチェック
(1)エラーメッセージの登録 application.properties
参照 → http://d.hatena.ne.jp/wani2000/20041205#p8(2)struts-config.xmlに設定を追加
アクションクラスの設定の記述で
input属性 validate属性を追加する
input="/jsp/userRegistForm.jsp" validatorでエラーした場合の遷移先
validate="true" validatorを有効にする
(3)フォームBeanに検証用メソッド validate() メソッドを定義する
参照 → http://d.hatena.ne.jp/wani2000/20041205#p11(4)エラーメッセージを表示できるようにjspファイルを修正
・エラーをすべて表示
・name属性のエラーだけ表示
フォームBean
import java.io.UnsupportedEncodingException; import javax.servlet.http.HttpServletRequest; import org.apache.struts.action.ActionError; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; public class UserRegistForm extends ActionForm { private String name; private String password; private String mailaddress; private int age; //文字化け対策 参照 → http://www.atmarkit.co.jp/fjava/onepoint/svltjsp/svltjsp12.html public void reset(ActionMapping mapping, HttpServletRequest request) { try { request.setCharacterEncoding("JISAutoDetect"); } catch (UnsupportedEncodingException ex) { ex.printStackTrace(); } } public int getAge() { return age; } public String getMailaddress() { return mailaddress; } public String getName() { return name; } public String getPassword() { return password; } public void setAge(int i) { age = i; } public void setMailaddress(String string) { mailaddress = string; } public void setName(String string) { name = string; } public void setPassword(String string) { password = string; } public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = new ActionErrors(); if ((name == null) || name.equals("")) { errors.add("name", new ActionError("errors.text", "名前")); } if ((password == null) || password.equals("")) { errors.add("password", new ActionError("errors.text", "パスワード")); } if (password.length() < 5 || password.length() > 10){ errors.add("password2", new ActionError("errors.password", "パスワード")); } if ((mailaddress == null) || mailaddress.equals("")) { errors.add("mailaddress", new ActionError("errors.text", "メールアドレス")); } if ((age < 0) || (age > 120)) { errors.add("age", new ActionError("errors.num", "年齢")); } return errors; } }
アクションクラス
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; public class UserRegistAction extends Action{ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { //フォームBean型でキャスト UserRegistForm registForm = (UserRegistForm)form; //処理 //たとえばログイン成功かどうかなど。 //それによってページ遷移を作る。 //"success"はstruts-config.xmlに渡され、struts-config.xmlで遷移先のページを指定する if(){ return mapping.findForward("success"); }else{ return mapping.findForward("error"); } } }
JSPファイル
<%@ page contentType="text/html; charset=Windows-31J" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %> <!-- html開始 --> <html:html> <head> <!-- ブラウザのURLではなく、JSPファイルの実際のパスをベースにして相対パスを解釈してくれる --> <html:base /> <title>JavaBoostScheduler -ログイン画面-</title> <link rel="stylesheet" href="base.css" type="text/css"> </head> <body bgcolor="#FFFFFF" text="#000000" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0"> <!-- formタグ --> <html:form action="/login"> <!-- validatorのエラー表示 --> <html:errors property="loginerror"/> <table width="400" border="0" cellspacing="0" cellpadding="5"> <tr> <td bgcolor="#F6F6F6"> <br /> <table width="100%" border="0" cellspacing="0" cellpadding="2"> <tr valign="top"> <td width="120">■ユーザ名<font color="#990000">(*)</font></td> <td > <!-- セレクトボックスで選択 --> <html:select property="id"> <html:options collection="nameList" property="value" labelProperty="key" /> </html:select> </td> </tr> <tr valign="top"> <td width="120">■パスワード</td> <td> <!-- text形式 --> <html:password property="password" size="30"/> </td> </tr> </table> </td> </tr> <tr> <td class="moko" bgcolor="EEEEEE"> <table width="100%" border="0" cellspacing="0" cellpadding="2"> <tr> <td> <!-- submitボタン --> <html:submit value="ログイン"/> </td> </tr> </table> </td> </tr> </table> </html:form> <br /> <!-- リンク --> <html:link action="/toRegistUser">新規ユーザ登録はこちら</html:link> </body> </html:html>
DAOTemplate
import java.sql.*; import javax.naming.InitialContext; import javax.sql.DataSource; /** * Data Access Objectの共通機能を実装したクラス * @author ITBoost */ public class DAOTemplate { /** * <pre>DAOで管理するデータベースのデータソース名を返す * ※サブクラスでオーバーライドする※</pre> * @return データソース名 */ public String getDataSourceName() { return "dummy"; } /** * データベースに接続する * @return Conncetionオブジェクト */ public Connection createConnection() throws SQLException { Connection con = null; try { // 初期コンテキストを取得 InitialContext ic = new InitialContext(); // ルックアップしてデータソースを取得 DataSource ds = (DataSource) ic.lookup("java:comp/env/" + getDataSourceName()); con = ds.getConnection(); } catch (Exception e) { // テスト用のデータベース情報 try { Class.forName("org.postgresql.Driver"); // 初期コンテキストを取得 con = DriverManager.getConnection( "jdbc:postgresql://sv:5432/strutsdev", "postgres", ""); } catch (Exception ex) { ex.printStackTrace(); } } return con; } /** * データベースから切断する * @param con Conncetionオブジェクト */ protected void closeConnection(Connection con) { try { if (con != null) con.close(); con = null; } catch (SQLException ex) { ; } } /** * <pre>次のIDを獲得する * ※トランザクションの中で呼び出すこと※</pre> * @param con Conncetionオブジェクト * @param tableName テーブル名 * @return 次のID */ protected synchronized int getNextId(Connection con, String tableName) throws SQLException { Statement stmt = con.createStatement(); stmt.execute("LOCK TABLE " + tableName); ResultSet rs = stmt.executeQuery("select max(id)+1 as next_id from " + tableName); rs.next(); return rs.getInt("next_id"); } /** * <pre>SQL式をエスケープする。 * PostgreSQLを想定。DBMSによってエスケープすべき文字は異なるので注意が必要。</pre> * @param aStr エスケープしたいSQL式 * @return エスケープ済みの文字列 */ public static String escapeSQL(String aStr) { char c; if (aStr == null) return null; StringBuffer returnStr = new StringBuffer(); int length = aStr.length(); for (int i = 0; i < length; i++) { c = aStr.charAt(i); if (c == '\'') { returnStr = returnStr.append("''"); } else if (c == '\\') { returnStr = returnStr.append("\\\\"); } else if (c == '"') { returnStr = returnStr.append("\\\""); } else if (c == ';') { returnStr = returnStr.append("\\;"); } else { returnStr = returnStr.append(c); } } return new String(returnStr); } }
DAO
import jp.co.itboost.scheduler.common.DAOTemplate; import java.sql.*; import java.util.LinkedHashMap; /** * User用DAOクラス * @author ITBoost */ public class UserDAO extends DAOTemplate { /** * テーブル名 */ private final static String USER_TABLE_NAME = "schedule_user"; /** * DAOで管理するデータベースのデータソース名を返す * @return データソース名 */ public String getDataSourceName() { return "jdbc/strutsdev"; } /** * 指定されたsqlを元にUserオブジェクトを生成する * @param sql 任意のSQL * @return Userオブジェクト */ private User getUser(String sql) { Connection con = null; try { con = createConnection(); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(sql); if (!rs.next()) return null; User user = new User(); user.setId(rs.getInt("id")); user.setName(rs.getString("name")); user.setPassword(rs.getString("password")); user.setMailAddress(rs.getString("mailaddress")); return user; } catch (SQLException ex) { System.out.println("in UserDAO:SQLException! sql=" + sql); ex.printStackTrace(); } finally { closeConnection(con); } return null; } /** * ユーザ情報をデータベースからロードする * @param id ユーザID * @return Userオブジェクト */ public User load(int id) { String sql = "select id, name,password,mailaddress from " + USER_TABLE_NAME + " where id=" + id; return getUser(sql); } /** * ユーザ情報をデータベースに新規保存する * @param user Userオブジェクト */ public void create(User user) { String sql = "insert into " + USER_TABLE_NAME + " (id, name,password,mailaddress) values(?,?,?,?)"; Connection con = null; try { con = createConnection(); con.setAutoCommit(false); int id = getNextId(con, USER_TABLE_NAME); PreparedStatement stmt = con.prepareStatement(sql); stmt.setInt(1, id); stmt.setString(2, user.getName()); stmt.setString(3, user.getPassword()); stmt.setString(4, user.getMailAddress()); stmt.executeUpdate(); con.commit(); } catch (SQLException ex) { System.out.println("in UserDAO:SQLException! sql=" + sql); ex.printStackTrace(); } finally { closeConnection(con); } } /** * データベースのユーザ情報を更新する * @param user Userオブジェクト */ public void store(User user) { String sql = "update " + USER_TABLE_NAME + " set name=?, password=? ,mailaddress=? where id=?"; Connection con = null; try { con = createConnection(); int id = user.getId(); PreparedStatement stmt = con.prepareStatement(sql); stmt.setString(1, user.getName()); stmt.setString(2, user.getPassword()); stmt.setString(3, user.getMailAddress()); stmt.setInt(4, id); stmt.executeUpdate(); } catch (SQLException ex) { System.out.println("in UserDAO:SQLException! sql=" + sql); ex.printStackTrace(); } finally { closeConnection(con); } } /** * ユーザIDとパスワードを指定して合致するユーザ情報を取り出す * @param id ユーザID * @param password パスワード * @return Userオブジェクト */ public User findByIdAndPassword(int id, String password) { String sql = "select id,name,password,mailaddress from " + USER_TABLE_NAME + " where id="+id+" and password='"+escapeSQL(password)+"'"; return getUser(sql); } /** * ユーザIDと名前の一覧を取り出す * @return keyに名前, valueにユーザIDが入ったLinkedHashMapオブジェクト */ public LinkedHashMap findAllIdAndName() { String sql = "select id, name from "+USER_TABLE_NAME+" order by id"; Connection con = null; LinkedHashMap ret = new LinkedHashMap(); try { con = createConnection(); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(sql); while(rs.next()) { ret.put(rs.getString("name"), new Integer(rs.getInt("id"))); } } catch (SQLException ex) { System.out.println("in UserDAO:SQLException! sql=" + sql); ex.printStackTrace(); } finally { closeConnection(con); } return ret; } }