Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot + Thymeleaf - form validation

i have problem with Thymeleaf when validating form. I'm trying to create simple user register form to learn Spring and i'm unfortunately stuck.

Here is my UserForm class

public class UserForm {
    @NotEmpty
    private String username;
    @NotEmpty
    private String password;
    @NotEmpty
    private String passwordConfirm;

    \\ Getters and Setters
}

First problem is when I add my custom validator class in initBinder

@Autowired
private UserFormValidator formValidator;

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.setValidator(formValidator);
}

"Default" annotated by @NotEmpty validation stops working. This is exptected behavior?

Second problem is how can I show global reject messages in thymeleaf?
My validator class is like below

public class UserFormValidator implements Validator {
    @Autowired
    UserService userService;

    @Override
    public boolean supports(Class<?> clazz) {
        return UserForm.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        UserForm userForm = (UserForm) target;
        if(!userForm.getPassword().equals(userForm.getPasswordConfirm())) {
            errors.reject("passwords.no.match", "Passwords not match");
        }

        if(userService.findOneByUsername(userForm.getUsername()).isPresent()) {
            errors.reject("user.exist", "User already exists (default)");
        }
    }   
}

and post mapping from controller

@PostMapping("/create")
public String registerUser(@ModelAttribute("form") @Valid final UserForm form, BindingResult bindingResult) {
    if(bindingResult.hasErrors()) {
        return "newuser";
    }
    userService.saveUser(form);
    return "redirect:/";
}

As "default" validation errors i can show by using exth:if="${#fields.hasErrors('passwordConfirm')}" i have no idea how can i show message for error passwords.no.match or check if this error occured?

like image 568
Jan Nowak Avatar asked Feb 23 '17 18:02

Jan Nowak


1 Answers

By default spring boot uses bean validation to validated form object annotated with @Valid. If you want to use your custom validator and register it through @InitBinder, then bean validation will not take place, this is expected behavior. If you want to bean validation also works with your custom validation you need to do it manually inside your validator class or even in controller.

Here comes your second problem to show password not match error message. Inside your custom validator UserFormValidator.class while rejecting any value you need to use rejectValue() method like below:

    @Override
    public void validate(Object target, Errors errors) {
        UserForm userForm = (UserForm) target;
        if(!userForm.getPassword().equals(userForm.getPasswordConfirm())) {
            errors.rejectValue("passwordConfirm", "passwords.no.match", "Passwords not match");
        }

        if(userService.findOneByUsername(userForm.getUsername()).isPresent()) {
            errors.rejectValue("username", "user.exist", "User already exists (default)");
        }
    } 

The rejectValue() method is used to add a validation error to the Errors object. The first parameter identifies which field the error is associated with. The second parameter is an error code which acts a message key for the messages.properties file (or messages_en.properties or messages_fr.properties etc, if these are being used). The third parameter of rejectValue() represents the fallback default message, which is displayed if no matching error code is found in the resource bundle.

Now you can show error messages using th:if="${#fields.hasErrors('passwordConfirm')} inside your form.

like image 87
Monzurul Shimul Avatar answered Oct 19 '22 01:10

Monzurul Shimul