我自己的验证密码输入的注释有问题。正如我测试的那样,当密码匹配时,注册确实有效,但当密码不匹配时,我想将它们显示在我的 /register 端点/站点中,就像所有其他有效的注释一样。 为什么我的密码匹配错误没有显示在 register.html 上?
注册.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<link rel="stylesheet" href="assets/css/form-style.css">
<title>Register</title>
</head>
<body>
<div th:replace="~{header :: header}">...</div>
<h1>Register</h1>
<form th:action="@{/createUser}" th:object="${MyUser}" method="post">
<div th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="errors"></div>
<input type="text" th:field="*{email}" placeholder="email"><br>
<div th:if="${#fields.hasErrors('password')}" th:errors="*{password}" class="errors"></div>
<input type="password" th:field="*{password}" placeholder="password"><br>
**//This should display the error**
**<div th:if="${#fields.hasErrors('confirmPassword')}" th:errors="*{confirmPassword}" class="errors"></div>**
<input type="password" th:field="*{confirmPassword}" placeholder="confirm password"><br>
<div th:if="${#fields.hasErrors('age')}" th:errors="*{age}" class="errors"></div>
<input type="number" th:field="*{age}" placeholder="age"><br>
<input type="submit" value="Register"> <br>
</form>
<div th:replace="~{footer :: footer}">...</div>
</body>
</html>
MyUser.java
package com.loginthyme.security.model;
import com.loginthyme.security.annotation.FieldsValueMatch;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Set;
@Document(collection = "users")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@FieldsValueMatch.List({@FieldsValueMatch(field = "password", fieldMatch = "confirmPassword", message = "The password fields must match")}
)
public class MyUser {
@Id
private ObjectId id;
@NotEmpty(message = "Email can not be empty")
@Email(message = "Invalid email format")
private String email;
@NotEmpty(message = "Password can not be empty")
private String password;
// @Transient
private String confirmPassword;
@Min(value = 18, message = "Age must be at least 18")
@NotNull(message = "Age can not be empty")
private Integer age;
private Set<Role> role;
}
FieldsValueMatchValidator.java
package com.loginthyme.security.validations;
import com.loginthyme.security.annotation.FieldsValueMatch;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.springframework.beans.BeanWrapperImpl;
public class FieldsValueMatchValidator implements ConstraintValidator<FieldsValueMatch, Object> {
private String field;
private String fieldMatch;
@Override
public void initialize(FieldsValueMatch constraintAnnotation) {
this.field = constraintAnnotation.field();
this.fieldMatch = constraintAnnotation.fieldMatch();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
Object fieldValue = new BeanWrapperImpl(value).getPropertyValue(field);
Object fieldMatchValue = new BeanWrapperImpl(value).getPropertyValue(fieldMatch);
if (fieldValue != null) {
return fieldValue.equals(fieldMatchValue);
} else {
return fieldMatchValue == null;
}
}
}
FieldsValueMatch.java
package com.loginthyme.security.annotation;
import com.loginthyme.security.validations.FieldsValueMatchValidator;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Constraint(validatedBy = FieldsValueMatchValidator.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldsValueMatch {
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String message() default "Fields value don`t match";
String field();
String fieldMatch();
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface List {
FieldsValueMatch[] value();
}
}
RegisterController.java
package com.loginthyme.security.controller;
import com.loginthyme.security.model.MyUser;
import com.loginthyme.security.model.Role;
import com.loginthyme.security.repository.UserRepository;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import java.util.Collections;
@Controller
@Slf4j
public class RegisterController {
UserRepository userRepository;
PasswordEncoder passwordEncoder;
@Autowired
public RegisterController(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
@PostMapping("/createUser")
public String createUser(@Valid @ModelAttribute("MyUser") MyUser myUser, BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
return "register";
}
if(!userRepository.existsByEmail(myUser.getEmail())) {
myUser.setPassword(passwordEncoder.encode(myUser.getPassword()));
myUser.setRole(Collections.singleton(Role.ROLE_USER));
userRepository.save(myUser);
log.info("User succesfully registered");
} else {
log.info("Such a user already exists");
}
return "redirect:/register";
}
@GetMapping("/register")
public String displayRegisterPage(Model model) {
model.addAttribute("MyUser", new MyUser());
return "register";
}
}
您的 Thymeleaf 模板中似乎缺少确认密码字段的错误消息。您已在 MyUser 类中正确添加了验证注释,但您需要在 HTML 模板中处理错误消息。
在您的register.html 文件中,确保为confirmPassword 字段添加错误消息,类似于您为电子邮件和密码字段所做的操作。修改方法如下:
<div th:if="${#fields.hasErrors('confirmPassword')}" th:errors="*{confirmPassword}" class="errors"></div>
当验证失败时,此行将显示confirmPassword字段的错误消息。确保将其放置在密码确认输入字段所在的表单部分中。