ModelDrivenプラグイン(作りかけ)
ovalを簡単に使いたかったので、T2で簡単なModelDrivenプラグイン(作りかけ)を作ってみました。
あくまで作りかけなのでDtoのプロパティの型にはStringしか設定できません・・・。
◇使い方
1.Dtoを作成
2.Pageクラスを作成し、ModelDrivenをimplementsします。
※Actionが呼ばれた時点で、リクエストに渡ってきたmodelにデータが入ってくる。
サンプルでは@Beforeでvalidation部分を分離しています。
以下、使い方のサンプル(t2,ovalおよび下にあるソースが必要)
package hoge.dto; public class LoginDto { @NotNull @NotEmpty @Length(min=4, max=12) private String loginid; @NotNull @NotEmpty @Length(min=8, max=16) private String password; public String getLoginid() { return loginid; } public void setLoginid(String loginid) { this.loginid = loginid; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
○Page
hoge.page.LoginPage
package hoge.page; @RequestScope @Page("login") public class LoginPage implements ModelDriven<LoginDto>{ private LoginDto model = new LoginDto(); public Navigation validateLogin(WebContext context) { Validator validator = new Validator(); List<ConstraintViolation> violations = validator.validate(model); for (ConstraintViolation violation : violations) { System.out.println(violation.getMessage()); } if(violations.size() > 0){ // NG. return Forward.to("/WEB-INF/pages/login.html"); } // OK. return PluginDefaultNavigation.INSTANCE; } @POST @ActionParam @Before(method = "validateLogin") public Navigation login(WebContext context) { System.out.println("====== login ======="); return ・・・ } @Override public LoginDto getModel() { return model; } }
○HTML
<html> <head></head> <body> <form action="/hoge/login" method="POST"> user:<input type="text" name="loginid" /><br /> pass:<input type="text" name="password" /><br /> <input type="submit" name="login" value="ログイン" /> </form> </body> </html>
どこにアップしていいか分からなかったので(アップする段階でもない)とりあえずソースを貼り付けておきます・・・。(よく分かっていない部分が多いので、ソースコードのツッコミ大歓迎)
org.t2framework.plugins.interceptor.ActionInterceptorPlugin.java
package org.t2framework.plugins.interceptor; import java.lang.reflect.Method; import java.util.Iterator; import java.util.Map; import org.seasar.framework.util.MethodUtil; import org.t2framework.commons.meta.BeanDesc; import org.t2framework.commons.meta.BeanDescFactory; import org.t2framework.commons.meta.Config; import org.t2framework.commons.meta.MethodDesc; import org.t2framework.commons.util.Logger; import org.t2framework.commons.util.StringUtil; import org.t2framework.plugins.interceptor.annotation.After; import org.t2framework.plugins.interceptor.annotation.Before; import org.t2framework.t2.action.ActionContext; import org.t2framework.t2.plugin.AbstractPlugin; import org.t2framework.t2.spi.Navigation; public class ActionInterceptorPlugin extends AbstractPlugin { protected Logger log = Logger.getLogger(ActionInterceptorPlugin.class); private void setValue(Object model, String name, Object value){ String setterName = "set" + StringUtil.capitalize(name); Method[] methods = model.getClass().getMethods(); for(int i=0; i<methods.length; i++){ if(methods[i].getName().equals(setterName)){ try{ // TODO 引数の型を変換する MethodUtil.invoke(methods[i], model, new Object[]{value}); }catch(IllegalArgumentException e){ log.info(methods[i].getName()+"の引数の型が一致しませんでした", value); } } } } @Override @SuppressWarnings("unchecked") public Navigation beforeActionInvoke(ActionContext actionContext, MethodDesc targetMethod, Object page, Object[] args) { if(page instanceof ModelDriven){ ModelDriven modelDriven = (ModelDriven) page; Object model = modelDriven.getModel(); if (model != null) { Map<String, Object> params = actionContext.getRequest().getAttributesAsMap(); if(!params.isEmpty()){ for (Iterator<Map.Entry<String, Object>> itr = params.entrySet().iterator(); itr.hasNext();) { Map.Entry<String, Object> entry = itr.next(); try { setValue(model, entry.getKey(), entry.getValue()); } catch (RuntimeException e) { e.printStackTrace(); log.error("", "ActionInterceptorPlugin", "Key:" + entry.getKey() + " Value:" + entry.getValue()); } } } } } if (targetMethod.hasConfig(Before.class)) { Config config = targetMethod.findConfig(Before.class); Before before = (Before) config.getAnnotation(); String methodName = before.method(); BeanDesc<Object> beanDesc = BeanDescFactory.getBeanDesc(page); MethodDesc beforeMethod = beanDesc.getMethodDesc(methodName); Navigation invoke = (Navigation) beforeMethod.invoke(page, args); if (invoke != null) { return invoke; } } return super.beforeActionInvoke(actionContext, targetMethod, page, args); } @Override public Navigation afterActionInvoke(ActionContext actionContext, MethodDesc targetMethod, Object page, Object[] args) { if (targetMethod.hasConfig(After.class)) { Config config = targetMethod.findConfig(After.class); After after = (After) config.getAnnotation(); String methodName = after.method(); BeanDesc<Object> beanDesc = BeanDescFactory.getBeanDesc(page); MethodDesc beforeMethod = beanDesc.getMethodDesc(methodName); Navigation invoke = (Navigation) beforeMethod.invoke(page, args); if (invoke != null) { return invoke; } } return super.afterActionInvoke(actionContext, targetMethod, page, args); } }
org.t2framework.plugins.interceptor.ModelDriven.java
package org.t2framework.plugins.interceptor; public interface ModelDriven<T> { T getModel(); }
org.t2framework.plugins.interceptor.annotation.Before.java
package org.t2framework.plugins.interceptor.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Before { String method() default "before"; }
org.t2framework.plugins.interceptor.annotation.After.java
package org.t2framework.plugins.interceptor.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface After{ String method() default "after"; }