Reputation: 157
I am trying to validate user registration. Scenario is common: If username or e-mail exist, then application must notify the user, which field was violated (Unique constraint). So far I have done the following: This method handles registration. Basically I try to commit transaction (insert) and if it fails, exception is caught with try catch.
@RequestMapping(value = "/registration", method = RequestMethod.POST)
public ModelAndView createNewUser(@Valid User user, BindingResult bindingResult) {
ModelAndView modelAndView = new ModelAndView();
try{
userService.saveUser(user);
modelAndView.addObject("successMessage", "User has been registered successfully");
modelAndView.addObject("user", user);
modelAndView.setViewName("registration");
}catch(DataIntegrityViolationException e){
bindingResult
.rejectValue("email", "error.user",
"There is already a user registered with the email provided");
}
return modelAndView;
}
This is my model class:
@Entity
@Table(name = "users")
public class User implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="user_id")
private Long user_id;
@Column(name="username")
@NotEmpty(message = "*Username is required")
@Length(min = 5, max = 20, message = "*Your username can have min 5 and max 20 characters")
private String username;
@Column(name="password")
@NotEmpty(message = "*Password is reqired")
@Transient
private String password;
@Column(name="email")
@Email(message = "*Please provide a valid Email")
@NotEmpty(message = "*Email is required")
private String email;
@Column(name="enabled")
private int enabled;
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 getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getEnabled() {
return enabled;
}
public void setEnabled(int enabled) {
this.enabled = enabled;
}
public Long getUser_id() {
return user_id;
}
public void setUser_id(Long user_id) {
this.user_id = user_id;
}
}
And this is my registration page:
<form autocomplete="off" action="#" th:action="@{/registration}"
th:object="${user}" method="post" class="form-horizontal"
role="form">
<h2>Registration Form</h2>
<div class="form-group">
<div class="col-sm-9">
<label th:if="${#fields.hasErrors('username')}" th:errors="*{username}"
class="validation-message"></label>
<input type="text" th:field="*{username}" placeholder="Username"
class="form-control" />
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<input type="text" th:field="*{email}" placeholder="Email"
class="form-control" /> <label
th:if="${#fields.hasErrors('email')}" th:errors="*{email}"
class="validation-message"></label>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<input type="password" th:field="*{password}"
placeholder="Password" class="form-control" /> <label
th:if="${#fields.hasErrors('password')}" th:errors="*{password}"
class="validation-message"></label>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<button type="submit" class="btn btn-primary btn-block">Register User</button>
</div>
</div>
<span th:utext="${successMessage}"></span>
</form>
Problem. Now the thing is that in my createNewUser method I do try catch. When unique violation occurs, catch block handles it. But what if there is multiple violations: username and email? How do I get from exception, which field was violated and associate it with right form field?
Upvotes: 0
Views: 311
Reputation: 57381
I would say you need to add your own custom validators to check unique username and email.
Code snipped from the example below. @Unique(service = UserService.class, fieldName = "email", message = "{email.unique.violation}") private String email;
Annotation and validator
@Target({ METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = UniqueValidator.class)
@Documented
public @interface Unique {
String message() default "{unique.value.violation}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<? extends FieldValueExists> service();
String serviceQualifier() default "";
String fieldName();
}
and
public class UniqueValidator implements ConstraintValidator<Unique, Object> {
@Autowired
private ApplicationContext applicationContext;
private FieldValueExists service;
private String fieldName;
@Override
public void initialize(Unique unique) {
Class<? extends FieldValueExists> clazz = unique.service();
this.fieldName = unique.fieldName();
String serviceQualifier = unique.serviceQualifier();
if (!serviceQualifier.equals("")) {
this.service = this.applicationContext.getBean(serviceQualifier, clazz);
} else {
this.service = this.applicationContext.getBean(clazz);
}
}
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
return !this.service.fieldValueExists(o, this.fieldName);
}
}
See the example
Upvotes: 1