SpringBoot表单验证报错:找不到firstName对应的BindingResult或目标对象
解决SpringBoot Validation报错:Neither BindingResult nor plain target object for bean name 'firstName' available as request attribute
问题根源
- Thymeleaf模板使用
*{firstName}这类字段选择语法,要求请求中必须存在绑定的表单对象(如User实例),但返回注册页面的GET接口未将User对象传入Model。 - POST接口用
@RequestParam逐个接收参数,未通过@ModelAttribute绑定到User对象,导致实体类上的@NotEmpty、@Size等验证注解完全失效,且BindingResult未关联任何验证对象。 - 验证失败时用
redirect:/addUser重定向,会丢失BindingResult中的错误信息,即便前面的问题修复,错误提示也无法显示。
具体修复步骤
1. 补充/修正返回注册页面的GET接口
假设注册页面通过/addUser访问,在Controller中添加或修改该方法,将空User对象传入Model:
@GetMapping("/addUser") public String showRegisterForm(Model model) { model.addAttribute("user", new User()); // 关键:将User对象放入Model,名称需与后续th:object对应 return "register"; // 替换为你的注册页面模板名称 }
2. 重构POST注册接口
将@RequestParam替换为@ModelAttribute绑定User对象,且BindingResult必须紧跟在@Valid注解的对象之后:
@PostMapping("/register") public String register(@Valid @ModelAttribute("user") User user, BindingResult result, HttpServletRequest request) { // 优先处理验证错误 if (result.hasErrors()) { return "register"; // 直接返回注册页面,保留错误信息 } // 赋予用户权限 user.grantAuthority("ROLE_USER"); userService.updateOrAddUser(user); // 自动登录逻辑 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( user.getEmail(), user.getPassword(), user.getAuthorities() ); Authentication authentication = authenticationManager.authenticate(token); if (authentication.isAuthenticated()) { SecurityContextHolder.getContext().setAuthentication(authentication); request.getSession().setAttribute( HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext() ); } return "redirect:/user"; }
注意:
@ModelAttribute("user")的名称需与GET方法中Model添加的名称一致,确保Thymeleaf能正确关联。
3. 修正Thymeleaf模板
给form标签添加th:object="${user}"绑定表单对象,用th:field替代原有的th:name和th:value,同时优化错误提示:
<form th:action="@{register}" method="post" th:object="${user}"> <label for="firstName"> First Name: </label> <input type="text" class="form-control" id="firstName" placeholder="First name" th:field="*{firstName}" data-cy="firstName" required autofocus> <p th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}">Invalid first name</p> <br/> <label for="lastName"> Last Name: </label> <input type="text" class="form-control" id="lastName" placeholder="Last name" th:field="*{lastName}" data-cy="lastName" required autofocus> <p th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}">Invalid last name</p> <br/> <label for="dateOfBirth"> Date of birth: </label> <input type="date" class="form-control" id="dateOfBirth" placeholder="Date of birth" th:field="*{dateOfBirth}" data-cy="dateOfBirth" required autofocus> <p th:if="${#fields.hasErrors('dateOfBirth')}" th:errors="*{dateOfBirth}">Invalid date of birth</p> <br/> <label for="email"> Email: </label> <input type="email" class="form-control" id="email" placeholder="Email" th:field="*{email}" data-cy="email" required autofocus> <p th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Invalid email</p> <br/> <label for="password"> Password: </label> <input type="password" class="form-control" id="password" placeholder="Password" th:field="*{password}" data-cy="password" required autofocus> <p th:if="${#fields.hasErrors('password')}" th:errors="*{password}">Invalid password</p> <button type="submit">Register</button> </form>
th:field会自动生成正确的name属性、回显表单值,并关联验证错误;th:errors可直接显示实体类中定义的自定义错误消息(如"User's name cannot be empty.")。
4. 确保User类有正确的构造方法和getter/setter
Spring需要通过无参构造方法创建User实例,同时所有字段需具备getter和setter,否则无法完成属性绑定:
public class User { // 必须有无参构造方法 public User() {} // 你的带参构造方法 public User(String firstName, String lastName, Date dateOfBirth, String email, String password) { this.firstName = firstName; this.lastName = lastName; this.dateOfBirth = dateOfBirth; this.email = email; this.password = password; } // 所有字段的getter和setter public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } // 其他字段的getter/setter同理实现... }
内容的提问来源于stack exchange,提问作者Amanda_C
相关产品推荐
相关产品推荐

