• 关于struts2的modelDriven



    今天做毕业设计,前台往后台赋值,习惯性的用了modelDriven。但是刚写完就奇怪它的机理是怎样的,它怎么知道我前台传的参是哪个Model的属性(之前用servlet都是手动),于是手贱的ctrl点进去,简单了解了一下


    之前记得要使用modelDriven必须使用modelDriven的拦截器,但是我没加这个拦截器也实现了功能,看默认拦截器defaultStack原来所谓的默认拦截器就是一系列拦截器的集合

    看modelDriven的源码可以看到

     1     @Override
     2 
     3 public String intercept(ActionInvocation invocation) throws Exception {
     4 
     5 //获取 Action 对象: EmployeeAction 对象, 此时该 Action 已经实现了 ModelDriven 接口
     6 
     7     //public class EmployeeAction implements RequestAware, ModelDriven<Employee>
     8 
     9         Object action = invocation.getAction();
    10 
    11 //判断 action 是否是 ModelDriven 的实例
    12 
    13         if (action instanceof ModelDriven) {
    14 
    15 //强制转换为 ModelDriven 类型
    16 
    17             ModelDriven modelDriven = (ModelDriven) action;
    18 
    19 //获取值栈
    20 
    21             ValueStack stack = invocation.getStack();
    22 
    23 //调用 ModelDriven 接口的 getModel() 方法
    24 
    25             //即调用 EmployeeAction 的 getModel() 方法
    26 
    27             /*
    28 
    29             public Employee getModel() {
    30 
    31               employee = new Employee();
    32 
    33               return employee;
    34 
    35            }
    36 
    37             */
    38 
    39             Object model = modelDriven.getModel();
    40 
    41             if (model !=  null) {
    42 
    43 //把 getModel() 方法的返回值压入到值栈的栈顶. 实际压入的是 EmployeeAction 的 employee 成员变量
    44 
    45               stack.push(model);
    46 
    47             }
    48 
    49             if (refreshModelBeforeResult) {
    50 
    51                 invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
    52 
    53             }
    54 
    55         }
    56 
    57         return invocation.invoke();

    发现它什么也没实现,就是modelDriven接口,如果实现了就调用了它的getModel方法,然后把得到的压入栈顶。没有赋值操作

    那么流程图应该是这样:


    那么setName()赋值操作是谁做的?ParametersInterceptor

    那么结论是:

    1)ModelDrivenInterceptor只是将实现了ModelDriven的action的model放入值栈而已,所以你才可以直接使用
    <input type="text" name="type" />传值。
    2)如果action没有实现此接口,那么配置ModelDrivenInterceptor没有任何意义
    3)ModelDrivenInterceptor并不负责注入值,赋值的是ParametersInterceptor 


    如果还要深究的话

    ParametersInterceptor拦截器继承自MethodFilterInterceptor,其主要功能是把ActionContext中的请求参数设置到ValueStack中,如果栈顶是当前Action则把请求参数设置到了Action中,如果栈顶是一个model(Action实现了ModelDriven接口)则把参数设置到了model中。

    ParametersInterceptor拦截器主要源码:

     1 @Override  
     2 public String doIntercept(ActionInvocation invocation) throws Exception {  
     3     Object action = invocation.getAction();//获取当前执行的Action对象  
     4     if (!(action instanceof NoParameters)) {//判断Action是否实现了NoParameters接口,实现该接口表示该Action没有任何请求参数  
     5         ActionContext ac = invocation.getInvocationContext();//获取ActionContext对象  
     6         final Map<String, Object> parameters = retrieveParameters(ac);//获取请求参数Map  
     7         //省略...  
     8         if (parameters != null) {//如果请求参数不为null  
     9             Map<String, Object> contextMap = ac.getContextMap();//获取ActionContext内部的context Map,即OgnlContext对象  
    10             try {  
    11                 //省略...  
    12                 ValueStack stack = ac.getValueStack();//获取值栈  
    13                 setParameters(action, stack, parameters);//为值栈设置参数  
    14             } finally {  
    15                 //省略...  
    16             }  
    17         }  
    18     }  
    19     return invocation.invoke();//调用下一个拦截器  
    20 }  

    可以知道为什么要实现自动赋值,只需要实现modelDriven接口就行了

    其中最重要逻辑代码是setParometers()方法

     1 protected void setParameters(Object action, ValueStack stack, final Map<String, Object> parameters) {  
     2     ParameterNameAware parameterNameAware = (action instanceof ParameterNameAware)  
     3             ? (ParameterNameAware) action : null;//判断Action有无实现ParameterNameAware接口  
     4   
     5     Map<String, Object> params;  
     6     Map<String, Object> acceptableParameters;//合法参数集合  
     7     //判断参数设置是否有序,ordered默认为false,即无序  
     8     if (ordered) {  
     9         params = new TreeMap<String, Object>(getOrderedComparator());//如果有序则要获取比较器  
    10         acceptableParameters = new TreeMap<String, Object>(getOrderedComparator());  
    11         params.putAll(parameters);  
    12     } else {  
    13         params = new TreeMap<String, Object>(parameters);  
    14         acceptableParameters = new TreeMap<String, Object>();  
    15     }  
    16     //迭代请求参数  
    17     for (Map.Entry<String, Object> entry : params.entrySet()) {  
    18         String name = entry.getKey();  
    19         //判断参数是否合法,如果Action实现了ParameterNameAware则acceptableName(name)返回true且parameterNameAware.acceptableParameterName(name)  
    20         //也返回true该参数才是合法的;如果Action没有实现ParameterNameAware则参数是否合法由acceptableName(name)方法决定  
    21         boolean acceptableName = acceptableName(name)  && (parameterNameAware == null  || parameterNameAware.acceptableParameterName(name));  
    22         //如果参数合法  
    23         if (acceptableName) {  
    24             acceptableParameters.put(name, entry.getValue());//把合法参数添加到合法参数集合中  
    25         }  
    26     }  
    27   
    28     ValueStack newStack = valueStackFactory.createValueStack(stack);  
    29     //省略...  
    30     for (Map.Entry<String, Object> entry : acceptableParameters.entrySet()) {//迭代合法参数  
    31         String name = entry.getKey();//参数名  
    32         Object value = entry.getValue();//参数值  
    33         try {  
    34             newStack.setValue(name, value);//将该参数设置到ValueStack中  
    35         } catch (RuntimeException e) {  
    36             //省略...  
    37         }  
    38     }  
    39     //省略...  
    40     //看该方法的名称是将合法参数添加到ActionContext中,但在该拦截器中,该方法为空实现,无任何代码  
    41     //该方法被声明为protected,即子类可以覆盖该方法以改变行为  
    42     addParametersToContext(ActionContext.getContext(), acceptableParameters);  
    43 }  

    先判断提交过来的参数是否合法,因为提交过来的参数会影响到值栈所以struts2要对提交过来的参数进行合法性检查,以防止恶意用户的攻击,凡是请求参数中表达式中含有等号(=),逗号(,),#号(#)的都是非法表达式

    至于怎么判断是否合法,我已经没兴趣了,知道是acceptableName(name)方法决定的。


    了解了这么多感觉用的更随心所欲了。急需做无聊的毕业设计


    欲为大树,何与草争;心若不动,风又奈何。
  • 相关阅读:
    关于ListView的注意点
    推荐一波 瀑布流的RecylceView
    RecycleView的简单应用
    Java Junit单元测试
    Java 2 个 List 集合数据求并、补集操作
    Java @Validated 遇到的大坑
    Java中的Validated验证
    使用一条sql语句查询多表的总数
    Java thymeleaf模板获取资源文件的内容
    Java热启动
  • 原文地址:https://www.cnblogs.com/admln/p/aboutStruts2ModelDriven.html
Copyright © 2020-2023  润新知