というかJSTLにつまづき。
変なとこで躓いた。
サーバ側のアクションでは、
にして、
"21" => holiday.name
としました。ふう。
道のりは長い。
やっと万年カレンダーと休日対応が完成。
Map<String, Holiday>holidayMap = new HashMap<String, Holiday>;
と定義してたんですよ。ちなみにHolidayってのはEntityでお作法にしたがって、
@Entity @Table(name = "holidays") public class Holiday { @Id @GeneratedValue public Integer id; @Temporal(TemporalType.DATE) public Date date; public String name; }としていたのですよ。 たとえば2008年7月を表示しているのであれば、mapに "21" => holidayオブジェクト(nameは"海の日") となるわけです。で、JSPでは以下のように、
<!-- boxlen はカレンダーのセルの数です。--> <c:forEach var="n" begin="1" end="${boxlen}"> <!-- 日付--> <c:set var="day" value="${n - calendarDto.startDayOfWeek + 1}" /> : <c:if test="${holidayMap[day] != null}"> <!-- まずここが無理--> : </c:if> </c:forEach>ELを使って、マップにダイレクトアクセスしたいんだけどできない。キーは変数はあかんのか? 結局、苦し紛れにmapもforEachでまわすことにした。また次に問題発生。
<!-- boxlen はカレンダーのセルの数です。--> <c:forEach var="n" begin="1" end="${boxlen}"> <!-- 日付--> <c:set var="day" value="${n - calendarDto.startDayOfWeek + 1}" /> : <c:forEach var="hol" items="${holidayMap}"> <c:if test="${hol.key == day}"> <c:set var="holiday" value="${hol.value}" /> ${f:h(holiday.name)} <!-- ここでだめ --> </c:if> </c:forEach> </c:forEach>Holidayというentityのnameにアクセスできないと言われた。nameプロパティあるのに。 ここでかなり時間を費やしてしまった。あまり悩んでも仕方がないので、mapを
やってみようpart6(JDBCRealm)
先に書いたとおり、認証はSAStrutsのサンプルでもあるとおりJ2EEコンテナにまかせることにしました。id:higayasuoさんおすすめらしいです。
テーブルの準備
server.xmlの設定
えーっと、Tomcat前提です。
すでにserver.xmlにJDBCRealmの設定がコメントされていますのでそれ参考で。以下抜粋です。
上のテーブル構成だとこんな感じになりました。
<Realm className="org.apache.catalina.realm.JDBCRealm" connectionName="dbuser" connectionPassword="dbpass" connectionURL="jdbc:mysql://hostname/dbname" driverName="com.mysql.jdbc.Driver" roleNameCol="role" userCredCol="passwd" userNameCol="login_id" userRoleTable="roles" userTable="users" />サンプルだとドライバーのクラスが org.gjt.mm.mysql.Driver になっていますがどうなんでしょう。ぼくはjdbc.diconにあわせました。ちゃんと動いてるからこれでいいんでしょう。 追記: デフォルトで有効になっているUserDatabaseRealmはコメントアウトしましょう。(2008.6.26)
<!-- コメントアウトしましょう <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> -->
web.xmlの設定
基本的にはSAStrutsのチュートリアルのまんまです。
を一番最初に説明するのがよさそう。
●このアプリケーションで有効にするロールの定義。つまりはロールテーブルのroleカラムにはいる値そのもの。ちなみに、どうしたって
アクセス制限対象URL︵複数可︶
● アクセスが許可されるロール︵複数可︶
現段階ではまだ設定してないですが、実際には、/manage/*以下はadminロール、/schedule/*以下はadmin or userとしたいので、そのものを複数指定してやればいいことに なります。
認証方法(FORM)と認証のかかっているURLにアクセス時に遷移する画面︵
)と認証エラー時に遷移する画面(
)を指定します。チュートリアルのままです。WEB-INF以下ですが、HTMLでもよいみたいです。
<security-constraint> <web-resource-collection> <web-resource-name> Authentication </web-resource-name> <url-pattern>/schedule/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>user</role-name> <role-name>admin</role-name> </auth-constraint> </security-constraint> <security-role> <role-name>user</role-name> </security-role> <security-role> <role-name>admin</role-name> </security-role> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/WEB-INF/view/login/login.html</form-login-page> <form-error-page>/WEB-INF/view/login/loginError.html</form-error-page> </form-login-config> </login-config>です。 おおきく、 にわけることができます。
<!-- NG --> <security-role> <role-name>user</role-name> <role-name>admin</role-name> </security-role>こう書きたくなるんだけど、これはNGのようです。 ●
認証方法をBASICにしたら、そもそも認証画面とかエラー画面の指定はいらないような気がしてきた。まあいいや。
その認証画面
url | /j_security_check |
---|---|
ログインIDのname属性 | j_username |
パスワードのname属性 | j_password |
以下、抜粋。
<form method="post" action="../j_security_check"> <table class="login"> <tr> <th>ログインID</th> <td><input type="text" name="j_username" value="" size="10" /></td> </tr> <tr> <th>パスワード</th> <td><input type="password" name="j_password" value="" size="10" /></td> </tr> <tr> <td colspan="2" style="text-align:center; padding-top:15px"> <input type="submit" name="login" value="ログインする" /> </td> </tr> </table> </form>
認証成功
認証に成功したら﹁誰がログインしたのか﹂をアプリが認識する必要があります。
当たり前ですが、servlet APIに準備されてます。
@Execute(validator = false) public String index() { Principal userPrincipal = request.getUserPrincipal(); logger.debug("LoginUser is " + userPrincipal.getName()); User user = userService.getUserDto(userPrincipal.getName()); Beans.copy(user, userDto).execute(); : }って感じです。 よくよく考えるとこのweb.xmlの設定では、/schedule/ 以下だとなんでもかんでも認証がかかるわけなので、index()だけにユーザ情報取得処理をいれててもあかんのか。/schedule/hogeにアクセスされるとhoge()にいっちゃう? それこそAOPで横断的になんとかできないかな。 今日はここまで。 追記‥ http://d.hatena.ne.jp/ngtn/20080603/1212503018 こちらにも詳しく書かれています。 (2008.6.26)