接触过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中对应的属性

来看代码:

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

上面的代码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类:

  1. package com.liany.demo.pubs.org.employee.action;
  2. import java.util.List;
  3. import com.opensymphony.xwork2.ActionSupport;
  4. import com.liany.demo.pubs.org.employee.model.Employee;
  5. import com.liany.demo.pubs.org.employee.service.EmployeeService;
  6. public class EmployeeAction extends ActionSupport{
  7. private EmployeeService employeeService;
  8. private List list;
  9. private Employee employee = new Employee();
  10. public StringReader getStringReader() {
  11. StringReader is = null;
  12. try {
  13. is = new StringReader(xmlBuf.toString());
  14. } catch (Exception e) {
  15. e.printStackTrace();
  16. }
  17. return is;
  18. }
  19. public Employee getEmployee() {
  20. return employee;
  21. }
  22. public void setEmployee(Employee employee) {
  23. this.employee = employee;
  24. }
  25. public List getList() {
  26. return list;
  27. }
  28. public void setEmployeeService(EmployeeService employeeService) {
  29. this.employeeService = employeeService;
  30. }
  31. public String execute(){
  32. //列表
  33. list = this.employeeService.getEmployees();
  34. return "list";
  35. }
  36. public String view(){
  37. employee = this.employeeService.getEmployeeById(employee.getId());
  38. return "view";
  39. }
  40. public String edit(){
  41. if(employee.getId()!=null){
  42. //修改
  43. employee = this.employeeService.getEmployeeById(employee.getId());
  44. }else{
  45. //新增
  46. employee.setId(null);
  47. }
  48. return "input";
  49. }
  50. public String save(){
  51. this.employeeService.saveEmployee(employee);
  52. return "repage";
  53. }
  54. public String delete(){
  55. this.employeeService.deleteEmployeeById(employee.getId());
  56. return "repage";
  57. }
  58. }

上面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

理解Struts2的Action中的setter方法是怎么工作的的更多相关文章

  1. struts2:数据校验,通过Action中的validate()方法实现校验,图解

    根据输入校验的处理场所的不同,可以将输入校验分为客户端校验和服务器端校验两种.服务器端验证目前有两种方式: 第一种 Struts2中提供了一个com.opensymphony.xwork2.Valid ...

  2. struts2:数据校验,通过Action中的validate()方法实现校验(续:多业务方法时的不同验证处理)

    前文:struts2:数据校验,通过Action中的validate()方法实现校验,图解 如果定义的Action中存在多个逻辑处理方法,且不同的处理逻辑可能需要不同的校验规则,在这种情况下,就需要通 ...

  3. struts2的占位符*在action中的配置方法

    转自:https://blog.csdn.net/u012546338/article/details/68946633 在配置<action> 时,可以在 name,class,meth ...

  4. JavaWeb_(Struts2框架)Action中struts-default下result的各种转发类型

    此系列博文基于同一个项目已上传至github 传送门 JavaWeb_(Struts2框架)Struts创建Action的三种方式 传送门 JavaWeb_(Struts2框架)struts.xml核 ...

  5. struts2开发action 的三种方法以及通配符、路径匹配原则、常量

    struts2开发action 的三种方法 1.继承ActionSupport public class UserAction extends ActionSupport { // Action中业务 ...

  6. 在struts2的action中操作域对象(request、session)

    在struts2的Action中,操作域对象一共有三种方式: 1.ActionContext(与servelt API无关联): //相当于request ActionContext.getConte ...

  7. Struts2中使用execAndWait后,在 Action中调用getXXX()方法报告java.lang.NullPointerException异常的原因和解决方法

    使用 Struts2 编写页面,遇到一个要长时间运行的接口,因此增加了一个execAndWait ,结果在 Action 中调用 getContext()的时候报告异常 ActionContext c ...

  8. struts2对action中的方法进行输入校验---xml配置方式(3)

    上面两篇文章已经介绍了通过编码java代码的方式实现action方法校验,这里我们介绍第二种方式:xml配置文件 首先我们来看一个样例: ValidateAction.java: package co ...

  9. struts2对action中的方法进行输入校验(2)

    struts2输入校验流程: 1.类型转换器对请求參数运行类型转换,并把转换后的值赋给aciton中的属性 2.假设在运行类型转换的过程中出现异常,系统会将异常信息保存到ActionContext, ...

随机推荐

  1. window环境mysql解压版配置

    1.下载并解压 到官网下载mysql-5.5.10-win32.zip,然后将mysql解压到任意路径,如:C:\mysql-5.5.10-win32 2.设置环境变量 打开计算机->属性-&g ...

  2. 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.jee.server:Weixin' did not find a matching property.

    警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclips ...

  3. ios 8 联系人ABPeoplePickerNavigationController

    一. ios 联系人ABPeoplePickerNavigationControllerDelegate方法,新添加下面两个联系人选中方法,适配iOS8需要实现 // Called after a p ...

  4. python之event【事件】

    # 线程之间用于交互的一个对象,这个event是一个内部的标签,线程可以等待这个标签的状态 #举个例子,比如红绿灯是一个线程,三辆汽车是3个线程,如果为红灯,则三个汽车的线程必须 #要停止,如果是绿灯 ...

  5. 识别名人 · Find the Celebrity

    [抄题]: 假设你和 n 个人在一个聚会中(标记为 0 到 n - 1),其中可能存在一个名人.名人的定义是所有其他 n - 1 人都认识他/她,但他/她不知道任何一个.现在你想要找出这个名人是谁或者 ...

  6. [leetcode]295. Find Median from Data Stream数据流的中位数

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  7. POJ 2585.Window Pains 拓扑排序

    Window Pains Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1888   Accepted: 944 Descr ...

  8. 如何看待阿里 AI 每秒制作 8000 张海报?

    看了其他设计老师们的回答,给了我一些启发,于是更新一波. 设计本质上是产品和服务的一部分,如果只站在设计师角度看这问题,免不了会有一种被取代的危机感. 来源:千锋UI ​但如果站在整个产品和服务的角度 ...

  9. JMeter中用java修改文件名称

    import java.io.File; String NewDataPath=bsh.args[0]; File SrcFile= new File(NewDataPath+"AutoTe ...

  10. 史上最全的Android开发学习教程集锦【初学者】

    根据Google的报告,截止2017年5月为止,Android活跃用户已超过20亿,并还在持续增长中.Android系统在几个主要的市场上已超过了iOS系统,特别是在美国,欧洲和日本,然而苹果确实在中 ...