#java #spring-boot #validation #error-handling #thymeleaf
#java #spring-boot #проверка #обработка ошибок #thymeleaf
Вопрос:
Я создаю небольшой api с Spring Boot, Spring Security, Thymeleaf. Я создал рабочий логин, роли безопасности и теперь пытаюсь выполнить регистрацию. Если я добавлю новые (правильные для моей базы данных) данные, то пользователь будет создан правильно, однако я выполнил некоторые классические проверки в CrmUser, такие как @Notnull и мои собственные — проверки электронной почты и сопоставление паролей. Все они не работают. Я не знаю почему. Единственное, что работает, это «имя пользователя уже существует» из моего метода контроллера. Кто-нибудь может помочь?
import com.marcinha.stylist.validation.FieldMatch;
import com.marcinha.stylist.validation.ValidEmail;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@FieldMatch.List({
@FieldMatch(first = "password", second = "matchingPassword", message = "The password fields must match")
})
public class CrmUser {
@NotNull(message = "is required")
@Size(min = 1, message = "is required")
private String userName;
@NotNull(message = "is required")
@Size(min = 1, message = "is required")
private String password;
@NotNull(message = "is required")
@Size(min = 1, message = "is required")
private String matchingPassword;
@NotNull(message = "is required")
@Size(min = 1, message = "is required")
private String firstName;
@NotNull(message = "is required")
@Size(min = 1, message = "is required")
private String lastName;
@ValidEmail
@NotNull(message = "is required")
@Size(min = 1, message = "is required")
private String email;
@NotNull(message = "is required")
@Size(min = 1, message = "is required")
private String country;
public CrmUser() {
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMatchingPassword() {
return matchingPassword;
}
public void setMatchingPassword(String matchingPassword) {
this.matchingPassword = matchingPassword;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class EmailValidator implements ConstraintValidator<ValidEmail, String> {
private Pattern pattern;
private Matcher theMatcher;
private final static String EMAIL_PATTERN = "^[_A-Za-z0-9-\\ ] (\\.[_A-Za-z0-9-] )*@"n"
"ttt "[A-Za-z0-9-] (\\.[A-Za-z0-9] )*(\\.[A-Za-z]{2,})$";
@Override
public boolean isValid(String email, ConstraintValidatorContext constraintValidatorContext) {
pattern = Pattern.compile(EMAIL_PATTERN);
if (email == null) {
return false;
}
theMatcher = pattern.matcher(email);
return theMatcher.matches();
}
}
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Constraint(validatedBy = EmailValidator.class)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValidEmail {
String message() default "Invalid email";
Class<?>[] groups() default{};
Class<? extends Payload>[] payload() default {};
}
import org.springframework.beans.BeanWrapperImpl;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object> {
private String firstFieldName;
private String secondFieldName;
private String message;
@Override
public void initialize(FieldMatch constraintAnnotation) {
firstFieldName = constraintAnnotation.first();
secondFieldName = constraintAnnotation.second();
message = constraintAnnotation.message();
}
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
boolean valid = true;
try{
Object firstObj = new BeanWrapperImpl(o).getPropertyValue(firstFieldName);
Object secondObj = new BeanWrapperImpl(o).getPropertyValue(secondFieldName);
valid = firstObj == null amp;amp; secondObj == null || firstObj != null amp;amp; secondObj.equals(firstObj);
}
catch (Exception ignore){
}
if(!valid){
constraintValidatorContext.buildConstraintViolationWithTemplate(message)
.addPropertyNode(firstFieldName)
.addConstraintViolation()
.disableDefaultConstraintViolation();
}
return valid;
}
}
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = FieldMatchValidator.class)
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldMatch {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String first();
String second();
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
FieldMatch[] value();
}
}
@Controller
@RequestMapping("/registry")
public class RegistrationController {
@Autowired
private UserService service;
private Logger logger = Logger.getLogger(getClass().getName());
@GetMapping("/showRegistrationForm")
public String showRegistration(Model model) {
model.addAttribute("crmUser", new CrmUser());
return "registration-from";
}
@PostMapping("/processingRegistrationForm")
public String registry(@Valid @ModelAttribute("crmUser") CrmUser theCrmUser,
BindingResult theBindingResult,
Model theModel) {
String username = theCrmUser.getUserName();
logger.info("Processing registration form for: " username);
if (theBindingResult.hasErrors()) {
return "registration-form";
}
User existingUser = service.findByUserName(username);
if (existingUser != null) {
theModel.addAttribute("crmUser", new CrmUser());
theModel.addAttribute("registrationError", "User already exist in database");
logger.warning("User name already exists.");
return "registration-form";
}
service.save(theCrmUser);
logger.info("Successfully created user: " username);
return "registration-confirmation";
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<Title> Registration form </Title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<form th:action="@{/registry/processingRegistrationForm}"
th:object="${crmUser}" method="POST">
<!-- Check for registration error -->
<div th:if="${registrationError}">
<span th:text="${registrationError}"></span>
</div>
<!-- User name -->
<div>
<input type="text" th:field="*{userName}" placeholder="Username (*)">
</div>
<div th:if="${#fields.hasErrors('userName')}">
<ul>
<li th:each="err : ${#fields.errors('userName')}" th:text="'User name ' ${err}" />
</ul>
</div>
<!-- Password -->
<div>
<input type="password" th:field="*{password}" placeholder="Password (*)">
</div>
<div th:if="${#fields.hasErrors('password')}">
<ul>
<li th:each="err : ${#fields.errors('password')}" th:text="'Password ' ${err}" />
</ul>
</div>
<!-- Confirm Password -->
<div>
<input type="password" th:field="*{matchingPassword}" placeholder="confirm password (*)">
</div>
<div th:if="${#fields.hasErrors('matchingPassword')}">
<ul>
<li th:each="err : ${#fields.errors('matchingPassword')}" th:text="'Password ' ${err}" />
</ul>
</div>
<!--First Name -->
<div>
<input type="text" th:field="*{firstName}" placeholder="First name (*)">
</div>
<div th:if="${#fields.hasErrors('firstName')}">
<ul>
<li th:each="err : ${#fields.errors('firstName')}" th:text="'First name ' ${err}" />
</ul>
</div>
<!-- Last Name -->
<div>
<input type="text" th:field="*{lastName}" placeholder="Last name (*)">
</div>
<div th:if="${#fields.hasErrors('lastName')}">
<ul>
<li th:each="err : ${#fields.errors('lastName')}" th:text="'Last name ' ${err}" />
</ul>
</div>
<!-- Email -->
<div>
<input type="text" th:field="*{email}" placeholder="Email (*)">
</div>
<div th:if="${#fields.hasErrors('email')}">
<ul>
<li th:each="err : ${#fields.errors('email')}" th:text="'Email ' ${err}" />
</ul>
</div>
<!-- Register Button -->
<div class="col-sm-6 controls">
<button type="submit" class="btn btn-primary">Register</button>
</div>
</form>
</body>
</html>
Ответ №1:
Неважно: D Я пропустил одну зависимость в моем pom:
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>