目前我在项目中使用 Struts 2.3.12,一切工作正常。
现在,我需要将Struts版本升级到2.3.20以解决一些安全问题。
我在项目的
pom.xml
中将 Struts 和所需的 Struts 插件版本更改为 2.3.20 并构建了项目 war。
现在,我尝试访问我的应用程序主 URL,但出现以下异常:
没有为与上下文路径
关联的命名空间[/web/public]
和操作名称[reset-password!reset]
映射的操作。 - [未知位置][/ims]
com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:185)
org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:63)
org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:37)
com.opensymphony.xwork2.DefaultActionProxyFactory.createActionProxy(DefaultActionProxyFactory.java:58)
org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:554)
org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
org.displaytag.filter.ResponseOverrideFilter.doFilter(ResponseOverrideFilter.java:125)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
org.josso.tc55.agent.SSOAgentValve.invoke(SSOAgentValve.java:472)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:875)
org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
java.lang.Thread.run(Thread.java:662)
我对发生的事情一无所知。
我查看了 Struts 2.3.20 的发行说明,但没有得到任何提示。
我正在使用
strust2-convention-plugin
。
我正在分享我的
web.xml
和 struts.xml
文件。看起来如下:
web.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="jail" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>ims</display-name>
<!-- JCaptcha servlet mapping -->
<servlet>
<servlet-name>jcaptcha</servlet-name>
<servlet-class>com.sapienza.jail.controller.jcaptcha.JailImageCaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jcaptcha</servlet-name>
<url-pattern>/web/public/jcaptcha.jpg</url-pattern>
</servlet-mapping>
<!-- Filters -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/web/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>ResponseOverrideFilter</filter-name>
<filter-class>org.displaytag.filter.ResponseOverrideFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ResponseOverrideFilter</filter-name>
<url-pattern>/web/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/web/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/web/public/*</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>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/struts/*</url-pattern>
</filter-mapping>
<!-- JSP configuration -->
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<el-ignored>false</el-ignored>
<page-encoding>UTF-8</page-encoding>
<include-prelude>/jsp/common/taglibs.jspf</include-prelude>
</jsp-property-group>
</jsp-config>
<welcome-file-list>
<welcome-file>/jsp/common/home.jsp</welcome-file>
</welcome-file-list>
<!-- Spring Listener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- Skin listener -->
<listener>
<listener-class>com.sapienza.jail.listener.ResourceListener</listener-class>
</listener>
<!-- LDAP Synchronisation Listeneer -->
<listener>
<listener-class>com.sapienza.jail.listener.LdapSyncListener</listener-class>
</listener>
<!-- Tiles listener -->
<listener>
<listener-class>org.apache.struts2.tiles.StrutsTilesListener</listener-class>
</listener>
<context-param>
<param-name>org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG</param-name>
<param-value>/WEB-INF/tiles/skins-definitions.xml,/WEB-INF/tiles/pages-definitions.xml</param-value>
</context-param>
<context-param>
<param-name>org.apache.tiles.evaluator.AttributeEvaluator</param-name>
<param-value>org.apache.tiles.evaluator.el.ELAttributeEvaluator</param-value>
</context-param>
</web-app>
struts.xml
:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="struts-default.xml"/>
<constant name="struts.objectFactory" value="spring"/>
<constant name="struts.devMode" value="true"/>
<constant name="struts.convention.default.parent.package" value="base-configuration"/>
<constant name="struts.convention.classes.reload" value="true"/>
<constant name="struts.enableJSONValidation" value="true"/>
<!-- struts configuration common for the whole application -->
<include file="struts-base.xml"/>
</struts>
struts-base.xml
:
<struts>
<!-- This package is abstract. It is not mean to declare any actions, only
common components such as interceptors, global results ... -->
<package name="base-configuration" abstract="true" extends="tiles-default">
<result-types>
<result-type name="jasper" class="org.apache.struts2.views.jasperreports.JasperReportsResult"/>
<result-type name="json" class="org.apache.struts2.json.JSONResult"/>
<result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult"/>
</result-types>
<!-- create a custom paramsPrepareParamsStack using our log4j interceptor -->
<interceptors>
<!-- declaration of the custom interceptor using log4j to log exceptions. -->
<interceptor name="log4jExceptionMappingInterceptor" class="log4jExceptionMappingInterceptor" />
<!-- declaration of the custom security interceptor -->
<interceptor name="securityInterceptor" class="securityInterceptor" />
<!-- declaration of the custom SearchBean interceptor -->
<interceptor name="searchBeanInterceptor" class="searchBeanInterceptor" />
<!-- declaration of the custom WhiteSpaceTrim interceptor -->
<interceptor name="whiteSpaceTrimmerInterceptor" class="whiteSpaceTrimmerInterceptor" />
<!-- Struts2 JSON Validation -->
<interceptor name="jsonValidation" class="org.apache.struts2.json.JSONValidationInterceptor" />
<interceptor-stack name="imsDefaultStack">
<!-- insert log4j interceptor inserted in the custom stack -->
<interceptor-ref name="log4jExceptionMappingInterceptor" />
<!-- insert the custom security interceptor -->
<interceptor-ref name="securityInterceptor" />
<interceptor-ref name="alias" />
<interceptor-ref name="params" />
<interceptor-ref name="servletConfig" />
<interceptor-ref name="prepare" />
<interceptor-ref name="i18n" />
<interceptor-ref name="chain" />
<interceptor-ref name="checkbox" />
<interceptor-ref name="staticParams" />
<interceptor-ref name="params" />
<!-- excludes base CRUD methods from the validation process -->
<!-- validation interceptor triggers the xml validation -->
<interceptor-ref name="validation">
<param name="validateAnnotatedMethodOnly">true</param>
<param name="excludeMethods">input,back,cancel,list,view,initCreate,initUpdate,delete</param>
</interceptor-ref>
<!-- ajax validation interceptor -->
<interceptor-ref name="jsonValidation">
<param name="excludeMethods">input</param>
</interceptor-ref>
<!-- workflow interceptor triggers programmatic validation (calls validate()) -->
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,list,view,initCreate,initUpdate,delete</param>
</interceptor-ref>
</interceptor-stack>
<!-- this new custom stack will be used for public URL -->
<interceptor-stack name="imsNoSecurityStack">
<!-- insert log4j interceptor inserted in the custom stack -->
<interceptor-ref name="log4jExceptionMappingInterceptor" />
<interceptor-ref name="alias" />
<interceptor-ref name="params" />
<interceptor-ref name="servletConfig" />
<interceptor-ref name="prepare" />
<interceptor-ref name="i18n" />
<interceptor-ref name="chain" />
<interceptor-ref name="checkbox" />
<interceptor-ref name="staticParams" />
<interceptor-ref name="params" />
<!-- excludes base CRUD methods from the validation process -->
<!-- validation interceptor triggers the xml validation -->
<interceptor-ref name="validation">
<param name="validateAnnotatedMethodOnly">true</param>
<param name="excludeMethods">input,back,cancel,list,view,initCreate,initUpdate,delete</param>
</interceptor-ref>
<!-- ajax validation interceptor -->
<interceptor-ref name="jsonValidation">
<param name="excludeMethods">input</param>
</interceptor-ref>
<!-- workflow interceptor triggers programmatic validation (calls validate()) -->
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,list,view,initCreate,initUpdate,delete</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- the new custom stack will be the default one used in the sub packages. -->
<default-interceptor-ref name="imsDefaultStack" />
<!-- exception handling -->
<global-results>
<result name="error">/jsp/common/error.jsp</result>
<result name="securityError">/jsp/common/access-denied.jsp</result>
<result name="ldapError">/jsp/common/ldap-connection-error.jsp</result>
</global-results>
<!-- any unhandled exceptions will return the error page displaying the
message of the exception. -->
<global-exception-mappings>
<exception-mapping result="error" exception="java.lang.Exception" />
<exception-mapping result="securityError" exception="com.sapienza.jail.exception.NoApplicationAccess" />
<exception-mapping result="ldapError" exception="com.sapienza.jail.exception.LDAPConnectionException" />
</global-exception-mappings>
</package>
</struts>
我在我的班级中使用基于注释的动作映射,如下所示
@Results({
@Result(name="index", type="tiles", location="testPage"),
@Result(name = "redirect", location = "user/search-user!view", type = "redirectAction")
})
@Namespace("/web/public")
@Action
public class HomeAction extends BaseAction {
private static final Logger logger = Logger.getLogger(HomeAction.class);
private static final String SESSIONBASKET = "userSessionBasket";
//-------------------------------------------------------------------------
// Dependencies injected by spring via setters
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Constructor and methods
//-------------------------------------------------------------------------
public HomeAction() {
}
@Override
public String execute() {
if (isInHttpSession(SESSIONBASKET)){
getSession().removeAttribute(SESSIONBASKET);
}
return result(REDIRECT_RESULT);
}
//-------------------------------------------------------------------------
// Getters and Setters
//-------------------------------------------------------------------------
}
从 struts 2.3.16 升级到 2.3.20 已经很困难了。 不确定我们是否面临同样的问题,但是,我仍然分享对我有用的解决方案。
REST 插件操作,应使用以下约定按后缀进行索引: 例如 struts.convention.action.suffix = 控制器
升级所有 struts2-* jar 文件和 xwork-core.jar 后根本无法工作
日志中没有打印任何内容。
最后看到这篇文章: http://comments.gmane.org/gmane.comp.jakarta.struts.user/186383 “今天早上我在更新了 struts2 后遇到了同样的问题, xwork jar 文件。 我将 asm、asm-commons、asm-tree 和 commons-lang3 jar 文件更新为 那些在 struts-2.3.20-lib.zip 文件中找到的内容,问题就消失了。”
升级asm-*.jar后,问题就消失了。
我唯一无法理解的是,2.3.20 版本降级了一些 jar 文件,例如 commons-validator 降级到 1.3.1(从 1.4.0),common-collections 降级到 1.3.1(从 3.2.1) .
希望它也能帮助您的项目。
干杯
最后我找到了罪魁祸首,这是由于 asm jar 冲突,它在我的应用程序 lib forder 中包含两次版本(3.1 和 5.1)。升级到 struts 2.3.20 后,它正在下载 asm 5.1,并且 asm 3.1 正在从父应用程序 pom 中包含。
您还必须通过在 struts.xml 中添加以下常量来显式启用 DMI。
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>