やっとAction

Logicクラスを作成する前にActionクラスを作成しよう。
まず、システムをつくるにはログオン/ログオフだろ。
ってことで、LogonActionとLogoffActionの作成。


Actionクラスもテストクラスは作成しなくてもいいか。
まずは、ドキュメントを参照しながら作ってみよう。

Actionクラスの呪縛から解き放つためには、やっぱり「ActionをPOJOにした使い方」を参照。
ふーむ。これは簡単にできそうだ。S2Daoのときはドキュメントを見ないでサンプルを見た感覚で作ったからたくさんエラーになったけど
今度はエラーなくできそうな予感。

まず、LoginActionインターフェイスを作成。

package study.xxx.web;
	
public interface LogonAction {
    
    public String logon();

}


次に実装だけど、ActionFormもやっぱりPOJOでしょ。
Struts1.2.4からはActionFormもPOJOでできるよってどっかで見た気がするし。動かしてみればすぐにわかることだし。
どうやって、ActionクラスとLogicクラスを結ぶんだろう?
s2jsf-exampleではセッター・インジェクションを利用してるなー。
でも、コンストラクタ・インジェクションがしっくりくるようなこないような・・・。ま、どっちでもいいか
こんなところで悩んでも勉強にならないし。自分優先で。

public class LogonActionImpl implements LogonAction {
    
    private PartyLogic partyLogic;
    
    private PartyDto logonForm;
    
    public LogonActionImpl(PartyLogic partyLogic) {
        this.partyLogic = partyLogic;
    }

    public String logon() {
        if (!partyLogic.existParty(logonForm)) {
            return "error";
        }
        
        return "success";
    }

    public PartyDto getLogonForm() {
        return logonForm;
    }
    
    public void setLogonForm(PartyDto logonForm) {
        this.logonForm = logonForm;
    }

}

こんなもんかな。最初は。
Logicクラスがないってコンパイルエラーが出てるから、PartyLogicインタフェースと実装を作ろう。
LogicクラスとDAOクラスを結びつけるためには・・・
うーむ。s2jsf-exampleではやっぱりセッター・インジェクションか・・・
コンストラクタ・インジェクションよりセッター・インジェクションの方がわかりやすいってことかな。
ま、ここもActionクラスとあわせてコンストラクタ・インジェクションにしよう。自分優先ってことで

public interface PartyLogic {

    public boolean existParty(PartyDto dto);

}
public class PartyLogicImpl implements PartyLogic {
    
    private PartyDao partyDao;
    
    public PartyLogicImpl(PartyDao partyDao) {
        this.partyDao = partyDao;
    }

    public boolean existParty(PartyDto dto) {
        PartyDto party = partyDao.findByAccount(dto.getAccount());
        if (party == null) {
            return false;
        }
        
        return party.getPassword().equals(dto.getPassword());
    }
}

あー、PartyDao#findByAccountがない・・・・
PartyDaoに追加しないと
DAOはテストクラス作ってるから、PartyDaoTestにtestFindByAccountを追加しないと。

最近の人だったら、ActionクラスでもLogicクラスでもきちんとテストクラス作るんだろうなー
自分はオールドタイプってことか・・・
簡単にテストクラスを作れないことが恥ずかしいな。
すぐにメンドクサイって思ってしまう。

テストメソッドはこんな感じかな。

    public void testFindByAccountTx() {
        deleteTable(PartyDto.TABLE);
        readXlsWriteDb("PartyTestData.xls");

        PartyDto found = dao.findByAccount("DUMMY");
        assertNotNull(found);
        assertEquals("DUMMY", found.getAccount());
    }

Eclipseの力を借りてコンパイルエラーをなくして、実行。
全部エラー。あれっっっ、期待と違うんですけど。
HSQLDBをあげ忘れてた・・・。
あげて実行。失敗1件。これこれ期待してたのは。
sqlファイルを作ればなくなるはず。
作って実行。グリーンバー。

残る作業は、

  1. DICONファイルの作成
  2. struts-config.xmlの作成
  3. JSPの作成

DICONファイルは、s2jsf-exampleをパクろう。
party.diconを作ってPartyLogicとLogonActionを記述しよう。
あと、app.diconに記述するのもわすれないようにっと。

<components>
    <include path="study/xxx/dicon/alldao.dicon"/>
    <include path="study/xxx/dicon/allaop.dicon"/>
    
    <component class="study.xxx.logic.PartyLogicImpl">
        <aspect>logicInterceptorChain</aspect>
    </component>

    <component class="study.xxx.web.LogonActionImpl" instance="request">
        <aspect>actionInterceptorChain</aspect>
    </component>
    
</components>

struts-config.xmlの作成か。ちょっと憂鬱だな。
XDocletって手もあるけど、POJOAction/POJOFormには対応してないし。
XDoclet使うためにActionやActionFormから派生するのはもっとヤダし。
自分でXDocletの定義を作るしかないかなー。でも後回しだ。XDocletは。
それにS2Daoを使ってみて思ったんだけど、struts-config.xmlを書くかわりにActionインターフェースに??アノテーションをつけて
とかで対応する方がかっこいいような気がする。
そっちは、LogonAction/LogoffActionができたら考えよう。

とりあえず、自力でstruts-config.xmlの記述。

ActionMappingはこんな感じ。

        <action
            path="/site/logon"
            type="study.xxx.web.LogonAction"
            name="logonForm"
            scope="request"
            unknown="false"
            validate="false"
        >
          <forward
              name="success"
              path="/pages/top.jsp"
              redirect="false"
          />
          <forward
              name="error"
              path="/pages/deny.jsp"
              redirect="false"
          />
        </action>


JSPファイル作成か。
sitemesh-blank.warからdecoratorディレクトリ配下をどっそりもらってこよう。
StrutsActionは/do/*にマッピングして、
sitemeshは/do/site/*にマッピングしよう。

あとは、

を作成するとMessageResources.propertiesに追加する必要の項目がたくさん出てくる。
ここらへんはメンドイけど、ゆっくりやるしかないんだよねー。

よし。できた。
今回、初のTomcat起動。
やっぱり、コンソールに例外が出力されている。

java.lang.ClassNotFoundException: examples.jsf.interceptor.ActionThrowsInterceptor

だって。
DICONファイルをs2jsf-exampleからコピーしたからだ。
allaop.diconに記述があった。
理解せずにコピーばかりしているとダメだね。やっぱり。
一回停止してから、allaop.diconを修正。そして起動。
またコンソールに例外が。

java.lang.ClassNotFoundException: study.xxx.logic.PartyLogicImpl

・・・これって記述ミス
study.xxx.logic.impl.PartyLogicImpl
だから。
Actionのほうも同じ記述ミス。


修正して再度起動。無事、例外なく起動。
JSP表示できるかなー。


表示できた。
でもスタイルシートをコピーしわすれ。変。
以前使ったやつを利用しよう。うん。きれいに表示できた。
でも、JSPエラーなく表示できたのはまぐれだな。いつもなら見慣れたエラーページが表示されるのに。


accountとpasswordを入力してLOGONと・・・
うまくいってる。
コンソールにもログがきれいにでてる。すごいなー。
passwordが違う場合も試してみよう。
おぉ、エラーメッセージ画面になった。
もしかしてLogonActionクラス完成。エラーにならなかったなー。S2Strutsのおかげだー。


sitemethのmain.jspがかっこわるいから変更しよう。メニュー欄とかつけないと。


修正したけど、画面を見ると反映されていない。なぜだろう。
キャッシュか?
workフォルダ配下を全部消してみよう。


うまくいった。


修正しないといけないところは、

  1. logonページ表示のURLをhttp://localhost:8080/s2xxx-study/pages/logon.jsp からhttp://localhost:8080/s2xxx-study/do/logonにすること。
  2. logonFormの入力検証を記述すること
  3. logonエラーの場合にエラーページにとぶんじゃなくてlogonページに入力検証エラーメッセージと同じような形で表示すること。

「1.」は簡単。Action-mappingに下のを追加するだけ

        <action
            path="/logon"
            forward="/pages/logon.jsp"/>

こういうところは、Strutsを使ってたからすぐにできる。
あと、logonした後のURLが気に入らないから/do/site/topにredirectすることにしよう。
もちろん

        <action
            path="/site/top"
            forward="/pages/top.jsp"/>

を追加して。

うまくできた。

次は「2.」。これもなれたもんだから簡単。
validation.xmlを書いて、Action-mappingを少し修正してTomcat再起動。
エラーの確認っと。


・・・・


validationはうまくできてるけど・・・
Logon画面がsitemeshによこどりされてる。
URLがまずいからか・・・
でも、/site/logonを/logonにするとさっき追加したAction-mappingとかぶる。
どうしよう。

/site/logonを/authにしよう。認証って意味で。これで解決と。
struts-config.xmlを修正してTomcat再起動。
そして確認っと。


ぬぉ、見慣れたエラーページが表示された
アクション /site/logon に対応するマッピングが見つかりません
だって。
logon.jspの修正忘れてた。
修正して、ページが表示できるか確認。


うまくできた。
validationエラーもきれいに表示できてる。

POJOのActionFormってうまく動いてる。


Seasar-userメーリングリストでPOJOActionFormがsessionスコープに格納できないってのがある。
そうなんだー。
いずれ解決しないといけないけど、POJOActionFormってStrutsが提供してるからs2strutsとは関係ないような気がする。
それともActionといっしょでS2Containerで管理してるのかな。
でもDICONファイルには記述していないし。やっぱ関係ないか。
ま、関係あるかないかもいずれわかることか。
こっちは問題なく動いてるし。
自分が取り掛かる前に解決してたらいいなー。


その前に「3.」の対応をしないと。
SturtsならActionMessageを作って、Action#addErrorsでできるんだけど、S2StrutsのActionはPOJOだからどうするんだろ?
調べよう。



sessionに格納するときは、

public final static String プロパティ名_EXPORT = org.seasar.struts.util.BindingUtil.SESSION;

でできるんだって。便利だ。


Messageについてはのってない。(探しが足りない?)

public final static String プロパティ名_EXPORT = ???;

って感じでできる気がする。
ソースを見てみよう。


ActionExecuteProcessorImplがBindingUtilを利用して処理してる。なるほどねー。
org.seasar.struts.util.BindingUtil.SESSIONって"session"っていう文字列なんだ。
ふーん。
現状EXPORTできるのはsessionだけなのかー。
どうしよう。


ActionExecuteProcessorImplは、s2struts.diconにexecuteProcessorとして記述してある。
独自のActionExecuteProcessorImplを作ればできそうだ。

public final static String プロパティ名_EXPORT = "errors";

ってなってたら、Action#addErrorsを呼んだときと同じようになるようにしよう。


っていうか独自のActionExecuteProcessorImplを作るだけの技術があるのか?


その前にAction#addErrorsの内容を調べよう。
うーむ。簡単な処理だ。
Action#addMessagesってのもあるんだー。使ったことない。勉強不足だ。


BindingUtilがインジェクションの対象だったらよかったな。
とりあえず、
XxxActionExecuteProcessorImplとXxxActionPropertyBinderImplってのを
作ろう。
処理内容はそれぞれActionExecuteProcessorImplとBindingUtilをコピーさせてもらおう。
メチャクチャになりそうな予感。でもやってみないとわからないし。