FalAn
FalAn

Reputation: 55

Spring boot modified bindingResult return the same error messages before bindingResult is modified

i am practicing validation in spring boot and i got a problem

This is my model:

public class Student {
@NotEmpty
@NotNull
@Length(min = 3, max = 10)
private String username;
@NotEmpty
@Pattern(regexp = "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})")
private String password;
@NotEmpty
@Email
private String email;
@URL
private String website;
@Min(18)
@Max(30)
private int age;

public Student() {
    super();
}

public Student(String username, String password, String email, String website, int age) {
    super();
    this.username = username;
    this.password = password;
    this.email = email;
    this.website = website;
    this.age = age;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

public String getWebsite() {
    return website;
}

public void setWebsite(String website) {
    this.website = website;
}

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

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;
}

@Override
public String toString() {
    return "Student [username=" + username + ", password=" + password + ", email=" + email + ", website=" + website
            + ", age=" + age + "]";
}

}

What i want to do is, when i validate this student class with a form, i want the @NotEmpty is the only error message to print if @NotEmpty is triggered, if @NotEmpty does not trigger, the other validation can freely print the error message, that mean when i leave the form blank, the field with @NotEmpty only print @NotEmpty error message, so i come up with an idea, that is modifying the bindingResult in the controller:

@Controller
@RequestMapping({ "validation", "" })
public class ValidationController {     
    @RequestMapping(value = { "index1", "/" }, method = RequestMethod.GET)
    public String index(ModelMap modelMap) {                        
        modelMap.put("student", new Student());
        return "/validation/index";
    }
    
    @RequestMapping(value = { "resgister" }, method = RequestMethod.POST)
    public String resgister(ModelMap modelMap, RedirectAttributes redirectAttributes, @ModelAttribute("student") @Valid Student student, BindingResult bindingResult) {
        if(bindingResult.hasErrors()) {
            var errors = Helper.customErrorMessageOrder(bindingResult.getFieldErrors());
            bindingResult = new BeanPropertyBindingResult(student, "student");
            for(var e : errors) {
                bindingResult.addError(e);
            }               
            return "/validation/index";
        }
        redirectAttributes.addFlashAttribute("message", "Success");
        return "redirect:/validation/index1";
    }

}

So good so far, i have successfully modify the bindingResult, i even print all the errors to check it out, and it work.

But when i leave the form blank and submit, it print all the errors, for example: the username field will print @NotEmpty and @Length(min = 3, max = 10) error messages, what i expect is only @NotEmpty can print the error message, i kinda have no idea why this happen, please help :(

My customErrorMessageOrder:

public static List<FieldError> customErrorMessageOrder(List<FieldError> listErrors){
        var notEmptyListErrors = listErrors
                                    .stream()
                                    .filter(e -> e.getCode().equals("NotEmpty"))
                                    .collect(Collectors.toList());  
        if(notEmptyListErrors.size()==0) {
            return listErrors;
        }
        
        var alterListErrors = listErrors.stream().collect(Collectors.toList());
        var newListErrors = notEmptyListErrors;
        
        for(var e : notEmptyListErrors) {
            alterListErrors.removeIf(e1->e1.getField().equals(e.getField()));
        }
        
        newListErrors.addAll(alterListErrors);
        
        return newListErrors;
}

And my form, i use thymeleaf:

<form th:action="@{/validation/resgister}" method="post" th:object="${student}">
        <table border="1">
            <tr>
                <td>Username</td>
                <td><input type="text" th:field="*{username}"></td>
                <td th:if="${#fields.hasErrors('username')}">
                    <span th:errors="*{username}"></span>
                </td>
            </tr>       
            
            <tr>
                <td>Password</td>
                <td><input type="text" th:field="*{password}"></td>
                <td th:if="${#fields.hasErrors('password')}">
                    <span th:errors="*{password}"></span>
                </td>
            </tr>   

            <tr>
                <td>Email</td>
                <td><input type="text" th:field="*{email}"></td>
                <td th:if="${#fields.hasErrors('email')}">
                    <span th:errors="*{email}"></span>
                </td>
            </tr>
            
            <tr>
                <td>Website</td>
                <td><input type="text" th:field="*{website}"></td>
                <td th:if="${#fields.hasErrors('website')}">
                    <span th:errors="*{website}"></span>
                </td>
            </tr>   

            <tr>
                <td>Age</td>
                <td><input type="text" th:field="*{age}"></td>
                <td th:if="${#fields.hasErrors('age')}">
                    <span th:errors="*{age}"></span>
                </td>
            </tr>

            <tr>
                <td colspan="2" style="text-align: center;"><input type="submit" value="submit"></td>
            </tr>
        </table>
</form>

Upvotes: 0

Views: 69

Answers (1)

FalAn
FalAn

Reputation: 55

i got it, since bindingResult got auto pass to an key called:

org.springframework.validation.BindingResult.**<NAME_OF_MODEL_ATTRIBUTE>**

in thymeleaf, so i have to overwrite it in the controller:

modelMap.put("org.springframework.validation.BindingResult.student", bindingResult);

and it worked!!

Upvotes: 0

Related Questions