接触过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. jquery 判断checkbox是否被选中问题

    1.jquery库2以上 $("#checkbox_check").click(function(){ alert($(this).prop("checked" ...

  2. 域名相关:DNS A记录 NS记录 MX记录 CNAME记录

    1. DNSDNS:Domain Name System 域名管理系统 域名是由圆点分开一串单词或缩写组成的,每一个域名都对应一个惟一的IP地址,这一命名的方法或这样管理域名的系统叫做域名管理系统.D ...

  3. Android模拟器内安装应用

    一.通过apk安装器安装应用 1.下载apk安装器(网上随便搜一个就可以) 2.下载要测试的应用的apk,我这里下载的是微信的apk 3.打开apk安装器,点击右上角的Devices选择要安装到的设备 ...

  4. git的一些常用操作命令

    这些操作命令都是从廖雪峰老师的官网上看过后记下来的,以下是廖雪峰老师的官网,大家可以看看,教程不错~ http://www.liaoxuefeng.com/wiki/00137395163059296 ...

  5. C#aspx页面前台使用<%=%>无法取到后台的值

    检查是不是有拼接问题,正常public和protected修饰的字段或属性均可使用<%=%>.另外,加载(Page_Load)时有没有给它们赋初始值? 答 1)前台页面只能调用本后置代码的 ...

  6. Required String parameter ' ' is not present

    Required String parameter ' ' is not present 报错原因: url中的参数错误. 解决方法: 1.修正url中的参数的值. 2.在Controller层中的@ ...

  7. Extjs面板和布局初探

    面板相当于一张干净的白纸,如果直接在上面添加内容,将很难控制面板中内容的显示位置,面板元素越多就越显得凌乱,所以需要在面板上划分不同的区域,将面板内容展示到希望的位置上.ExtJS通过提供多种布局类来 ...

  8. OC - 缓存 - NSCache - 介绍

  9. Django模型之Meta详解

    Django模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.而可用的选项大致包含以下几类 abstract 这个属性是定义当前的模型是不是一个抽象类.所谓抽象类是不会对应数据 ...

  10. mysql rc模式时binlog_format=row的解释【转】

    总体来说:在 tx_isolation= READ-COMMITTED .binlog_format =statement 的情况下,mysql 没有gap 锁,这样binlog 记录的数据修改的顺序 ...