Spring Bean Validation异常:MethodArgumentNotValidException致表单方法未执行
Spring Bean Validation 验证失败抛出异常而非返回原表单问题解决
问题描述
已在与注册表单输入字段映射的FacultyPojo类字段上添加Spring Bean Validation验证约束,期望输入无效时显示带错误信息的原表单。但输入不合法时,处理表单的FacultyRegDetails() Handler方法未执行,BindingResult未填充错误字段,反而抛出org.springframework.web.bind.MethodArgumentNotValidException异常。
相关代码
FacultyPojo类代码
public class FacultyPojo { private int id; @Pattern(regexp = "^[a-zA-Z ]{5,}$", message = "姓名只能包含大小写字母和空格,且长度至少5个字符") private String name; @Pattern(regexp = "^(FIT|FCS|FCE|FME|FEE|FET)\\d{6}$" , message = "教职工ID必须以FIT/FCS/FCE/FME/FEE/FET开头,后跟6位数字") private String facultyId; @Email(message = "请输入有效的邮箱地址") private String email; @Pattern(regexp = "^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[@_])[A-Za-z0-9@_]{5,}$" ,message = "密码必须包含至少一个大写字母、一个小写字母、一个数字和@/_特殊字符,且长度至少5个字符") private String password; // 构造方法... // getter... // setter... }
Handler方法代码(原错误版本)
@PostMapping("/faculty/registration/otpVerification") public String otpVerification2(Model model, Principal p) { if(p == null) { model.addAttribute("PageName", "Faculty_registration2"); FacultyPojo facultyPojo = new FacultyPojo(); model.addAttribute("facultyPojo", facultyPojo); return "Template"; } else { System.out.println("no"); return "redirect:/home/loginSuccess"; } } @PostMapping("/faculty/registrationDetails") public String FacultyRegDetails(@ModelAttribute("facultyPojo") @Valid FacultyPojo facultyPojo, Principal p, BindingResult bindingResult, Model model) { if(p == null) { if(bindingResult.hasErrors()) { model.addAttribute("PageName", "Faculty_registration2"); return "Template"; } else { Faculty faculty = new Faculty(facultyPojo.getName(), facultyPojo.getFacultyId(), facultyPojo.getEmail(), passwordEncoder.encode(facultyPojo.getPassword())); faculty.addRole("ROLE_FACULTY"); ProfilePic profilePic = new ProfilePic("default_pic.jpg"); profilePic.setFaculty(faculty); faculty.setProfilePic(profilePic); serviceFacultyDao.saveFaculty(faculty); return "redirect:/home/login"; } } else { return "redirect:/home/loginSuccess"; } }
表单模板代码
<div class="row m-2" th:fragment="Faculty_registration2"> <div class="col-md-6 offset-md-3 rounded loginContainer p-5"> <h3 class="text-center text-Success">REGISTRATION</h3> <form th:action="@{/home/faculty/registrationDetails}" method="post" th:object="${facultyPojo}"> <div class="form-floating mb-2"> <input type="text" name="facultyId" id="facultyId" class="form-control" placeholder="BT24F06F006" th:field="*{facultyId}"> <label for="facultyId">Enter faculty Id</label> <p th:if="${#fields.hasErrors('facultyId')}" th:errors="*{facultyId}"></p> </div> <div class="form-floating mb-2"> <input type="text" name="name" id="name" class="form-control" placeholder="FullName" th:field="*{name}"> <label for="name">Enter Your Full Name</label> <p th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></p> </div> <div class="form-floating mb-2"> <input type="email" name="email" id="email" class="form-control" placeholder="example@gmail.com" th:field="*{email}"> <label for="email">Enter Your Email</label> <p th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></p> </div> <div class="form-floating"> <input type="password" name="password" id="password" class="form-control" placeholder="Password" th:field="*{password}"> <label for="password">Enter Password</label> <p th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></p> </div> <div class="row mt-3"> <div class="col-6 text-center"> <button type="submit" class="btn btn-primary ">Submit</button> </div> <div class="col-6 text-center"> <a th:href="@{/home/login}" class="btn btn-secondary text-decoration-none">Login</a> </div> </div> </form> </div> </div>
问题原因与解决方案
核心问题:Handler方法参数顺序错误
Spring MVC规定,带有@Valid注解的参数对应的BindingResult必须紧邻该参数,中间不能插入其他参数(比如这里的Principal p)。如果顺序不对,Spring无法将验证错误绑定到BindingResult,会直接抛出MethodArgumentNotValidException,导致你的方法逻辑完全无法执行。
修正后的Handler方法
@PostMapping("/faculty/registrationDetails") // 将BindingResult移到@Valid参数的紧后面 public String FacultyRegDetails(@ModelAttribute("facultyPojo") @Valid FacultyPojo facultyPojo, BindingResult bindingResult, Principal p, Model model) { if(p == null) { if(bindingResult.hasErrors()) { model.addAttribute("PageName", "Faculty_registration2"); return "Template"; } else { Faculty faculty = new Faculty(facultyPojo.getName(), facultyPojo.getFacultyId(), facultyPojo.getEmail(), passwordEncoder.encode(facultyPojo.getPassword())); faculty.addRole("ROLE_FACULTY"); ProfilePic profilePic = new ProfilePic("default_pic.jpg"); profilePic.setFaculty(faculty); faculty.setProfilePic(profilePic); serviceFacultyDao.saveFaculty(faculty); return "redirect:/home/login"; } } else { return "redirect:/home/loginSuccess"; } }
额外修正点
- FacultyPojo正则表达式修正:原
facultyId的正则表达式包含\\n,会匹配换行符导致验证逻辑错误,已移除该部分。 - 表单label关联修正:原表单中第一个label的
for="facId"与input的id="facultyId"不匹配,已改为for="facultyId",确保标签与输入框正确关联。
内容的提问来源于stack exchange,提问作者Shrikant Bochare
相关产品推荐
相关产品推荐

