Struts+SpringでSpringをそれらしく使う


試行錯誤して、ある日ふと閃いた方法。というかはよ気がつけよ、と思ったのも事実だが・・・。


お約束の層分け
・web層  ・・・ActionクラスとかStrutsまわり
・app層  ・・・POJOによるビジネスロジック
・domain層 ・・・DBアクセスを管理


目的
「web-app層間、app-domain層間の関係を断ち切ることにより、Mockを用いたapp層のユニットテストを可能にする」


というわけでStrutsとSpringを連携させる下準備


Struts側の修正
struts-config.xmlにplug-inの記述を追加


 


Action定義の変更
※Spring Days*1だと"org.springframework.web.struts.DelegatingRequestProcessor"を使う意見が多いようだけど、これを使うとTilesのRequestProcessorが使えない?っぽいので"org.springframework.web.struts.DelegatingActionProxy"を使うことにする。
=>誰か教えてplz【助けて!】【いたわる】
※"org.springframework.web.struts.DelegatingActionProxy"についてはJavaWorldの記事を参照


引き続きstruts-config.xml


   <=Tilesに飛ばしている


これで"/myTestInit"へのリクエストは"org.springframework.web.struts.DelegatingActionProxy"によってプロキシされる。


プロキシの設定("/WEB-INF/strutsContext.xml")


  
   
  


■Springの設定ファイル
"/WEB-INF/beans/appbeans.xml"にはapp層のBean定義を書いておく


 


"/WEB-INF/beans/domainbeans.xml"にdomain層のBean定義を書いておく(Hibernateを利用するための設定etc)
※ここから先のDBアクセスはまた別の機会に


■ソース側の修正
"sample.web.action.MyTestAction"

public class MyTestAction extends AbstractBaseAction
{
 private MyTestAppInterface app;

 public ActionForward execute(ActionMapping mapping,
                 ActionForm form,
                 HttpServletRequest request,
                 HttpServletResponse response){

  //Beanからメッセージを取得して画面に表示するだけ
  String msg = _app.getMessage();

  ActionMessage message = new ActionMessage("application.BeanName", msg);
  ActionMessages messages = new ActionMessages();
  messages.add(ActionMessages.GLOBAL_MESSAGE,message);
  saveMessages(session,messages);

  return mapping.findForward("success");
 }

 //"/WEB-INF/strutsContext.xml"に記述されたpropertyによりセットされる
 public void setMyTestApp(MyTestAppInterface _myTestApp){
  this.myTestApp = _myTestApp;
 }
}


"sample.web.app.MyTestAppInterface"

public interface MyTestAppInterface {
 public String getMessage();
}


"sample.web.app.MyTestAppBean"

public class MyTestAppBean implements MyTestAppInterface {

 private MyTestDomainInterface domain;

 //"/WEB-INF/beans/appbeans.xml"に記述されたpropertyによりセットされる
 public void setMyTestDomain(MyTestDomainInterface _domain) {
  this.domain = _domain;
 }

 public String getMessagee() {
  return domain.getMessage();
 }
}


domain層でも同様にpropertyの値がセットされる。


こうしておけば各層は「自分がどこからコールされるのか関知しないし、誰を呼び出すのかはInterfaceのみ知っている」とDIっぽくなっているんじゃないかな?
テストをする時にはテストクラスからMockのクラスをセットしておけばとっても楽ちん。


課題
・"org.springframework.web.struts.DelegatingActionProxy"を利用すると"org.apache.struts.actions.MappingDispatchAction"が使えない?
・Springの設定ファイル間の依存関係(ref)が増える
・「クラスの依存があるのでユニットテストができません」と言い訳できなくなる