Reputation: 349
I simply want to validate a form data and display an error message. Validating email format, password size and password matching. What would be the best way to do that?
Here's what I've tried
My controller
@PostMapping("/{customerId}/createUser")
public String signIn(@PathVariable(value = "customerId", required = false) Long customerId,
@ModelAttribute(name = "user") @Valid Users user, RedirectAttributes redirectAttributes,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "customerNewUser";
}
// Encrypt password
user.setPassword(encoder.encode(user.getPassword()));
user.setCustomerId(customerId);
user.setEventDescription("User Admin creation");
try {
Users returnedUser = userService.save(user);
List<Authorities> authorities = new ArrayList<Authorities>();
Authorities auth = new Authorities(new AuthoritiesPK(returnedUser.getId(), "ROLE_CLI_ADM"), returnedUser,
"ROLE_CLI_ADM");
authorities.add(auth);
returnedUser.setAuthorities(authorities);
returnedUser.setEventDescription("Add Admin role");
for (int i = 0; i < returnedUser.getAuthorities().size(); i++) {
authorityService.save(returnedUser.getAuthorities().get(i));
}
userService.save(returnedUser);
} catch (WebExchangeBindException webe) {
StringBuilder errorBuilder = new StringBuilder();
for (ObjectError error : webe.getAllErrors()) {
errorBuilder.append(messageSource.getMessage(error.getCode(), null, Locale.getDefault())).append("\n");
}
redirectAttributes.addFlashAttribute("signInError", errorBuilder.toString());
}
return "redirect:/customers/?id=" + customerId;
}
My form in my customerNewUser html file
<form
th:action="@{${user?.id} ? '/customers/' + ${customer.id} + '/createUser/' + ${user.id} : '/customers/' + ${customer.id} + '/createUser/'}"
th:object="${user}" action="#" method="post">
<div class="alert alert-danger" th:if="${#fields.hasAnyErrors()}">
<div th:each="detailedError : ${#fields.detailedErrors()}">
<span th:text="${detailedError.message}"></span>
</div>
</div>
<div class="form-group">
<div class="form-row">
<div class="col-md-5">
<label class="text-right label-control"
th:text="#{firstname} + ':'">Firstname:</label>
</div>
<div class="col-md-4">
<input type="text" id="firstname" name="firstname"
th:value="${user?.firstname} ? ${user?.firstname} : ''"
class="form-control" th:placeholder="#{firstname}"
required="required" autofocus="autofocus" th:field="*{firstname}"/>
<label th:style="'color: red;'" class="text-right label-control" th:if="${#fields.hasErrors('firstname')}" th:errors="*{firstname}" th:text="#{passwordError}">Password Error</label>
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<div class="col-md-5">
<label class="text-right label-control"
th:text="#{surname} + ':'">Surname:</label>
</div>
<div class="col-md-4">
<input type="text" id="surname" name="surname"
th:value="${user?.surname} ? ${user?.surname} : ''"
class="form-control" th:placeholder="#{surname}"
autofocus="autofocus" />
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<div class="col-md-5">
<label class="text-right label-control"
th:text="#{email} + ':'">Email:</label>
</div>
<div class="col-md-4">
<input th:placeholder="#{email}" required="required"
autofocus="autofocus" id="email" class="form-control"
type="text" th:value="${user?.email} ? ${user?.email} : ''"
name="email" th:field="*{email}"/>
<label th:style="'color: red;'" class="text-right label-control" th:if="${#fields.hasErrors('email')}" th:errors="*{email}" th:text="#{emailError}">Email Error</label>
</div>
</div>
</div>
<div class="form-group" th:if="!${user?.id}">
<div class="form-row">
<div class="col-md-5">
<label class="text-right label-control"
th:text="#{password} + ':'">Password:</label>
</div>
<div class="col-md-4">
<input type="password" id="password" name="password"
class="form-control" th:placeholder="#{password}"
required="required" autofocus="autofocus" th:field="*{password}"/>
<label th:style="'color: red;'" class="text-right label-control" th:if="${#fields.hasErrors('password')}" th:errors="*{password}" th:text="#{passwordError}">Password Error</label>
</div>
</div>
</div>
<div class="form-group" th:if="!${user?.id}">
<div class="form-row">
<div class="col-md-5">
<label class="text-right label-control"
th:text="#{passwordConfirmation} + ':'">Password confirmation:</label>
</div>
<div class="col-md-4">
<input type="password" id="matchPassword" name="matchPassword"
class="form-control" th:placeholder="#{password}"
required="required" autofocus="autofocus" th:field="*{matchPassword}"/>
<label th:style="'color: red;'" class="text-right label-control" th:if="${#fields.hasErrors('matchPassword')}" th:errors="*{matchPassword}" th:text="#{matchPassword}">Match Password Error</label>
</div>
</div>
</div>
<div class="form-group" th:if="${user?.id}">
<div class="form-row">
<div class="col-md-5">
<label class="text-right label-control"
th:text="#{userStatus} + ':'">Status:</label>
</div>
<div class="col-md-3">
<select class="form-control form-control" id="userStatus"
name="userStatus">
<option
th:each="userStatus : ${T(br.com.macrosul.stetho.entity.UserStatus).values()}"
th:text="${userStatus}" th:value="${userStatus}"
th:selected="${user.userStatus} eq ${userStatus}"></option>
</select>
</div>
</div>
</div>
<div class="form-group">
<p class="error-control" th:text="${signInError}"></p>
</div>
<input type="submit" class="btn btn-md btn-block"
value="Sign in"
th:value="${user?.id} ? #{updateUser} : #{signIn}" />
</form>
And here is the stacktrace when I try to force a password size error ->
@Size(min=6)
@Column(nullable = false)
private String password;
Field error in object 'user' on field 'password': rejected value [12345]; codes [Size.user.password,Size.password,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.password,password]; arguments []; default message [password],2147483647,6]; default message [tamanho deve estar entre 6 e 2147483647]
I want a simple validation. If there's a simpler way to indicate the user the data are invalid I would appreciate for any help or advice!
Upvotes: 0
Views: 2102
Reputation: 11
It is a little bit late, but you need to put your BindingResult next to your @valid attribute so instead of:
@ModelAttribute(name = "user") @Valid Users user, RedirectAttributes redirectAttributes, BindingResult bindingResult
you should write:
@ModelAttribute(name = "user") @Valid Users user, BindingResult bindingResult, RedirectAttributes redirectAttributes
Upvotes: 1
Reputation: 11
You can put a div in the html that only exists if there are errors on the validation. Then you show each error in a loop:
<div th:if="${#fields.hasErrors('*')}">
<p th:each="err : ${#fields.errors('*')}">
<span th:text="${err}"></span>
</p>
</div>
This way, when you return to this view there will be errors on your fields so this code will be shown.
Upvotes: 0
Reputation: 3282
You need a validator like below. Its not the exact code what you need but sufficient enough and pretty close to what you need to get you going.
@Override
public void validate(Object o, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "useremail", "NotEmpty");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userfirstname", "NotEmpty");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userlastname", "NotEmpty");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "useraddress", "NotEmpty");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "NotEmpty");
if (user.getPassword().length() < 8 || user.getPassword().length() > 32) {
errors.rejectValue("password", "Size.userForm.password");
}
if (!user.getPasswordConfirm().equals(user.getPassword())) {
errors.rejectValue("passwordConfirm", "Diff.userForm.passwordConfirm");
}
}
For more details you can take a look at here, here and here.
Upvotes: 0