- 追加された行はこの色です。
- 削除された行はこの色です。
[[Cart問題]]
* session scopeについて [#m1eed57f]
長くなったので、ページを分けました。
** session scopeの確認 [#w1b0d28a]
cartはセッションの中で管理しなければなりません。そのため、Spring2.0から導入されたsession scopeを使用します。
まずは、session scopeの使い方を確認します。
最初に以下のような簡単なクラスを定義します。
#pre{{
package example.cart.service;
public class CartService {
private Integer id;
public CartService() {
id = new Integer(1);
}
}
}}
session scopeオブジェクトは、サーブレットではなく、applicationContext.xmlと同レベルで定義しないとbeanが見つからないとのエラーになります。
そこで、session-def.xmlにsession scopeをまとめて定義しました。
#pre{{
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- a HTTP Session-scoped bean exposed as a proxy -->
<bean id="cartService" class="example.cart.service.CartService" scope="session" />
</beans>
}}
本当は、<aop:scoped-proxy />を使って自動的にsession scopeオブジェクトの再配置をしたかったのですが、何度もテストしましたがこの宣言を入れるとうまくオブジェクトがセットされません。
次にこのsession scopeオブジェクトを使用するメソッド(ここではlistメソッド)に
#pre{{
ApplicationContext co = WebApplicationContextUtils.getRequiredWebApplicationContext( request.getSession().getServletContext());
Object obj = co.getBean("cartService");
}}
としてアプリケーション・コンテキストからcartServiceを取得します。
次に、デバッガでCartServiceのコンストラクタにブレークポイントをセットし、tomcatを起動します。
ブラウザーからlistのページにアクセスするとcartServiceオブジェクトのコンストラクタがコールされます。
ブラウザーを起動し直すと再度cartServiceオブジェクトのコンストラクタがコールされ、session毎に
オブジェクトが生成されることが確認できます。
** テストケース [#w1ffaed7]
先の修正でsession scopeのオブジェクトは、取得できるようになったのですが、テストではこれがうまく動作しません。
試行錯誤の結果、以下のような対処をTestCaseにしました。
- getApplicationContextメソッドで返されるContextをGenericApplicationContextからGenericWebApplicationContextに変更
- StaticWebApplicationContextのようにscopeの処理を登録
- requestの前後にRequestContextFilterの処理を追加
上記の処理を追加したTestCaseをAbstractTransactionalSpringWebContextTestsとしてGenMVCプラグイン
に登録しました。
使い方は、
#pre{{
public void testmemberOpsController_List() {
dbUnitHelperDao.restore("src/test/resources/dump.xml");
MockHttpServletRequest req = new MockHttpServletRequest("POST","memberops/list.htm");
MemberOpsController memberOpsController = (MemberOpsController)getApplicationContext().getBean("memberOpsController");
ModelAndView mv = null;
try {
beginRequest(req);
mv = memberOpsController.handleRequest(req,new MockHttpServletResponse());
endRequest(req);
} catch (Exception err) {
err.printStackTrace();
}
Member expectedMember = (Member)getApplicationContext().getBean("expectedMember");
assertNull(mv.getViewName());
Member[] members = (Member[])mv.getModel().get("memberList");
assertEquals(memberManager.print(expectedMember), memberManager.print(members[0]));
HttpSession session = req.getSession();
req = new MockHttpServletRequest("POST","memberops/list.htm");
// sessionを持ち回るとsession内の要求として扱われる
req.setSession(session);
memberOpsController = (MemberOpsController)getApplicationContext().getBean("memberOpsController");
mv = null;
try {
beginRequest(req);
mv = memberOpsController.handleRequest(req,new MockHttpServletResponse());
endRequest(req);
} catch (Exception err) {
err.printStackTrace();
}
expectedMember = (Member)getApplicationContext().getBean("expectedMember");
assertNull(mv.getViewName());
members = (Member[])mv.getModel().get("memberList");
assertEquals(memberManager.print(expectedMember), memberManager.print(members[0]));
}
}}
handleRequestの前後にbeginRequest, endRequestを入れ、最初の要求のsessionを以降のrequestにセットします。