Apache Struts 配置参数详解

Struts 6.12.0 配置参数详解:配置体系,default.properties 内置 57 项默认值,devMode/action.extension/multipart 参数实测,拦截器与结果类型,全程实测。

Apache StrutsApache Struts2026/10/12

Apache Struts 配置参数详解

目标:基于 struts2-core 6.12.0 的 jar 内 default.properties 与 struts-default.xml 实取,以及在 Ubuntu 22.04.5 + Tomcat 9.0.58(JVM 堆 -Xms256m -Xmx512m)环境的逐项实测整理。覆盖配置体系与加载顺序、核心常量参数(含默认值、配置写法与实测效果)、OGNL/UI/Spring 参数、内置拦截器与结果类型,以及参数修改后的生效方式与常见问题。所有命令与回显均实测取得。

一、配置体系概览

1.1 配置文件层级

层级位置作用
default.propertiesstruts2-core jar 内 org/apache/struts2/default.properties框架内置默认值(共 57 个 struts.* 键)
struts-default.xmlstruts2-core jar 内拦截器、拦截器栈、结果类型声明
struts.xml应用 src/main/resources/struts.xml(打包后在 WEB-INF/classes)应用配置:常量覆盖、package、action
web.xml应用 WEB-INF/web.xml注册 StrutsPrepareAndExecuteFilter 入口

加载顺序为从上到下,struts.xml 中的 <constant> 会覆盖 default.properties 的同名默认值。

1.2 查看内置默认参数

从本地 Maven 仓库的 jar 中直接解出 default.properties 查看:

cd /tmp && unzip -o -q /root/.m2/repository/org/apache/struts/struts2-core/6.12.0/struts2-core-6.12.0.jar org/apache/struts2/default.properties
grep -E '^struts\.(devMode|action\.extension|multipart\.(maxSize|saveDir)|enable\.DynamicMethodInvocation) *=' org/apache/struts2/default.properties

实测回显(关键 5 键的内置默认值):

struts.multipart.saveDir=
struts.multipart.maxSize=2097152
struts.action.extension=action,,
struts.enable.DynamicMethodInvocation = false
struts.devMode = false

统计全部键数量:

grep -c '^struts\.' org/apache/struts2/default.properties

实测回显:

57

💡 说明:default.properties 中共 57 个 struts.* 键,下文按用途分组摘取实测值。注意文件中部分键的等号两侧带空格(如 struts.devMode = false),为 jar 内原文,照实呈现。

二、核心常量参数详解

2.1 struts.devMode(开发模式)

  • 内置默认值:false
  • 作用:开启后 OGNL 安全策略使用 devMode 专属排除清单,异常信息更详细,便于开发排查。
  • struts.xml 写法:<constant name="struts.devMode" value="true"/>

实测:设置 true 并部署后,服务日志出现告警(journalctl -u tomcat9):

2026-10-12 05:18:07,504 WARN  [Catalina-utility-1] ognl.SecurityMemberAccess (SecurityMemberAccess.java:544) - Working in devMode, using devMode excluded classes and packages!

生产环境必须关闭(false),该 WARN 也会随之消失。

2.2 struts.action.extension(Action 后缀)

  • 内置默认值:action,,(支持 .action 与无后缀)
  • 作用:限定哪些 URL 后缀会交给 Struts 处理,逗号分隔,末尾空项代表「无后缀也匹配」。
  • struts.xml 写法:<constant name="struts.action.extension" value="do,action,"/>

实测:设置为 do,action, 并重新打包部署后,.action 与 .do 均可访问:

curl -s -o /dev/null -w 'hello.action: HTTP %{http_code}\n' 'http://localhost:8080/struts2-demo/hello.action?name=X'
curl -s -o /dev/null -w 'hello.do: HTTP %{http_code}\n' 'http://localhost:8080/struts2-demo/hello.do?name=Y'

实测回显:

hello.action: HTTP 200
hello.do: HTTP 200

⚠️ 注意:若把空后缀去掉(如 do,action),无后缀 URL 将不再映射,依赖无后缀 URL 的单元测试会抛 NullPointerException,详见 8.1 节实测报错。

2.3 struts.multipart.maxSize(上传大小上限)

  • 内置默认值:2097152(2MB,整个请求的上限,单位字节)
  • 作用:限制 multipart 请求总大小,超限时上传拦截器捕获错误并返回 input。
  • struts.xml 写法:<constant name="struts.multipart.maxSize" value="10485760"/>

实测(默认值时上传 3MB,页面回显错误原文):

curl -s -F 'upload=@/tmp/big.bin;type=application/octet-stream' 'http://localhost:8080/struts2-demo/upload.action' | grep -A2 'errorMessage'

实测回显:

        <ul class="errorMessage">
            <li><span>Request exceeded allowed size limit! Max size allowed is: 2,097,152 but request was: 3,145,929!</span></li>       </ul>

调整到 10485760 并重新打包部署后,同一文件上传成功:

curl -s -F 'upload=@/tmp/big.bin;type=application/octet-stream' 'http://localhost:8080/struts2-demo/upload.do' | grep -E 'Saved'

实测回显:

<p>Saved big.bin (3145728 bytes, content-type=application/octet-stream) to /tmp/big.bin</p>

2.4 struts.multipart.saveDir(上传临时目录)

  • 内置默认值:空字符串(回退到 Web 应用临时目录 javax.servlet.context.tempdir)
  • 作用:multipart 请求体在解析阶段的暂存目录。
  • struts.xml 写法:<constant name="struts.multipart.saveDir" value="/data/struts-upload-tmp"/>

实测:未设置时服务日志提示(INFO 级,不影响功能):

2026-10-12 05:21:37,936 INFO  [http-nio-8080-exec-9] dispatcher.Dispatcher (Dispatcher.java:1027) - Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir

2.5 struts.enable.DynamicMethodInvocation(动态方法调用)

  • 内置默认值:false
  • 作用:控制 Action!method 感叹号语法是否可用。关闭时该形态 URL 直接 404,是 Struts 6.x 的安全默认。
  • struts.xml 写法:<constant name="struts.enable.DynamicMethodInvocation" value="false"/>

实测(保持默认关闭):

curl -s -o /dev/null -w 'HTTP %{http_code}\n' 'http://localhost:8080/struts2-demo/example/Login!execute.action'

实测回显:

HTTP 404

按方法分发推荐使用通配符映射(如 <action name="Login_*" method="{1}">),不建议打开 DMI。

三、OGNL 与表达式相关参数

jar 内 default.properties 实取值(grep 原文):

struts.ognl.allowStaticFieldAccess=true
struts.ognl.logMissingProperties=false
struts.ognl.expressionCacheType=wtlfu
struts.ognl.expressionCacheMaxSize=10000
struts.ognl.beanInfoCacheType=wtlfu
struts.ognl.beanInfoCacheMaxSize=10000
struts.ognl.expressionMaxLength=256
键默认值说明
struts.ognl.allowStaticFieldAccesstrue是否允许 OGNL 访问静态字段(如 @class@field)
struts.ognl.logMissingPropertiesfalse目标对象缺失属性时是否记录日志
struts.ognl.expressionCacheTypewtlfuOGNL 表达式缓存类型
struts.ognl.expressionCacheMaxSize10000表达式缓存上限
struts.ognl.beanInfoCacheTypewtlfuBeanInfo 缓存类型
struts.ognl.beanInfoCacheMaxSize10000BeanInfo 缓存上限
struts.ognl.expressionMaxLength256OGNL 表达式最大长度,超长直接拒绝(安全防护)

四、UI 与 URL 及其他参数

jar 内 default.properties 实取值(grep 原文):

struts.locale.validateRequestLocale=false
struts.ui.theme=xhtml
struts.ui.theme.expansion.token=~~~
struts.url.http.port = 80
struts.url.https.port = 443
struts.date.formatter=dateTimeFormatter
键默认值说明
struts.locale.validateRequestLocalefalse是否校验请求携带的 locale 参数合法性
struts.ui.themexhtmls: 标签默认渲染主题(另有 simple、css_xhtml 等)
struts.ui.theme.expansion.token~~~主题展开 token
struts.url.http.port80s:url 生成 http 链接使用的端口
struts.url.https.port443s:url 生成 https 链接使用的端口
struts.date.formatterdateTimeFormatters:date 渲染使用的格式化器

💡 实测佐证:默认 xhtml 主题下,s:form/s:file/s:submit 渲染出的登录表单带 tdLabel/label/formButton 等布局结构(属 xhtml 主题自动生成的表格布局);切换主题时修改 struts.ui.theme 即可。

五、Spring 集成参数

jar 内 default.properties 实取值(grep 原文,未引入 Spring 依赖时不生效,保留默认即可):

struts.objectFactory.spring.autoWire = name
struts.objectFactory.spring.useClassCache = true
struts.objectFactory.spring.autoWire.alwaysRespect = false
struts.objectFactory.spring.enableAopSupport = false
键默认值说明
struts.objectFactory.spring.autoWirenameSpring 装配方式(name/byName/type/auto/constructor)
struts.objectFactory.spring.useClassCachetrue是否缓存已创建的 bean 类
struts.objectFactory.spring.autoWire.alwaysRespectfalse装配时是否始终尊重 Spring bean 定义
struts.objectFactory.spring.enableAopSupportfalse是否启用 Spring AOP 支持

六、struts-default.xml:拦截器与结果类型

从 jar 中解出 struts-default.xml 查看:

cd /tmp && unzip -o -q /root/.m2/repository/org/apache/struts/struts2-core/6.12.0/struts2-core-6.12.0.jar struts-default.xml
grep -c 'interceptor name=' struts-default.xml

实测回显:

40

6.1 内置拦截器清单(实取节选 25 个)

grep -oE '<interceptor name="[^"]+" class="[^"]+"' struts-default.xml | head -25

实测回显:

<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"
<interceptor name="coep" class="org.apache.struts2.interceptor.CoepInterceptor"
<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"
<interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"
<interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor"
<interceptor name="coop" class="org.apache.struts2.interceptor.CoopInterceptor"
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor"
<interceptor name="csp" class="org.apache.struts2.interceptor.csp.CspInterceptor"
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor"
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"
<interceptor name="actionFileUpload" class="org.apache.struts2.interceptor.ActionFileUploadInterceptor"
<interceptor name="i18n" class="org.apache.struts2.interceptor.I18nInterceptor"
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"
<interceptor name="paramRemover" class="org.apache.struts2.interceptor.ParameterRemoverInterceptor"
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"
<interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"
<interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"

常用拦截器速记:params(请求参数注入 Action 属性)、fileUpload(multipart 解析)、i18n(request_locale 切换)、exception(异常映射)、token/tokenSession(防重复提交)、prepare(prepare() 前置回调)、validation(校验框架,未在节选中列出)。

6.2 默认拦截器栈 defaultStack(实取开头)

grep -A6 'interceptor-stack name="defaultStack"' struts-default.xml

实测回显:

            <interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="httpMethod"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="csp">

自定义 package 通过 extends="struts-default" 继承后,未显式声明拦截器时自动引用 defaultStack。

6.3 结果类型清单(实取节选)

grep -oE '<result-type name="[^"]+" class="[^"]+"' struts-default.xml | head -12

实测回显:

<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"
<result-type name="dispatcher" class="org.apache.struts2.result.ServletDispatcherResult"
<result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"
<result-type name="httpheader" class="org.apache.struts2.result.HttpHeaderResult"
<result-type name="redirect" class="org.apache.struts2.result.ServletRedirectResult"
<result-type name="redirectAction" class="org.apache.struts2.result.ServletActionRedirectResult"
<result-type name="stream" class="org.apache.struts2.result.StreamResult"
<result-type name="plainText" class="org.apache.struts2.result.PlainTextResult"
<result-type name="postback" class="org.apache.struts2.result.PostbackResult"
结果类型用途本文实测位置
dispatcher转发到 JSP(默认类型)各页面均为此类型
redirect302 重定向到 URLgoHello.action → hello.action?name=Redirected
redirectAction302 重定向到另一 Actionfoo.action 兜底 → example/HelloWorld.action
chainAction 链(转发,非 302)—
stream文件流下载—
freemarker / plainText / httpheader / postback模板 / 源码 / 响应头 / 回发—

七、参数修改与生效方式

struts.xml 打包后位于 WAR 的 WEB-INF/classes 下,属于随应用加载的静态配置。修改常量后的生效流程(实测路径):

  1. 编辑 src/main/resources/struts.xml 中的 <constant>;
  2. 重新打包:mvn package;
  3. 重新部署(复制 war 到 /var/lib/tomcat9/webapps/ 或走 Manager 的 undeploy + deploy);
  4. curl 验证新值生效(如 2.2 节 .do 返回 200、2.3 节 10MB 上传成功)。

⚠️ 注意:仅改 Tomcat 上已解压目录里的 struts.xml 不可靠(应用重载时会被 war 覆盖),务必以「改源码 → 重新打包 → 重新部署」为准。

八、常见问题

8.1 action.extension 去掉空后缀导致单元测试 NPE

把 struts.action.extension 设为 do,action(末尾无空项)后执行 mvn package,surefire 报错原文:

testLoginSubmitInput(com.example.struts.example.LoginTest)  Time elapsed: 0.302 sec  <<< ERROR!
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test (default-test) on project struts2-demo: There are test failures.
java.lang.NullPointerException: Cannot invoke "org.apache.struts2.dispatcher.mapper.ActionMapping.getNamespace()" because "mapping" is null
        at org.apache.struts2.junit.StrutsTestCase.getActionProxy(StrutsTestCase.java:91)
        at com.example.struts.example.LoginTest.testLoginSubmitInput(LoginTest.java:46)

定位:LoginTest.java 第 46 行使用无后缀 URL:ActionProxy proxy = getActionProxy("/example/Login");,空后缀被去掉后该 URL 不再映射任何 Action,mapping 为 null。

解决:保留空后缀,改回 value="do,action,",重新打包后 6 个测试全部通过(Tests run: 6, Failures: 0)。

8.2 日志出现 Working in devMode 告警

这是 struts.devMode=true 的正常提示(OGNL 使用 devMode 排除清单),不是故障。生产环境把 devMode 设为 false 后告警消失。

8.3 上传报 Request exceeded allowed size limit

上传大小超过 struts.multipart.maxSize(默认 2097152 字节)。按业务需要调大该常量(如 10485760)并重新打包部署;同时注意反向代理(如有)自身的请求体限制需一并放行。

九、参考链接