Struts 6.3.0.2中ModelDriven与表单提交的取值异常问题
问题核心原因
嵌套ModelDriven不被支持:Struts2的ModelDriven拦截器仅处理单层模型驱动逻辑。当Action实现
ModelDriven<AdvanceSettlementForm>,同时Form又实现ModelDriven<AdvanceSettlementModel>时,拦截器只会将Form对象压入值栈,不会自动递归处理Form内部的Model,导致表单参数无法映射到内层的AdvanceSettlementModel。拦截器栈不完整:struts.xml中仅单独引用了
modelDriven拦截器,缺少负责参数填充的params拦截器,以及validation、workflow等默认拦截器,参数无法被正确填充到模型中。前端提交逻辑冲突:a标签的
href指向/orders/saveSettlement,但表单的action是orders,点击a标签时浏览器可能同时触发GET请求,导致实际请求的Action与预期不符。
解决建议
1. 移除嵌套的ModelDriven实现
取消AdvanceSettlementForm的ModelDriven接口实现,改为直接持有模型并提供 getter/setter,或直接暴露模型属性:
public class AdvanceSettlementForm implements Serializable { private AdvanceSettlementModel model = new AdvanceSettlementModel(); // 提供模型的getter/setter public AdvanceSettlementModel getModel() { return model; } public void setModel(AdvanceSettlementModel model) { this.model = model; } // 可选:直接暴露模型属性,简化参数映射 public String getSettlementAmount() { return model.getSettlementAmount(); } public void setSettlementAmount(String settlementAmount) { model.setSettlementAmount(settlementAmount); } }
2. 修复拦截器栈配置
使用Struts2默认拦截器栈defaultStack,它包含了modelDriven、params等所有必要拦截器:
<package name="your-package" extends="struts-default"> <action name="orders" class="your-package.YourActionClass" method="execute"> <interceptor-ref name="defaultStack"/> <result>/your-result.jsp</result> </action> <!-- 确保saveSettlement对应Action也正确配置 --> <action name="saveSettlement" class="your-package.YourActionClass" method="execute"> <interceptor-ref name="defaultStack"/> <result>/your-result.jsp</result> </action> </package>
3. 修正前端提交逻辑
移除a标签的href属性,避免触发额外GET请求,改用纯按钮或Struts2自带的提交标签:
<!-- 替换原a标签为按钮 --> <button type="button" onclick="submitForm();" class="btn btn-default">Save Settlement</button> <!-- 或直接使用Struts2提交标签,无需自定义JS --> <s:submit value="Save Settlement" cssClass="btn btn-default"/>
4. 调整表单参数名称(可选)
如果保留Form持有Model的结构,前端表单的参数名称需改为model.settlementAmount,对应Form中getModel()返回的对象属性:
<s:textfield maxlength="225" styleClass="form-control" name="model.settlementAmount" />
关于RestActionInvocation方法的说明
该方法是Rest插件的内部逻辑,用于限制非GET请求,和当前表单提交问题无关。除非你启用了Rest插件且配置restrictToGet为true,否则不会影响POST表单提交。
内容的提问来源于stack exchange,提问作者Ramakant Adam

