首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

理解Struts2的Action中的setter方法是如何工作的

2012-06-29 
理解Struts2的Action中的setter方法是怎么工作的接触过webwork和Struts2的同行都应该知道,提交表单的时候,

理解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" name="code">//com.opensymphony.xwork2.interceptor.ParametersInterceptor.java//主要代码如下://...? @Override public String doIntercept(ActionInvocation invocation) throws Exception { Object action = invocation.getAction(); if (!(action instanceof NoParameters)) { ActionContext ac = invocation.getInvocationContext(); final Map<String, Object> parameters = retrieveParameters(ac); if (LOG.isDebugEnabled()) { LOG.debug("Setting params " + getParameterLogMap(parameters)); } if (parameters != null) { Map<String, Object> contextMap = ac.getContextMap(); try { ReflectionContextState.setCreatingNullObjects(contextMap, true); ReflectionContextState.setDenyMethodExecution(contextMap, true); ReflectionContextState.setReportingConversionErrors(contextMap, true); ValueStack stack = ac.getValueStack(); setParameters(action, stack, parameters); } finally { ReflectionContextState.setCreatingNullObjects(contextMap, false); ReflectionContextState.setDenyMethodExecution(contextMap, false); ReflectionContextState.setReportingConversionErrors(contextMap, false); } } } return invocation.invoke(); } protected void setParameters(Object action, ValueStack stack, final Map<String, Object> parameters) { ParameterNameAware parameterNameAware = (action instanceof ParameterNameAware) ? (ParameterNameAware) action : null; Map<String, Object> params; Map<String, Object> acceptableParameters; if (ordered) { params = new TreeMap<String, Object>(getOrderedComparator()); acceptableParameters = new TreeMap<String, Object>(getOrderedComparator()); params.putAll(parameters); } else { params = new TreeMap<String, Object>(parameters); acceptableParameters = new TreeMap<String, Object>(); } for (Map.Entry<String, Object> entry : params.entrySet()) { String name = entry.getKey(); boolean acceptableName = acceptableName(name) && (parameterNameAware == null || parameterNameAware.acceptableParameterName(name)); if (acceptableName) { acceptableParameters.put(name, entry.getValue()); } } ValueStack newStack = valueStackFactory.createValueStack(stack); boolean clearableStack = newStack instanceof ClearableValueStack; if (clearableStack) { //if the stack's context can be cleared, do that to prevent OGNL //from having access to objects in the stack, see XW-641 ((ClearableValueStack)newStack).clearContextValues(); Map<String, Object> context = newStack.getContext(); ReflectionContextState.setCreatingNullObjects(context, true); ReflectionContextState.setDenyMethodExecution(context, true); ReflectionContextState.setReportingConversionErrors(context, true); //keep locale from original context context.put(ActionContext.LOCALE, stack.getContext().get(ActionContext.LOCALE)); } boolean memberAccessStack = newStack instanceof MemberAccessValueStack; if (memberAccessStack) { //block or allow access to properties //see WW-2761 for more details MemberAccessValueStack accessValueStack = (MemberAccessValueStack) newStack; accessValueStack.setAcceptProperties(acceptParams); accessValueStack.setExcludeProperties(excludeParams); } for (Map.Entry<String, Object> entry : acceptableParameters.entrySet()) { String name = entry.getKey(); Object value = entry.getValue(); try { newStack.setParameter(name, value); } catch (RuntimeException e) { if (devMode) { String developerNotification = LocalizedTextUtil.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}", new Object[]{ "Unexpected Exception caught setting '" + name + "' on '" + action.getClass() + ": " + e.getMessage() }); LOG.error(developerNotification); if (action instanceof ValidationAware) { ((ValidationAware) action).addActionMessage(developerNotification); } } } } if (clearableStack && (stack.getContext() != null) && (newStack.getContext() != null)) stack.getContext().put(ActionContext.CONVERSION_ERRORS, newStack.getContext().get(ActionContext.CONVERSION_ERRORS)); addParametersToContext(ActionContext.getContext(), acceptableParameters); }//...

?

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

?

(2) Spring配置bean注入到Action中
来看一个简单的Action类:

package com.liany.demo.pubs.org.employee.action;import java.util.List;import com.opensymphony.xwork2.ActionSupport;import com.liany.demo.pubs.org.employee.model.Employee;import com.liany.demo.pubs.org.employee.service.EmployeeService;public class EmployeeAction extends ActionSupport{private EmployeeService employeeService;private List list; private Employee employee = new Employee();  public StringReader getStringReader() {StringReader is = null;try {is = new StringReader(xmlBuf.toString());} catch (Exception e) {e.printStackTrace();}return is;}public Employee getEmployee() {return employee;}public void setEmployee(Employee employee) {this.employee = employee;} public List getList() {return list;}public void setEmployeeService(EmployeeService employeeService) {this.employeeService = employeeService;}public String execute(){//列表list = this.employeeService.getEmployees();return "list";}public String view(){employee = this.employeeService.getEmployeeById(employee.getId());return "view";}public String edit(){if(employee.getId()!=null){//修改employee = this.employeeService.getEmployeeById(employee.getId());}else{//新增employee.setId(null);}return "input";}public String save(){this.employeeService.saveEmployee(employee);return "repage";}public String delete(){this.employeeService.deleteEmployeeById(employee.getId());return "repage";}}

?

上面Action中的employeeService对象其实是在Spring配置文件中声明的bean,
代码中给它定义一个public的setEmployeeService()方法,这样就可以将bean实例注入到
Action中的实例中,这个功能是在Struts过虑器初始化的时候初始化了一个全局变量,
从而使得调用action时,从spring ioc容器中找到这个bean,再set给action对象。
配置文件是在struts.properties文件中声明:
struts.objectFactory = spring
struts.objectFactory.spring.autoWire = name

?

好了先研究到这里, 有兴趣的朋友可以交流交流...

?

?

热点排行