I have a simple form to save an User and I can't get it to show the error messages
I have the exact same structure for saving "Customer" and it works, but when I try to replicate it to User It doesn't work
My log error:
2019-08-21 17:07:14.521 WARN 11332 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by handler execution: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors Field error in object 'user' on field 'password': rejected value [123]; 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 [A senha deve conter pelo menos 6 caracteres.]
User controllers:
@GetMapping("/{customerId}/createUser")
public ModelAndView userForm(@PathVariable(value = "customerId", required
= false) Long customerId,
@RequestParam(value = "userId", required = false) Long userId,
Model model) {
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
Optional<Users> authenticatedUserOptional =
userRepository.findByEmail(authentication.getName());
model.addAttribute("userLogedIsAdmin",
authenticatedUserOptional.get().getIsAdmin());
if (authentication == null || !authentication.isAuthenticated()) {
ModelAndView mv = new ModelAndView("accessDenied");
return mv;
}
if (!authenticatedUserOptional.isPresent()) {
ModelAndView mv = new ModelAndView("accessDenied");
return mv;
}
if (customerId != null) {
Optional<Customers> customerOptional =
customerRepository.findById(customerId);
Customers customer = customerOptional.get();
model.addAttribute("customer", customer);
if (userId != null) {
Users existingUser = userRepository.findById(userId).get();
if (existingUser.getEnabled()) {
existingUser.setUserStatus(UserStatus.ATIVO);
} else {
existingUser.setUserStatus(UserStatus.INATIVO);
}
model.addAttribute("user", existingUser);
} else {
model.addAttribute("user", new Users());
}
ModelAndView mv = new ModelAndView("customerNewUser");
return mv;
} else {
ModelAndView mv = new ModelAndView("accessDenied");
return mv;
}
}
@PostMapping("/{customerId}/createUser")
public ModelAndView saveUser(@PathVariable(value = "customerId", required
= true) Long customerId,
@ModelAttribute(name = "user") @Valid Users user,
RedirectAttributes redirectAttributes,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return userForm(customerId, user.getId(), new Model() {
@Override
public Model mergeAttributes(Map<String, ?> attributes) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean containsAttribute(String attributeName) {
// TODO Auto-generated method stub
return false;
}
@Override
public Map<String, Object> asMap() {
// TODO Auto-generated method stub
return null;
}
@Override
public Model addAttribute(String attributeName, Object
attributeValue) {
// TODO Auto-generated method stub
return null;
}
@Override
public Model addAttribute(Object attributeValue) {
// TODO Auto-generated method stub
return null;
}
@Override
public Model addAllAttributes(Map<String, ?> attributes) {
// TODO Auto-generated method stub
return null;
}
@Override
public Model addAllAttributes(Collection<?> attributeValues)
{
// TODO Auto-generated method stub
return null;
}
});
}
// Encrypt password
if (user.getPassword().equals(user.getMatchPassword())) {
user.setPassword(encoder.encode(user.getPassword()));
user.setCustomerId(customerId);
user.setEventDescription("User Admin creation");
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);
ModelAndView mv = new ModelAndView("redirect:/customers/" +
customerId);
return mv;
} else {
ModelAndView mv = new ModelAndView("accessDenied");
return mv;
}
}
form html:
<div class="card mb-3">
<div class="card-header"
th:text="${user?.id} ? #{editUser} : #{newUser}">
<i class="fas fa-table"></i>
</div>
<div class="card-body">
<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}" />
</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}" />
</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}" />
</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}" />
</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" id="saveDiv">
<div class="form-row">
<div class="col-md-5"></div>
<div class="col-md-2">
<a class="btn-nounderline" href="#"> <input type="submit"
class="btn btn-md btn-block" value="Save"
th:value="${user?.id} ? #{updateUser} : #{save}" id="save" />
</a>
</div>
</div>
</div>
</form>
</div>
</div>
part of my model:
@Entity
public class Users extends BaseEntity {
private static final long serialVersionUID = -1667698094711992210L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator =
"users_seq")
@SequenceGenerator(name = "users_seq", sequenceName = "users_seq",
allocationSize = 50, initialValue = 1)
@JsonProperty(access = Access.READ_ONLY)
private Long id;
@NotBlank(message = "E-mail não pode estar em branco.")
@NotNull(message = "E-mail deve ser informado.")
@Email(message = "Formato inválido de E-mail.")
@Column(nullable = false, unique = true)
private String email;
@JsonProperty(access = Access.WRITE_ONLY)
@Size(min=6, message="A senha deve conter pelo menos 6 caracteres.")
@NotNull(message = "A senha deve ser informada.")
@NotBlank(message = "A senha não pode estar em branco.")
@NotEmpty(message = "A senha não pode estar vazia.")
@Column(nullable = false)
private String password;
@JsonIgnore
@Transient
private String matchPassword;
@JsonIgnore
@Column(nullable = false)
private Boolean enabled = true;
@NotNull(message = "O nome deve ser informada.")
@NotBlank(message = "O nome não pode estar em branco.")
@NotEmpty(message = "O nome não pode estar vazia.")
@Column(nullable = false)
private String firstname;
private String surname;
@Column(nullable = true)
private Long customerId;
@JsonIgnore
@Transient
private Boolean isAdmin;
@JsonIgnore
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
private List<Authorities> authorities = new ArrayList<>();
@Enumerated(EnumType.STRING)
@Transient
private UserStatus userStatus;
}
I simply can't understand why it does not show the error message, I'm pretty sure what's logged is not en error itself... Any help would be appreciated!
Might not be what is failing, but bindingresult has to follow the parameter it is validating. You can see more details on the answers here
So change:
public ModelAndView saveUser(@PathVariable(value = "customerId", required = true) Long customerId,
@ModelAttribute(name = "user") @Valid Users user, RedirectAttributes redirectAttributes,
BindingResult bindingResult) { ... }
To:
public ModelAndView saveUser(@PathVariable(value = "customerId", required = true) Long customerId,
RedirectAttributes redirectAttributes, @ModelAttribute(name = "user") @Valid Users user,
BindingResult bindingResult) { ... }