显示"Passwords don't match"自定义批注消息



如何在 Spring 中将来自自定义类类型注释的此消息显示为 HTML 表单中的警告消息?我正在使用Spring Boot MVC和Thymeleaf。Thymeleaf 可以处理字段错误和全局错误,这些错误与表单中的任何特定字段无关,但仍然存在。如果此自定义批注发现密码不匹配,是全局错误还是字段错误?如何显示此消息?

自定义注释:

@Target({ TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = PasswordMatchesValidator.class)
@Documented
public @interface PasswordMatches {
    String message() default "Passwords don't match";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

验证器类:

public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, Object> {
    @Override
    public void initialize(PasswordMatches passwordMatches) {
    }
    @Override
    public boolean isValid(Object obj, ConstraintValidatorContext context) {
        UserDto userDto = (UserDto) obj;
        return userDto.getPassword().equals(userDto.getMatchingPassword());
    }
}

后控制器

@PostMapping(value = "/register")
public ModelAndView processRegistration(ModelAndView modelAndView, @Valid @ModelAttribute ("userDto") UserDto userDto,
                                        BindingResult bindingResult, HttpServletRequest request, Errors errors) {
    // Lookup user in database by e-mail
    User userExists = userService.findByEmail(userDto.getEmail());
    System.out.println(userExists);
    if (userExists != null) {
        modelAndView.addObject("alreadyRegisteredMessage", "Oops!  There is already a user registered with the email provided.");
        modelAndView.setViewName("register");
        bindingResult.reject("email");
    }
    if (bindingResult.hasErrors()) {
        modelAndView.setViewName("register");
    } else { // new user so we create user and send confirmation e-mail
        User user = userService.createNewAccount(userDto);
        user.setEnabled(false);
        userService.saveUser(user);
        modelAndView.addObject("confirmationMessage", "A confirmation e-mail has been sent to " + userDto.getEmail());
        modelAndView.setViewName("registered");
    }
}

网页表单:

<div class="container">
  <div class="row">
    <div class="card col-6 mx-auto" style="width: 20rem; margin: 20px;">
      <div class="card-body">
        <h4 class="card-title">Registration form:</h4>
        <form th:action="@{register}" th:object="${userDto}"  th:method="post" method="post" action="register">
          <div class="form-group">
            <label th:for="name" for="Name">Name</label>
            <input type="text" class="form-control" th:field="*{name}" id="name" placeholder="Enter name">
            <p class="text-danger" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></p>
          </div>
          <div class="form-group">
            <label th:for="surname" for="Surname">Surname</label>
            <input type="text" class="form-control" th:field="*{surname}" id="surname" placeholder="Enter surname">
            <p class="text-danger" th:if="${#fields.hasErrors('surname')}" th:errors="*{surname}"></p>
          </div>
          <div class="form-group">
            <label th:for="username" for="Username">Username</label>
            <input type="text" class="form-control" th:field="*{username}" id="username" placeholder="Enter username">
            <p class="text-danger" th:if="${#fields.hasErrors('username')}" th:errors="*{username}"></p>
          </div>
          <div class="form-group">
            <label th:for="email" for="Email">Email address</label>
            <input type="email" class="form-control" th:field="*{email}" id="email" aria-describedby="emailHelp" placeholder="Enter email">
            <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
            <p class="text-danger"th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></p>
            <p class="text-danger" th:text="${alreadyRegisteredMessage}"></p>
          </div>
          <div class="form-group">
            <label th:for="password" for="Password">Password</label>
            <input type="password" class="form-control" th:field="*{password}" id="password" placeholder="Password">
            <p class="text-danger"th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></p>
          </div>
          <div class="form-group">
            <label th:for="matchingPassword" for="matchingPassword">Confirm Password</label>
            <input type="password" class="form-control" th:field="*{matchingPassword}" id="matchingPassword" placeholder="Password">
            <p class="text-danger"th:if="${#fields.hasErrors('matchingPassword')}" th:errors="*{matchingPassword}"></p>
          </div>
          <button type="submit" class="btn btn-primary">Submit</button>
        </form>
      </div>
    </div>
  </div>
</div>

您可以自定义 PasswordMatchesValidator 类以显示警告消息。

public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, Object> {
  private String message;
    @Override
    public void initialize(PasswordMatches passwordMatches) {
      this.message = passwordMatches.message();
    }
    @Override
    public boolean isValid(Object obj, ConstraintValidatorContext context) {
        final UserDto userDto = (UserDto) obj;
        boolean isValid = userDto.getPassword().equals(userDto.getMatchingPassword());
        if (!isValid) {
            context.disableDefaultConstraintViolation();
            context
                    .buildConstraintViolationWithTemplate( message )
                    .addPropertyNode( "matchingPassword" ).addConstraintViolation();
        }
        return isValid;
    }
}

解决方案是以HTML形式包含全局错误Thymeleaf语法。但由于某种原因,此消息中的单引号:"密码不匹配"不会呈现。这个问题的答案就在这里。

最新更新