Spring MVC控制器无法获取JSP form:hidden隐藏域值问题
问题现象
测试支付相关代码时,需要接收表单传入的隐藏金额字段,但使用<form:hidden>标签定义的隐藏域值无法传递到后端控制器,其余普通表单字段均可正常获取,唯独该隐藏域取值失败。将字段改为带readonly属性的普通输入框时,所有字段值均可正常获取。
相关代码
JSP表单代码
<form:form id="frmCard" method="post" action="${payment_url}" align="center" modelAttribute="payment"> <div id="my-card" class="card-js" data-capture-name="true" data-icon-colour="#337ab7"> <form:input path="card_number" class="card-number" placeholder="Card Number" /> <form:input path="card_name" class="name englishonly" placeholder="Name On Card" maxlength="21" /> <form:input path="card_expiry_month" class="expiry-month" /> <form:input path="card_expiry_year" class="expiry-year" /> <form:input path="card_cvc" class="cvc" /> <form:hidden path="amount" value="10" /> <!-- 异常字段 --> <p> <div> <img src="../img/cards.png"> </div> <p> <input type="submit" name="Pay" /> </form:form>
控制器方法代码
@PostMapping("/addPayment") public String payment(@ModelAttribute("payment") Payment payment ) { System.out.println(""+payment.getCard_number()); // 正常获取值 System.out.println("$ "+payment.getAmount()); // 无法获取值 String status = "error"; try { status = paymentService.process(payment); } catch (Exception e) { e.printStackTrace(); } return status; }
原因说明
- 前端DOM重构问题:当前使用的
card-js银行卡号输入组件,初始化时会扫描容器内的表单元素,仅保留带指定类名(card-number、expiry-month等组件识别类)的输入项做自定义渲染,未被识别的<form:hidden>元素会被组件移出表单甚至直接删除,导致表单提交时请求参数中根本不包含amount字段,后端自然无法获取值。这也是把字段改成带readonly的普通输入框(属于组件识别的input类型)时可以正常传值的核心原因。 - Spring表单标签绑定逻辑问题:
<form:hidden>标签的渲染逻辑会优先读取modelAttribute绑定对象的对应属性值,手动写在标签上的value属性不会强制覆盖绑定值。如果跳转页面时没有提前给model中payment对象的amount属性赋值,即使标签上写了value="10",渲染出的隐藏input实际value也可能为空。
解决方案
- 方案1:将隐藏域移出card-js组件容器
把<form:hidden path="amount" />标签移到id="my-card"的div外部,作为<form:form>的直接子节点,避免被前端组件修改DOM。同时在跳转到支付页面的控制器方法中,提前给绑定的payment对象设置amount值,不要手动在标签上硬写value:// 跳转到支付页的接口示例 @GetMapping("/toPayPage") public String toPayPage(Model model) { Payment payment = new Payment(); payment.setAmount(10); // 提前赋值 model.addAttribute("payment", payment); return "payPage"; } - 方案2:使用原生HTML隐藏域
不使用Spring的<form:hidden>标签,在card-js容器内直接写原生隐藏输入框,确保name属性和实体类字段名一致即可正常绑定:<input type="hidden" name="amount" value="10" /> - 方案3:用隐藏样式的只读输入框替代
保留输入框的readonly属性,通过CSS设置为不可见,实现和隐藏域一致的效果,同时不会被card-js组件过滤:<form:input path="amount" readonly="true" style="display: none;" value="10" />
内容的提问来源于stack exchange,提问作者J. Doe
相关产品推荐
相关产品推荐

