Spring Controller POST方法失效:JSP表单提交无法触发控制器方法
我来帮你一步步排查这个问题,之前做项目的时候也碰到过类似的情况,大概率是路径配置或者Spring扫描的问题,咱们逐一梳理:
1. 检查Controller类的基础注解与扫描配置
首先确认你的Controller类上有没有加@Controller或者@RestController注解?另外,Spring是否能扫描到这个Controller类?
- 如果是传统Spring MVC项目,要在XML配置里加上
<context:component-scan base-package="com.yourpackage.controller"/>(替换成你的Controller实际所在包); - 如果是Spring Boot项目,确保带
@SpringBootApplication的启动类所在包包含Controller的包,或者手动通过@ComponentScan指定扫描路径。
另外要注意:如果Controller类上有类级别的@RequestMapping前缀(比如@RequestMapping("/api")),那方法的实际映射路径会变成/api/school,而你的表单action是/school,路径不匹配就会触发不了方法。
2. 修正表单的Action路径(重点!)
你现在用的是绝对路径/school,但如果你的项目部署时设置了上下文路径(Context Path)(比如Tomcat配置了path="/myapp",或者Spring Boot里设置了server.servlet.context-path=/myapp),那实际请求路径应该是/myapp/school,直接写/school会找不到对应的映射。
最稳妥的方式是用JSTL的<c:url>标签生成正确路径,它会自动带上上下文路径:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <form action="<c:url value='/school'/>" method="POST"> School name: <input type="text" id="school" name="school" /> <input type="hidden" value="${firstName}" name="firstName"/> <input type="hidden" value="${lastName}" name="lastName"/> <!-- 后续步骤如果需要加CSRF字段也放这里 --> <input type="submit" value="Submit" /> </form>
如果不想用JSTL,也可以手动拼接上下文路径:action="${pageContext.request.contextPath}/school",效果一致。
3. 检查Spring Security的CSRF拦截(如果用到了)
如果你的项目集成了Spring Security,默认会开启CSRF保护,POST请求如果没有携带CSRF令牌会被拦截,导致Controller方法无法触发。解决方法是在表单里添加CSRF隐藏字段:
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
把这段代码加到表单的隐藏字段区域即可。
4. 验证映射是否注册成功
启动项目时,查看Spring的DEBUG级别日志,找有没有类似这样的输出:
Mapped "{[/school],methods=[POST]}" onto public void com.yourpackage.YourController.setSchool(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
如果没有这条日志,说明你的RequestMapping根本没被Spring注册,回到第一步检查扫描和注解问题。
5. 用Postman测试排除表单问题
可以先用Postman直接发送POST请求到http://localhost:8080/school(注意加上上下文路径如果有的话),带上参数firstName、lastName、school,看能不能触发Controller方法:
- 如果Postman能触发,那问题出在表单的路径或者CSRF配置上;
- 如果Postman也触发不了,那就是Controller的配置问题。
额外的代码优化建议
你的Controller方法里有个小bug:不管status是不是SUCCESS,都会执行sendRedirect,但sendError之后再调用sendRedirect会抛出IO异常,应该改成if-else结构:
@RequestMapping(value = "/school", method = RequestMethod.POST) public void setSchool(HttpServletRequest request,HttpServletResponse response){ String firstName= request.getParameter("firstName"); String lastName= request.getParameter("lastName"); String school= request.getParameter("school"); String status = userController.setSchool(firstName, lastName, school); try { if(!status.equals("SUCCESS")) { response.sendError(HttpServletResponse.SC_FORBIDDEN, status); } else { // 建议用上下文路径生成重定向地址,避免硬编码 response.sendRedirect(request.getContextPath() + "/getInsideSchool?school="+school+"&firstName="+firstName+"&lastName="+lastName); } } catch (IOException e) { e.printStackTrace(); } }
按照上面的步骤排查,应该就能解决问题啦!
内容的提问来源于stack exchange,提问作者lambad

