以前使用struts2 的 2.3.4 版本,做的一个项目,使用了stuts2的 Rest与Convention插件,然后动态访问某个action中的方法时,都是使用 “!” 去进行指定的,如
http://127.0.0.1:7070/oa/login!login
这样的话,convention插件会自动去查找 LoginAction 中的 login() 方法。
这样做一直没什么问题。但昨天将struts2的版本升级到 2.3.20之后,再去访问这个URL的时候,一直报下面这个错
java.lang.NoSuchMethodException: com.test.action.LoginAction.create()
很是纳闷,这是为什么呢?
后来在struts2官方文档上找到如下的这段注释:
This Restful action mapper enforces Ruby-On-Rails Rest-style mappings. If the method is not specified (via '!' or 'method:' prefix), the method is "guessed" at using ReST-style conventions that examine the URL and the HTTP method. Special care has been given to ensure this mapper works correctly with the codebehind plugin so that XML configuration is unnecessary.
它说如果URL没有使用 “!” 或者 "method:" 去指定要访问方法时,会基于REST风格去“猜测”要执行的方法。即按照下面所列的规则去猜测:
这样就对得上了,我的LOGIN请求是以POST方式发送的,所以被对应到了 create() 方法。
但是,我的URL里明明就通过“!”指定了要访问的方法为 login() 了啊,为什么不起作用呢?没办法 只好进行debug了。果然,发现了下面的这段处理:
org.apache.struts2.dispatcher.mapper.DefaultActionMapper.parseActionName protected ActionMapping parseActionName(ActionMapping mapping) { if (mapping.getName() == null) { return null; } if (allowDynamicMethodCalls) { // handle "name!method" convention. String name = mapping.getName(); int exclamation = name.lastIndexOf("!"); if (exclamation != -1) { mapping.setName(name.substring(0, exclamation)); mapping.setMethod(name.substring(exclamation + 1)); } } return mapping; }
它的if语句判断了“allowDynamicMethodCalls”是不是true,是true的话,才会去截取“!”后的方法名作为要执行的方法名。那么“allowDynamicMethodCalls”又是什么呢,它的值是怎么设定的呢?请看:
@Inject(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION) public void setAllowDynamicMethodCalls(String allow) { allowDynamicMethodCalls = "true".equalsIgnoreCase(allow); }
也就是说它的值是由strtus2进行inject 的,inject的字段为“StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION”,而这个“StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION”就是
/** Allows one to disable dynamic method invocation from the URL */ public static final String STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION = "struts.enable.DynamicMethodInvocation";
看到这,大家应该看明白了吧?
它就是“default.properties”中的“struts.enable.DynamicMethodInvocation”这个配置项。
(PS:这份文件在 struts2-core-xxxxx.jar 的 “org.apache.struts2” 目录下)
在2.3.4中,这个配置项默认是 true,所以以前的项目运行是没有问题的,
而在2.3.20版本中,这个值默认是false,所以会报错。
那要怎么做呢?其实很简单啦,只要在"struts.xml"覆盖一下就可以了:
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
这个例子告诉我们,你要哪个功能,最后将其配置项明确的配置出来,不要依赖框架本身提供的默认值,谁知道框架会不会改它的默认值呢?