カレントパスを気にせずにjspにcssファイル等のパスを指定する方法

同じjspを使う場合であってもurlが/employeeと/employee/indexなどとカレントパスが異なる場合があるので、jsp内でcssファイルなどを相対パスでベタ書きした場合には、どちら一方は正しくないパスとなってしまいます。

なにかSAStruts側で用意されていないか調べてみたらありました。

aタグのhref要素などを設定するときに、コンテキストルートを自動的に補完させる場合は、 f:url()を使います。パスを/ではじめた場合は、コンテキストルートからみたパスになります。パスが/ではじまっていない場合は、JSPからみたパスになります。

こんな感じで書けます。

<link rel="stylesheet" type="text/css" href="${f:url("/css/hoge.css")}">

パスを/ではじめるのがミソですね。

これを知らなかったら、

<link rel="stylesheet" type="text/css" href="<%= request.getContextPath() %>/css/hoge.css">

といった感じの記述をたくさん書いてしまうところでした。

結果は同じですが、前者の方が断然シンプルですね。

global-exceptionsでキャッチできるのはRuntimeExceptionのサブクラスのみ?

Exceptionのサブクラスをstruts-config.xmlのglobal-exceptionsに定義していもキャッチできず、RuntimeExceptionのサブクラスであればキャッチできました。

これって生Strutsの仕様だったかなぁ?

S2Strutsを使っていた時にはExeptionのサブクラスでもキャッチできてたんですが。。

インターセプター内でもJdbcManagerがインジェクションされる


Action用のインターセプター内でDB接続したかったので色々試していたら、Actionと同様にJdbcManagerをpublicフィールドで定義しておけば自動的にインジェクションされた!

public class HogeInterceptor extends AbstractInterceptor {

    public JdbcManager jdbcManager;

    public Object invoke(final MethodInvocation invocation) throws Throwable {
            // ここでjdbcManagerを使ってDB接続できる
            return invocation.proceed();
    }
}

最初、SingletonS2Container.getComponent(JdbcManager.class)で取得しようとしたらExceptionが発生したので、なんとなくActionのようにpublicフィールドにセットしてみたら、ちゃんと使えました。

SAStrutsのマニュアルには特に書いていないようだけど、これはSmartDeployの為せるワザなのかな?

Seasar2.4は初めてなので、こっちのマニュアルももっと読まないと、ですね。

JDBCレルム認証で権限管理

『Executeアノテーションでつけられるroles属性によって、ユーザのロールによってアクセス制御をかけることができる』ということは、
マニュアルを見れば一目瞭然なのですが、DBを使ってユーザー認証をした後にロールをどうやってセットすればよいのかが分かりませんでした。


調べた結果、自分でセットできるものではなく、サーブレットコンテナに任せた認証を使う必要があるとのこと。


しかし、今までのアプリの認証は全て自前でカスタムしたものばかりで、

サーブレットコンテナの認証って何?」
という状態だったので、チュートリアルの設定をみたり、ブログをあさってみたりと手探り状態で、
答えにたどり着くまでに随分時間がかかってしまいました。 orz


JDBCレルムを使った認証というのがあるんですね。全く知りませんでした。
[参照]http://www.jajakarta.org/tomcat/tomcat5.0/ja/docs/tomcat-docs/realm-howto.html


自分のようにその存在を知らない方のために、取っ掛かりにでもなればと思い、やった手順をざっくりですがメモしておきます。

      1. まずテーブルは「ユーザー表」「ユーザーロール表」の2つが必要です。「ユーザー表」にはログイン名とパスワード用の列、「ユーザーロール表」にはログイン名とロール名用の列が必要です。
      2. TOMCAT_HOME/conf/server.xmlJDBCレルムの設定を記述します。コメントアウトをはずし、データベースの情報、JDBCドライバ、認証に使うテーブルの情報などを設定します。デフォルトで有効となっていたの設定はコメントアウトします。
      3. TOMCAT_HOME/common/libにJDBCドライバのjarファイルを入れます。
      4. 続いてログイン画面とログインエラー時の画面を用意します。ログイン画面のformのactionは"j_security_check"、ログイン名・パスワードのinputタグのname属性はそれぞれ"j_username"、"j_password"とする必要があります。
      5. あとはweb.xmlに認証が必要なURLのパターンやログイン画面の場所などを設定するのですが、これはSAStrutsチュートリアルのweb.xmlを見たら分かると思います。タグやタグの設定です。


1〜3の話は上記のTomcatのページを見れば詳しく載っています。4、5もググれば参考になる情報はたくさんあります。


欲を言えば、この辺の認証まわりの話はマニュアルにもうちょっと書くか、参考URLへのリンクを貼っておいてもらいたかったなぁ(八つ当たり)。

常識過ぎて必要ないんですかね。

SAStrutsことはじめ

次のJAVA案件をSAStrutsS2JDBCでいってみようかと現在調査中。

Seasar2の経験はSeasar2.3+S2Struts(設定ファイル有)+S2Daoの構成で数回あります。


過去の資産があるので、わざわざSAStrutsを使う必要も無いかと思ったのですが、
ここのところずっとPHPでのお仕事が続いていたので、

      • アクションを追加する度にお決まりの設定を設定ファイルに追加
      • 修正の度にTomcatの再起動

などの煩わしさに耐えられず、SAStrutsの方が断然魅力的に見えてきました。


本家のマニュアルを見ながらセットアップしたら、すんなりチュートリアルを動かすことができました。

まずはマニュアルとチュートリアルのソースをじっくり読みながら、認証・権限管理まわりの処理を調査してみようと思います。

CakePHP善戦、しかし圧勝したのは...

何の話かというと、先日行われていた次のアンケート。自分としては意外(?)な結果が。

PHPプログラマーの方でPHP用フレームワークを使っている方へアン… - 人力検索はてな

「現在使っている」「自分がフレームワークを選ぶ場合」の両方でpradoが圧倒的に票を獲得していて、次いでCakePHPが2位でした。

個人的にはPHPフレームワークの現在の人気はSymfonyCakePHPかと思っていたので、この結果は意外でした。

モデルの指定列からselectタグを作るのに便利な方法

1.1系ではModel::generateList()メソッドを使えば、モデルから指定した列のkeyとvalueがペアとなった配列が取得でき、selectタグを作るのに便利でした。


1.2系ではそのgenerateList()は非推奨メソッドとなり、
「1.2系ではgenerateList()の代わりにModel::find('list')を使う」
という情報は色々なところで見つかったのですが、keyとvalueに使われる列を自分で指定する方法が分からなかったので調べてみました。


今回分かったのは2通りのやり方です。(Beta 1.2.0.6311で確認)

方法1:displayFieldプロパティを設定して、Model::find('list')を呼ぶ方法

こちらの方法はkeyに使われる列はモデルの主キー(通常であれば'id')固定になります。

モデルのdisplayFieldプロパティでvalueにセットしたい列の指定ができます。

displayFieldプロパティに指定列をセットした後で、find('list')を呼べば配列のvalueには指定した列の値がセットされます。

<?php
    // Mailモデルのsubjectをvalueに設定する例
    $this->Mail->displayField = 'subject';
    $mails = $this->Mail->find('list');

    // ビューでselectタグを作るためにset
    $this->set('mails', $mails);
 ?>


ちなみにdisplayFieldをセットしない場合は、そのモデルが'title'もしくは'name'という名前の列を持っていればその列('title'を優先)を、もっていなければ主キー列がvalueにセットされます。

方法2:Set::Combineを使う方法

こちらの方法はkeyとvalueの両方が指定できます。

Model::find('all')で取得したモデルの一覧データをSet::Combine($data, $keyPath, $valuePath)メソッドに渡すことでkeyとvalueがペアとなった配列が取得できます。

<?php
    // Mailモデルのidをkeyに、subjectをvalueに設定する例
    $results = $this->Mail->find('all');
    $mails = Set::Combine($results, '{n}.Mail.id', '{n}.Mail.subject');
    
    // ビューでselectタグを作るためにset
    $this->set('mails', $mails);
 ?>


$keyPath、$valuePathの指定方法はCakePHP Model::generateList メソッドの {n} | Sun Limited Mt.が詳しいです。

1.1系の情報ですが、1.2系でも当てはまる部分が多々あり、今回参考にさせて頂きました。