您的位置:首页 > 编程语言 > Java开发

理解Struts2的Action中的setter方法是怎么工作的

2016-02-28 21:52 399 查看
接触过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代码


//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类:

Java代码


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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: