理解Struts2的Action中的setter方法工作原理

接触过webwork和Struts2的同行都应该知道,

提交表单的时候,只要Action中的属性有setter方法,这些表单数据就可以正确赋值到Action中属性里;
另外对于Spring配置文件中声明的bean,也可以在Action中声明setter方法将其注入到Action实例中。
那么现在要研究:这些是怎么工作的呢?


(1)提交表单时的参数
在struts2-core-2.3.1.2.jar压缩包内的struts-default.xml配置文件中有这个配置:
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
这个拦截器是负责解析请求中的URL参数,并赋值给action中对应的属性

来看代码:

Java代码   收藏代码
  1. //com.opensymphony.xwork2.interceptor.ParametersInterceptor.java  
  2. //主要代码如下:  
  3. //...  
  4.   
  5.     @Override  
  6.     public String doIntercept(ActionInvocation invocation) throws Exception {  
  7.         Object action = invocation.getAction();  
  8.         if (!(action instanceof NoParameters)) {  
  9.             ActionContext ac = invocation.getInvocationContext();  
  10.             final Map<String, Object> parameters = retrieveParameters(ac);  
  11.   
  12.             if (LOG.isDebugEnabled()) {  
  13.                 LOG.debug("Setting params " + getParameterLogMap(parameters));  
  14.             }  
  15.   
  16.             if (parameters != null) {  
  17.                 Map<String, Object> contextMap = ac.getContextMap();  
  18.                 try {  
  19.                     ReflectionContextState.setCreatingNullObjects(contextMap, true);  
  20.                     ReflectionContextState.setDenyMethodExecution(contextMap, true);  
  21.                     ReflectionContextState.setReportingConversionErrors(contextMap, true);  
  22.   
  23.                     ValueStack stack = ac.getValueStack();  
  24.                     setParameters(action, stack, parameters);  
  25.                 } finally {  
  26.                     ReflectionContextState.setCreatingNullObjects(contextMap, false);  
  27.                     ReflectionContextState.setDenyMethodExecution(contextMap, false);  
  28.                     ReflectionContextState.setReportingConversionErrors(contextMap, false);  
  29.                 }  
  30.             }  
  31.         }  
  32.         return invocation.invoke();  
  33.     }  
  34.   
  35.     protected void setParameters(Object action, ValueStack stack, final Map<String, Object> parameters) {  
  36.         ParameterNameAware parameterNameAware = (action instanceof ParameterNameAware)  
  37.                 ? (ParameterNameAware) action : null;  
  38.   
  39.         Map<String, Object> params;  
  40.         Map<String, Object> acceptableParameters;  
  41.         if (ordered) {  
  42.             params = new TreeMap<String, Object>(getOrderedComparator());  
  43.             acceptableParameters = new TreeMap<String, Object>(getOrderedComparator());  
  44.             params.putAll(parameters);  
  45.         } else {  
  46.             params = new TreeMap<String, Object>(parameters);  
  47.             acceptableParameters = new TreeMap<String, Object>();  
  48.         }  
  49.   
  50.         for (Map.Entry<String, Object> entry : params.entrySet()) {  
  51.             String name = entry.getKey();  
  52.   
  53.             boolean acceptableName = acceptableName(name)  
  54.                     && (parameterNameAware == null  
  55.                     || parameterNameAware.acceptableParameterName(name));  
  56.   
  57.             if (acceptableName) {  
  58.                 acceptableParameters.put(name, entry.getValue());  
  59.             }  
  60.         }  
  61.   
  62.         ValueStack newStack = valueStackFactory.createValueStack(stack);  
  63.         boolean clearableStack = newStack instanceof ClearableValueStack;  
  64.         if (clearableStack) {  
  65.             //if the stack's context can be cleared, do that to prevent OGNL  
  66.             //from having access to objects in the stack, see XW-641  
  67.             ((ClearableValueStack)newStack).clearContextValues();  
  68.             Map<String, Object> context = newStack.getContext();  
  69.             ReflectionContextState.setCreatingNullObjects(context, true);  
  70.             ReflectionContextState.setDenyMethodExecution(context, true);  
  71.             ReflectionContextState.setReportingConversionErrors(context, true);  
  72.   
  73.             //keep locale from original context  
  74.             context.put(ActionContext.LOCALE, stack.getContext().get(ActionContext.LOCALE));  
  75.         }  
  76.   
  77.         boolean memberAccessStack = newStack instanceof MemberAccessValueStack;  
  78.         if (memberAccessStack) {  
  79.             //block or allow access to properties  
  80.             //see WW-2761 for more details  
  81.             MemberAccessValueStack accessValueStack = (MemberAccessValueStack) newStack;  
  82.             accessValueStack.setAcceptProperties(acceptParams);  
  83.             accessValueStack.setExcludeProperties(excludeParams);  
  84.         }  
  85.   
  86.         for (Map.Entry<String, Object> entry : acceptableParameters.entrySet()) {  
  87.             String name = entry.getKey();  
  88.             Object value = entry.getValue();  
  89.             try {  
  90.                 newStack.setParameter(name, value);  
  91.             } catch (RuntimeException e) {  
  92.                 if (devMode) {  
  93.                     String developerNotification = LocalizedTextUtil.findText(ParametersInterceptor.class"devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}"new Object[]{  
  94.                              "Unexpected Exception caught setting '" + name + "' on '" + action.getClass() + ": " + e.getMessage()  
  95.                     });  
  96.                     LOG.error(developerNotification);  
  97.                     if (action instanceof ValidationAware) {  
  98.                         ((ValidationAware) action).addActionMessage(developerNotification);  
  99.                     }  
  100.                 }  
  101.             }  
  102.         }  
  103.   
  104.         if (clearableStack && (stack.getContext() != null) && (newStack.getContext() != null))  
  105.             stack.getContext().put(ActionContext.CONVERSION_ERRORS, newStack.getContext().get(ActionContext.CONVERSION_ERRORS));  
  106.   
  107.         addParametersToContext(ActionContext.getContext(), acceptableParameters);  
  108.     }  
  109. //...  

 

上面的代码ValueStack stack = ac.getValueStack();
表明,它是从当前Action上下文获取值栈(其实就类似一个全局Map集合,用来存储参数值或struts上下文全局变量),
然后由判断如果是当前action可以接受的参数(Action中有setter方法)就过滤出来,
调用这句“newStack.setParameter(name, value);”来保存到值栈中,
保存到了值栈中其实action实例的属性就能拿到值了。
最后一句“addParametersToContext(ActionContext.getContext(), acceptableParameters);
表明它还把这些过滤出来的参数保存到了ActionContext上下文中,
这样,如果跳转的类型是forward(服务器内部重定向),
目标url中就会带上上次请求的url的所有有用的参数。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值