分享

【Struts2进阶】Struts2深度解析ModelDriven原理

 沙门空海 2017-11-23

Strus2在获取表单数据的时候有两种方式:属性驱动模式和模型驱动模式,使用属性驱动模式,需要在Action中声明这些属性,并提供属性的getter和setter方法,这样从前台传过来的参数就会自动set到你声明的属性中。但这种方式不好的地方在于,如果实体属性很多的话,就需要声明一大堆属性以及get(),set()方法。

不过不要紧,Struts2可以采用类似于Struts1中的ActionForm方式收集数据,这样方式叫ModelDriven模式,这种模式会使用咱们定义好的JavaBean来封装这些请求参数,大大减少了JSP和Action的代码。

另外,和Struts1的ActionForm方式不同的是,Struts2中实体类Model不用继承任何父类,而在Struts1中每个Model都必须要继承ActionForm父类,显然这样侵入性更小了。


下面就来看看如何实现ModelDriven(模型驱动模式)?以及ModelDriven的原理解析。

ModelDriven实战

下面以一个示例介绍ModelDriven的使用。

一共需要如下三步:

* 创建User
* Action需要实现ModelDriven接口
* 实现getModel()方法,返回Bean对象
  • 1
  • 2
  • 3
  • 4

创建User实体

public class User {

    private String username;

    private String password;

    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;
    }   
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

UserAction的部分代码

public class LoginAction implements Action, ModelDriven<User> {

    private User user = new User();

    public String execute() throws Exception {
        if ("admin".equals(user.getUsername()) && "admin".equals(user.getPassword())) {
            return SUCCESS;
        }else {
            return ERROR;
        }
    }

    public User getModel() {
        return user;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

然后在struts.xml的配置文件中配置好Action即可,就这么简单。


ModelDriven原理

ModelDriven原理通过两部分介绍

第一部分:拦截器ModelDriven(ModelDrivenInterceptor),它是Struts2缺省拦截器链的一部分,当一个请求经过ModelDrivenInterceptor的时候,在这个拦截器中,会判断当前要调用的Action对象是否实现了ModelDriven接口,如果实现了这个接口,则调用getModel()方法,并将model对象(本例是user对象)压入ValueStack的对象栈,此时Model对象就放在了对象栈的栈顶。

第二部分:拦截器params(ParametersInterceptor),他的作用是将表单的字段映射到ValueStack的对象栈中的对象的各个属性中,映射顺序是从栈顶开始,依次往下,因为此时ValueStack的栈顶元素是刚被压入的Model(本例为User)对象,所以该Model将被首先填充,如果某个字段在Model里没有匹配的属性,Params拦截器将会匹配ValueStack中的下一个对象,直到找到匹配为止。如果没有匹配的对象属性,那么这个字段就会放到ValueStack的map中统一存储。

ModelDriven的原理就是通过这两个拦截器实现的。

下面是该拦截器intercept方法源码:

@Override
public String intercept(ActionInvocation invocation) throws Exception {
    Object action = invocation.getAction();//获取当前正在执行的Action
    //如果Action实现了ModelDriven接口
    if (action instanceof ModelDriven) {
        ModelDriven modelDriven = (ModelDriven) action;
        ValueStack stack = invocation.getStack();
        Object model = modelDriven.getModel();//通过getModel方法获取model
        if (model != null) {//如果model不为null则把model压入值栈
            stack.push(model);
        }
        if (refreshModelBeforeResult) {//在执行Result之前是否要更新model对象,默认为false
            invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
        }
    }
    return invocation.invoke();//调用下一个拦截器
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

小结

相对于属性驱动模式,模型驱动模式的好处不言而喻,它使得Action代码更加简洁,让我们的Action更加专注于是控制业务逻辑。但是任何事物都没有绝对的好坏之分,当Model中没有封装我们需要的个别特殊属性时,还是需要使用属性驱动模式,所以实际项目中一般会交叉应用。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多