ModelDriven机制及其运用

来源:互联网 发布:淘宝店推广软文范文 编辑:程序博客网 时间:2024/06/05 15:45
ModelDriven

 

为什么需要ModelDriven

 

所谓ModelDriven ,意思是直接把实体类当成页面数据的收集对象。比如,有实体类User 如下:

 

package cn.com.leadfar.struts2.actions;

 

public class User {

   private int id ;

   private String username ;

   private String password ;

   private int age ;

   private String address ;

   public String getUsername() {

      return username ;

    }

   public void setUsername(String username) {

      this . username = username;

    }

   public String getPassword() {

      return password ;

    }

   public void setPassword(String password) {

      this . password = password;

    }

   public int getAge() {

      return age ;

    }

   public void setAge( int age) {

      this . age = age;

    }

   public String getAddress() {

      return address ;

    }

   public void setAddress(String address) {

      this . address = address;

    }

   public int getId() {

      return id ;

    }

   public void setId( int id) {

      this . id = id;

    }

   

   

}

 

 

假如要写一个Action ,用来添加User 。

第一种做法是直接在Action 中定义所有需要的属性,然后在JSP 中直接用属性名称来提交数据:

UserAction:

 

public class UserAction {

   private int id ;

   private String username ;

   private String password ;

   private int age ;

   private String address ;

 

   public String add(){

      

       User user = new User();

       user.setId( id );

       user.setUsername( username );

       user.setPassword( password );

       user.setAge( age );

       user.setAddress( address );

      

      new UserManager().addUser(user);

      

      return "success" ;

    }

   

   public int getId() {

      return id ;

    }

   public void setId( int id) {

      this . id = id;

    }

   public String getUsername() {

      return username ;

    }

   public void setUsername(String username) {

      this . username = username;

    }

   public String getPassword() {

      return password ;

    }

   public void setPassword(String password) {

      this . password = password;

    }

   public int getAge() {

      return age ;

    }

   public void setAge( int age) {

      this . age = age;

    }

   public String getAddress() {

      return address ;

    }

   public void setAddress(String address) {

      this . address = address;

    }

   

}

 

add_input.jsp:

 

     < form action = "test/user.action" method = "post" >

        < input type = "hidden" name = "method:add" >

        username: < input type = "text" name = "username" > < br />

        password: < input type = "text" name = "password" > < br />

        age: < input type = "text" name = "age" > < br />

        address: < input type = "text" name = "address" > < br />

        < input type = "submit" name = "submit" value = " 添加用户 " >

     </ form > < br />

上述做法不好之处是:如果实体类的属性非常多,那么Action 中也要定义相同的属性。

 

 

第二种做法是将User 对象定义到UserAction 中,然后在JSP 中通过user 属性来给user 赋值:

UserAction:

 

public class UserAction {

   

   private User user ;

   

   public String add(){

 

      new UserManager().addUser( user );

      

      return "success" ;

    }

 

   public User getUser() {

      return user ;

    }

 

   public void setUser(User user) {

      this . user = user;

    }

   

   

}

 

add_input.jsp:

 

     < form action = "test/user.action" method = "post" >

        < input type = "hidden" name = "method:add" >

        username: < input type = "text" name = "user.username" > < br />

        password: < input type = "text" name = "user.password" > < br />

        age: < input type = "text" name = "user.age" > < br />

        address: < input type = "text" name = "user.address" > < br />

        < input type = "submit" name = "submit" value = " 添加用户 " >

     </ form > < br />

这种做法不好的地方是:JSP 页面上表单域中的命名变得太长

 

第三种做法是利用ModelDriven 机制,让UserAction 实现一个ModelDriven 接口,同时实现接口中的方法:getModel() 。如下所示:

 

public class UserAction implements ModelDriven{

   

   private User user ;

   

    @Override

   public Object getModel() {

      if ( user == null ){

           user = new User();

       }

      return user ;

    }

 

   public String add(){

 

      new UserManager().addUser( user );

      

      return "success" ;

    }

 

   public User getUser() {

      return user ;

    }

 

   public void setUser(User user) {

      this . user = user;

    }

}

JSP 的代码如下:

 

     < form action = "test/user.action" method = "post" >

        < input type = "hidden" name = "method:add" >

        username: < input type = "text" name = "username" > < br />

        password: < input type = "text" name = "password" > < br />

        age: < input type = "text" name = "age" > < br />

        < input type = "submit" name = "submit" value = " 添加用户 " >

     </ form > < br />

 

可见,第三种做法是比较好的,Action 和JSP 写起来都比较简单。

 

 

ModelDriven 背后的机制?

 

ModelDriven 背后的机制就是ValueStack 。界面通过:username/age/address 这样的名称,就能够被直接赋值给user 对象,这证明user 对象正是ValueStack 中的一个root 对象!

 

那么,为什么user 对象会在ValueStack 中呢?它是什么时候被压入ValueStack 的呢?答案是:ModelDrivenInterceptor (关于Interceptor 的概念,请参考后续章节的说明)。ModelDrivenInterceptor 是缺省的拦截器链的一部分,当一个请求经过ModelDrivenInterceptor 的时候,在这个拦截器中,会判断当前要调用的Action 对象是否实现了ModelDriven 接口,如果实现了这个接口,则调用getModel() 方法,并把返回值(本例是返回user 对象)压入ValueStack 。

请看ModelDrivenInterceptor 的代码:

 

public class ModelDrivenInterceptor extends AbstractInterceptor {

 

   protected boolean refreshModelBeforeResult = false ;

 

   public void setRefreshModelBeforeResult( boolean val) {

       this . refreshModelBeforeResult = val;

    }

 

    @Override

   public String intercept(ActionInvocation invocation) throws Exception {

        Object action = invocation.getAction();

 

       if (action instanceof ModelDriven) {

            ModelDriven modelDriven = (ModelDriven) action;

            ValueStack stack = invocation.getStack();

            Object model = modelDriven.getModel();

           if (model !=  null ) {

             stack.push(model);

            }

           if ( refreshModelBeforeResult ) {

                invocation.addPreResultListener( new RefreshModelBeforeResult(modelDriven, model));

            }

        }

       return invocation.invoke();

    }

从ModelDrivenInterceptor 中,即可以看到model 对象被压入ValueStack 中!

 

其中的 refreshModelBeforeResult 是为了接下来描述的一个问题而提供的解决方法。

 

理解常见的陷阱及其解决方法

 

假设我们要更新一个实体对象,那么第一步首先是打开更新界面,请看下述模拟打开更新界面的代码:

 

public class UserAction implements ModelDriven{

   

   private User user ;

   

    @Override

   public Object getModel () {

      if ( user == null ){

           user = new User();

           //user.setUsername(" 这是原来的 User 对象 ");

       }

      return user ;

    }

   

   public String updateInput(){

      

       // 根据 ID ,查询数据库,得到 User 对象

       user = new UserManager().findUserById( user .getId());

      

      

      return "update_input" ;

    }

 

上述代码中,new UserManager().findUserById(user.getId()); 这一行,将从数据库中查询相应的记录,同时转换为User 对象返回。而return “ update_input ” ;将转向更新显示页面。

 

更新页面如下:

 

     < form action = "test/user.action" method = "post" >

        < input type = "hidden" name = "method:update" >

        id: < input type = "text" name = "id" value = "< s:property value = "id" /> "> < br />

        username: < input type = "text" name = "username" value = "< s:property value = "username" /> "> < br />

        password: < input type = "text" name = "password" value = "< s:property value = "password" /> "> < br />

        age: < input type = "text" name = "age" value = "< s:property value = "age" /> "> < br />

        address: < input type = "text" name = "address" value = "< s:property value = "address" /> "> < br />

        < input type = "submit" name = "submit" value = " 更新用户 " >

     </ form > < br />

 

 

上述代码运行起来之后,你在更新界面上将看不到数据(id 属性有值,其它属性无显示)。关键的原因是在执行到updateInput 之前,user 对象(在getMode() 方法中创建的对象)被压到ValueStack 中,这时候,UserAction 和ValueStack 都指向同一个user 对象;但紧接着,UserAction 中的user 被一个新的user 对象覆盖,这时候,UserAction 和ValueStack 不再指向同一个user 对象!ValueStack 中是旧的user 对象,而UserAction 中是新的user 对象!我们在JSP 中,直接通过username/address 等直接访问,当然是要访问ValueStack 中的旧user 对象,所以它们的属性都是空的(id 属性除外) !

 

理解上述问题很重要,当你理解了问题,那么问题的解决方法就可以有很多了:

比如,你可以把新对象的属性拷贝到旧对象上;比如,你可以先把旧对象从ValueStack 中移除,然后再把新对象压入ValueStack 等……

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 工行企业网银证书过期了怎么办 海淘转运地址国家填错了怎么办 集装箱实重与申报重量不一样怎么办 微博复制的淘口令找不到了怎么办 买了移动手机不能用联通卡怎么办 移动手机用联通卡网速慢怎么办 移动手机插联通卡没反应怎么办 移动手机办了联通大王卡怎么办 qq被冻结但是有至尊宝怎么办 qq被冻结了有至尊宝怎么办 移动电话卡注销了里面的钱怎么办 罗麦的oa上经理喜报没截图怎么办 工行融e联登录密码忘了怎么办 融e借有额度秒拒怎么办 工行银行柜台办理融e借怎么办 地球末日生存破解版金币没了怎么办 手机被别人骗走了里面的微信怎么办 在微信里面被做微商的骗了钱怎么办 在qq上骗了人50怎么办 被3m多酶清洗液滴到皮肤怎么办 做3m赔了9万怎么办 在携程网上订的酒店发票怎么办 滴滴滴取消订单电话打不通怎么办 百度云容量2068g满了怎么办 淘宝电脑端描述图片间隔大怎么办 手机上下载游戏自动扣费怎么办 苹果手机下载游戏自动扣费怎么办 用手机账号登陆游戏换手机怎么办 在qq上被骗充q币怎么办 微信借钱后删了好友怎么办 财付通绑定了其它人的身份证怎么办 微信支付密码忘了没绑银行卡怎么办 微信没有绑银行卡忘记密码怎么办 威信解绑银行卡支付密码望了怎么办 买了个qq号绑定了财付通怎么办 淘宝买的东西下架了怎么办 微信红包充话费充错了怎么办 手机qq不能发红包或转账怎么办 qq给人发红包被骗了怎么办 qq发红包对方看不不到怎么办 手机浏览器支付页面弹不出来怎么办