You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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";
    }
}

额外修正点

  1. FacultyPojo正则表达式修正:原facultyId的正则表达式包含\\n,会匹配换行符导致验证逻辑错误,已移除该部分。
  2. 表单label关联修正:原表单中第一个label的for="facId"与input的id="facultyId"不匹配,已改为for="facultyId",确保标签与输入框正确关联。

内容的提问来源于stack exchange,提问作者Shrikant Bochare

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 00:07:03