struts.xml中package的extends仅继承父包的interceptors、results等配置,不继承action标签;父包须设abstract="true",子包需自行定义action并正确配置namespace。
struts.xml 里
的
属性到底继承什么
它只继承父
声明的
、
、
、
和
,不继承
标签本身——子包必须自己定义 action。
常见错误是以为写了
就能直接用父包里定义的
,结果 404。Struts2 不支持 action 级别的继承,只有配置结构复用。
父包必须设
才能被继承(否则启动报错
)
父包里定义的
或自定义拦截器栈,子包可直接引用名字,不用重复声明
如果子包也声明了同名
(比如
),会覆盖父包的定义,不是合并
为什么 extends="struts-default" 是几乎每个 package 的标配
因为
是 Struts2 自带的抽象包,它预定义了最常用的拦截器栈
、JSON/REST 相关 result 类型、常用异常映射等。不继承它,你的 action 默认连参数绑定、字段验证、类型转换都失效。
典型现象:action 方法执行了,但
始终为
,或者表单提交后页面空白没跳转——大概率是忘了
或误写成
(后者不存在)。
检查拼写:
中间是短横线,不是下划线或空格
不能写成
:Struts2 不支持多继承,只能单继承,如需 JSON 支持,应继承
(它自己已继承
)
自定义拦截器栈若依赖
里的拦截器(比如
),就必须确保父包最终链到
多个 package 继承同一父包时,interceptor 栈会不会冲突
不会。每个
的
是独立解析的,即使都引用
,运行时也是各自创建拦截器实例链,互不影响。
真正容易出问题的是:在父包里改了
的定义(比如删掉
拦截器),所有继承它的子包都会受影响——这不是冲突,是预期中的传递性变更。
调试技巧:启动时加 JVM 参数
,访问
路径可查看所有 package 和拦截器栈展开结构
避免在父包中重定义
,如需定制,建议新建栈名(如
),用
显式组装
如果子包要临时禁用某个拦截器(比如登录 action 不需要验证),应在 action 级用
替代全局引用
extends 配置生效但 action 找不到,可能卡在哪几个地方
最常忽略的是命名空间(
)和路径匹配逻辑。Struts2 匹配 action 时,是“先找 namespace 匹配的 package,再在该 package 内找 action name”,
只影响配置复用,不改变查找路径。
例如:父包
、
,子包
、
、
。此时子包里的
对应 URL 是
,不是
。
检查
是否以
开头(不加会变成相对命名空间,行为难预测)
确认请求 URL 的路径前缀和 package 的
完全一致(包括末尾斜杠)
用
查看控制台日志,搜索
,它会打印出 Struts2 实际尝试匹配的 package 名和 action 名
不要在子包里漏写
:如果不写,它默认是
(根命名空间),和父包的
完全无关
Struts2 的
是静态配置复用机制,不是面向对象继承;它不解决 action 复用,也不绕过命名空间隔离——这两点最容易让人反复踩坑。
packageextendspackageinterceptorsresultsglobal-resultsglobal-exception-mappingsdefault-interceptor-refactionextends="base"abstract="true"Package [xxx] cannot be extendedname="success"struts-defaultdefaultStackString usernamenullextends="struts-default"extends="default"struts-defaultextends="struts-default, json-default"json-defaultstruts-defaultdefaultStackparamsstruts-defaultpackageinterceptor-refdefaultStackdefaultStackvalidation-Dstruts.devMode=true/struts/defaultStackmyStacknamespaceextendsname="base"namespace="/api"name="user"namespace="/api/v2"extends="base"/api/v2/list.action/api/list.actionnamespace/namespacestruts.devMode=trueUnable to find actionnamespace""/apiextends