サービスレイヤー
DAO レイヤーと連携しながら、コントローラーの要求に応じたサービスを提供するレイヤーです。DAO レイヤーと同様(というか Spring Framework における開発の基本?)、インターフェースを定義し、その実装クラスを作ります。
AccountService.java(インターフェース)
新規アカウントを作成する makeAccount() と UserProfile を取得する getProfile() を定義してます。
package wrider.service; import java.util.Map; import wrider.model.IdCard; import wrider.model.UserProfile; public interface AccountService { public MapmakeAccount(UserProfile userProfile); public UserProfile getProfile(IdCard idCard); }
AccountServiceImpl.java(実装クラス)
@Service アノテーションでこのクラスがサービスコンポーネントであることを示しています。尚、ProfileManager インターフェースの実装クラス ProfileManagerImple には、@Repository アノテーションを付けてリポジトリーコンポーネントであることを示しています。
[servlet-name]-servlet.xml で <context:component-scan/> が有効になっている場合、Spring Framework は、@Autowired されたフィールドの型に該当するインターフェースの実装クラスを探して DI します。実装クラスに付けた @Service や @Repository は、この時の目印になります。
ProfileManager フィールドに @Autowired を付けて、 ProfileManagerImpl を DI しています。
makeAccount()メソッドは、コントローラーから受け取った UserProfile オブジェクトを profileManager の callAddUserProfile()メソッドに渡し、処理結果を Map
package wrider.service; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import wrider.dao.ProfileManager; import wrider.model.IdCard; import wrider.model.UserProfile; @Service public class AccountServiceImpl implements AccountService { @Autowired private ProfileManager profileManager; public Map<String, Object> makeAccount(UserProfile userProfile) { return this.profileManager.callAddUserProfile(userProfile); } public UserProfile getProfile(IdCard idCard) { return this.profileManager.getUserProfile(idCard); } }
コントローラー
テーブルスキーマの定義から DAO レイヤー、サービスレイヤーと遡って、ようやくコントローラーに辿りつきました。『CGLIB Proxy で捕捉エリアを拡大』までに散々手を加えた AccountController クラスに、先述した AccountService を利用するメソッドを追加します。
AccountController.java(抜粋)
まず、@Autowired で AccountService を DI しています。/account/login.html および /account/register.html に対する GET リクエストを受けた場合は、単純に各 URL に対応するビュー名を返すだけです。
package wrider.controller; : @Controller @SessionAttributes({"idCard", "userProfile"}) public class AccountController { @Autowired private AccountService accountService; @ModelAttribute("idCard") public IdCard makeIdCard() { return new IdCard(); } @ModelAttribute("userProfile") public UserProfile makeUserProfile() { return new UserProfile(); } : @RequestMapping(value="/account/login.html", method=RequestMethod.GET) public String login() { return "account/login"; } : @RequestMapping(value="/account/register.html", method=RequestMethod.GET) public String register() { return "account/registrationForm"; } : }
login()メソッド:
ログインフォームからの POST リクエストで実行される login()メソッドは、引数として フォームへの入力データを含む IdCard とバリデーション結果を格納する BindingResult のほか、@ModelAttribute でアノテートされた UserProfile オブジェクトを受け取ります。これに accountService.getProfile(idCard) の実行結果がバインドされます。UserProfile オブジェクトは、@SessionAttributes に登録されているため、セッションが有効である間は維持されます。認証成功後、取得した UserProfile を ModelAndView オブジェクトに登録して /welcome/home.html にリダイレクトします。
@RequestMapping(value="/account/login.html", method=RequestMethod.POST)
public ModelAndView login(
@ModelAttribute("userProfile") UserProfile userProfile,
@Valid IdCard idCard,
BindingResult br) {
ModelAndView mav = new ModelAndView();
if (br.hasErrors()) {
mav.getModel().putAll(br.getModel());
mav.setViewName("account/login");
}
else {
userProfile = accountService.getProfile(idCard);
if (userProfile == null) {
mav.setViewName("account/login");
}
else {
mav.addObject("userProfile", userProfile);
mav.setViewName("redirect:../welcome/home.html");
}
}
return mav;
}
尚、引数の順序について若干の注意が必要です。リファレンス“16.3.3.1 Supported method argument types”の最後に『BindingResult(またはError)引数は、モデルオブジェクト(引数)の直後に続かなければならない。Spring は、先行する各モデルオブジェクトのために BindingResult インスタンスを生成する』という旨が書いてあります。確かに、BindingResult が @Valid でアノテートした引数の後に記述されていないと「バリデーション結果を入れる場所が無い」と怒られます。
register()メソッド:
accountService.makeAccount(userProfile) の実行結果は、HashMap
@RequestMapping(value="/account/register.html", method=RequestMethod.POST)
public ModelAndView register(
@Valid UserProfile userProfile,
BindingResult br) {
ModelAndView mav = new ModelAndView();
if (br.hasErrors()) {
mav.getModel().putAll(br.getModel());
mav.setViewName("account/registrationForm");
}
else {
HashMap<String, Object>notice = (HashMap<String, Object>)accountService.makeAccount(userProfile);
if (Boolean.parseBoolean(notice.get(Items.RESULT).toString())) {
mav.setViewName("redirect:/welcome/home.html");
}
else {
mav.setViewName("account/registrationForm");
}
}
return mav;
}
次回は、Hibernate, c3p0 関連の設定を予定しています。
0 件のコメント:
コメントを投稿