锁定老帖子 主题:Struts2释疑之一
精华帖 (2) :: 良好帖 (2) :: 新手帖 (1) :: 隐藏帖 (7)
|
|
---|---|
作者 | 正文 |
发表时间:2010-09-06
最后修改:2010-09-06
1、Struts2在web.xml中配置为“/*”和“*.action,*.jsp”的差别。 2、There is no Action mapped for namespace / and action name ...的问题。 分析(环境是Struts2.1.8.1): Struts2过滤器的配置有2种方式: <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> 那么这两种方式的配置,究竟有什么差别呢? 首先,假如配置方式是*.action的话,一般应当同时配置*.jsp,因为如果不通过action而直接访问jsp页面的话,Struts2标签在解析的时候会获取当前线程ThreadLocal中的Dispatcher。而Dispatcher是在Struts过滤器中预设的。代码如下: public static ValueStack getStack(PageContext pageContext) { HttpServletRequest req = (HttpServletRequest) pageContext.getRequest(); ValueStack stack = (ValueStack) req.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); if (stack == null) { HttpServletResponse res = (HttpServletResponse) pageContext.getResponse(); Dispatcher du = Dispatcher.getInstance(); if (du == null) { throw new ConfigurationException("The Struts dispatcher cannot be found. This is usually caused by "+ "using Struts tags without the associated filter. Struts tags are only usable when the request "+ "has passed through its servlet filter, which initializes the Struts dispatcher needed for this tag."); } //略... 除了为当前线程预设Dispatcher以外,Struts2对“/*”的请求,在完成普通的“*.action”过滤的基础上,另外提供2点功能: 第1点用于访问classpath中特定的静态资源; 第2点支持无后缀名的Action请求; Struts2的标签有时候需要某些CSS、JS文件的支持,比如<s:head/>标签,可能就转换成: <link rel="stylesheet" href="/demo/struts/xhtml/styles.css" type="text/css"/> <script src="/demo/struts/utils.js" type="text/javascript"></script> 第1点功能带来的好处是可以把这些Struts2框架用到的CSS、JS文件打包在Struts2-core-***.jar文件中分发,使得Struts2的发布包对开发人员而言更加简洁。 下面看一下StrutsPrepareAndExecuteFilter是怎样实现的: ①将Dispatcher预设到线程的ThreadLocal变量上; ②对于Action请求,直接execute.executeAction(request,response,mapping); ③如果是/struts、或者/static开始的资源,则在classpath下查找特定的包下面的匹配资源; ④其他的所有资源(包括直接访问的JSP、以及其他静态资源)转交过滤器链的下一个环节处理:chain.doFilter(request, response); 上面所说的特定包,是指在 <filter> <filter-name>struts2</filter-name> <filter-class> org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </filter-class> <init-param> <param-name>packages</param-name> <param-value>eee</param-value> </init-param> </filter> 中通过packages参数指定的包、以及 "org.apache.struts2.static template org.apache.struts2.interceptor.debugging static"这4个包。 由于packages可配置,从而,如果有自己的classpath上的资源需要访问,或者需要更改Struts本身的静态资源时,只要把Classpath下相应的package设置在过滤器的初始参数中即可(这一条看上去好像没什么用处)。 上面是使用/*时对静态资源的访问,那么使用*.action时如果需要的话,如何访问静态资源呢? 很简单,只要把需要用到的静态资源解压缩到WebContent/struts目录下即可。 第2点“支持无后缀名的Action请求”经常带来一些混乱,最典型的就是“/*”错误地拦截了其他的映射为无后缀名的Servlet请求。比如DWR、FCKEditor等都存在这种问题。 比如,当访问“/demo/dwr”时,正常情况应该显示当前系统中对外暴露的JS方法的列表,但在Struts2的默认配置下,却得到“There is no Action mapped for namespace / and action name dwr.” 又比如在默认配置下,访问http://localhost:8080/demo/hello.action 和访问http://localhost:8080/demo/hello这两者是等同的。 当然,也只有无后缀名的URL请求才会被Struts2当做是Action,这也是为什么/dwr无法访问,然而/dwr/interface.js可以访问的原因。 具体的,看一下下面的代码就明白了: //Struts2默认将“*.action”或者无后缀的URL当做Action protected List<String> extensions = new ArrayList<String>() {{ add("action"); add("");}}; protected String dropExtension(String name, ActionMapping mapping) { if (extensions == null) { return name; } for (String ext : extensions) { if ("".equals(ext)) { // This should also handle cases such as /foo/bar-1.0/description. It is tricky to distinquish /foo/bar-1.0 but perhaps adding a numeric check in the future could work // request uri如果不包含扩展名的话,则匹配此情况 int index = name.lastIndexOf('.'); if (index == -1 || name.indexOf('/', index) >= 0) { return name; } } else { String extension = "." + ext; if (name.endsWith(extension)) { name = name.substring(0, name.length() - extension.length()); mapping.setExtension(ext); return name; } } } return null; } 那么,怎么解决此问题呢? 有2种办法。 第1种很简单,在Struts.properties中定义: struts.action.extension = action即可解决此问题。 Struts2缺省配置对应于: struts.action.extension = action,(注意后面有个逗号) 第2种是在Struts.properties中设置: struts.action.excludePattern = /dwr.*,/webEditor.*(注意,这儿是正则表达式,不是URL匹配模式,所以要写/dwr.*而不是/dwr/*) 这种写法应配置StrutsPrepareAndExecuteFilter,配置FilterDispatcher是无效的。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-09-07
折腾,两个问题都不是要看什么源代码的问题。
|
|
返回顶楼 | |
发表时间:2010-09-07
只是一个web.xml配置的问题。
着重点在于web容器解析web.xml |
|
返回顶楼 | |
发表时间:2010-09-07
lz的总结还是不错的,我以前总是为这个错误头疼半天。
最烦人的是 访问根目录,比如说http://localhost:8080/struts2_project/,也会弹出2、There is no Action mapped for namespace / and action name ...的问题。 我想lz的总结会给我一点启示。 |
|
返回顶楼 | |
发表时间:2010-09-07
最后修改:2010-09-07
说明问题是不错的,不过实际上是不需要看什么源码的,servlet规范中关于url-pattern的规定清楚,及struts.action.extension属性理解清楚就行了。
还有为什么要配置*.jsp? 如果jsp是作为mvc的view,就应该放在WEB-INF目录下保护起来,如果是独立的页面,也不需要struts管(只要你不去配struts.action.extension=xxx,jsp, 自找麻烦)的。 |
|
返回顶楼 | |
发表时间:2010-09-07
两个问题很清楚怎么解决的,但第一次看这些底层的东西,受益匪浅,谢谢
Good Luck! |
|
返回顶楼 | |
发表时间:2010-09-07
lewisw 写道 servlet规范中关于url-pattern的规定清楚
第1个问题想说明的不是servlet规范中url-pattern的用法(这一点我想只要不是弱智,应该都明白),而是说为什么*.action映射还不能满足Struts2的要求,还需要使用/*作为filter-mapping? 这个问题困扰我比较长时间了,我现在的所能得到的结论就是 使用/*最主要的用处就是处理Struts2-core-***.jar包中的静态资源。 主要是为了减少配置。不然的话,需要同时配置*.action、/struts(或者/static)、(*.jsp特殊情况下需要)为filter-mapping。 lewisw 写道 及struts.action.extension属性理解清楚
这一点我想很多人都没有意识到struts.action.extension是支持空缺后缀的(而且要命的是,这是缺省情况)。 Struts2缺省的配置可以看作是(或者等价于)struts.action.extension=action,(最后有一个逗号) 就是这个逗号导致There is no Action mapped for namespace / and action name ...的问题。 这也是我非常郁闷的,不知道Struts2为何要这样做。 这个问题网上随便一搜大把,但很少有说清楚产生问题的真正原因的。 上面的问题不看源码我估计自己是弄不清楚的了。 lewisw 写道 还有为什么要配置*.jsp?
我个人不赞成从浏览器直接访问JSP页面。但是假如某人想要这么做的话,不配置/*就必须配置*.jsp, 这也是配置/*和配置*.action时应该要知道的差别。 |
|
返回顶楼 | |
发表时间:2010-09-07
其实lz总结的不错,思考定位也很准确,确实解决了新手使用struts2时候遇到的一些问题,我觉得很不错。希望大家多给予鼓励,如果lz说的有偏颇之处或者不全,大家尽可指出,但是如果片面的就去评论,难免会有偏颇之处,只是个人的一点看法。
总之,希望楼主再接再厉,呵呵 |
|
返回顶楼 | |
发表时间:2010-09-07
lewisw 写道 说明问题是不错的,不过实际上是不需要看什么源码的,servlet规范中关于url-pattern的规定清楚,及struts.action.extension属性理解清楚就行了。
还有为什么要配置*.jsp? 如果jsp是作为mvc的view,就应该放在WEB-INF目录下保护起来,如果是独立的页面,也不需要struts管(只要你不去配struts.action.extension=xxx,jsp, 自找麻烦)的。 严重同意 |
|
返回顶楼 | |
发表时间:2010-09-08
最后修改:2010-09-08
sswh 写道 这一点我想很多人都没有意识到struts.action.extension是支持空缺后缀的(而且要命的是,这是缺省情况)。 Struts2缺省的配置可以看作是(或者等价于)struts.action.extension=action,(最后有一个逗号) 就是这个逗号导致There is no Action mapped for namespace / and action name ...的问题。 这也是我非常郁闷的,不知道Struts2为何要这样做。 这个问题网上随便一搜大把,但很少有说清楚产生问题的真正原因的。 上面的问题不看源码我估计自己是弄不清楚的了。 / 是web.xml的welcome-file-list部分设定的默认页面。struts确实没必要做mapping。做了反而会跟Web容器冲突。 当然welcome-file也可以设定action的url <welcome-file-list> <welcome-file>login.action</welcome-file> </welcome-file-list> |
|
返回顶楼 | |