This technique should be used when you need to do ALL your controller’s validation yourself, and you can’t or don’t want to make use of the Hibernate’s reference implementation of a JSR 303 validator. From this, you’ll guess that you can’t mix your own custom Spring validator with Hibernate’s JSR 303 validator.
The MVC command object is a simple matter of tying together a few address fields:
public class Address {
private String street;
private String town;
private String country;
private String postCode;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getTown() {
return town;
}
public void setTown(String town) {
this.town = town;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getPostCode() {
return postCode;
}
public void setPostCode(String post_code) {
this.postCode = post_code;
}
}
Create a custom validator
@Component
public class AddressValidator implements Validator {
/**
* Return true if this object can validate objects of the given class. This is cargo-cult
* code: all implementations are the same and can be cut 'n' pasted from earlier examples.
*/
@Override
public boolean supports(Class clazz) {
return clazz.isAssignableFrom(Address.class);
}
/**
* Validate an object, which must be a class type for which the supports() method returned
* true.
*
* @param obj The target object to validate
* @param errors contextual state info about the validation process (never null)
*/
@Override
public void validate(Object obj, Errors errors) {
Address address = (Address) obj;
String postCode = address.getPostCode();
validatePostCode(postCode, errors);
}
private void validatePostCode(String postCode, Errors errors) {
if (isValidString(postCode) && isNotBirminghamPostCode(postCode)) {
errors.rejectValue("postCode", "AddressValidator.postCode.notBirmingham",
"Not a Birmingham Post Code");
}
}
private boolean isValidString(String str) {
return isNotNull(str) && (str.length() > 0);
}
private boolean isNotNull(String postCode) {
return postCode != null;
}
/** The first character of the Birmingham post code is 'B' */
private boolean isNotBirminghamPostCode(String postCode) {
char val = postCode.charAt(0);
return val != 'B';
}
}
Attaching the validator to the controller is pretty straight forward. The first step is to annotate the Address command object with @Valid:
@RequestMapping(value = PATH, method = RequestMethod.POST)
public String addAddress(@Valid Address address, BindingResult result, Model model) {
The second step is to inject the validator into the data binder:
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(addressValidator);
}
Adding these two code snippets together, the complete AddressController code looks like this:
@Controller
public class AddressController {
private static final String FORM_VIEW = "address.page";
private static final String PATH = "/address";
@Autowired
private AddressValidator addressValidator;
/**
* Create the initial blank form
*/
@RequestMapping(value = PATH, method = RequestMethod.GET)
public String getCreateForm(Model model) {
model.addAttribute(new Address());
return FORM_VIEW;
}
/**
* Attach the custom validator to the Spring context
*/
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(addressValidator);
}
/**
* This is the handler method. Check for errors and proceed to the next view
*/
@RequestMapping(value = PATH, method = RequestMethod.POST)
public String addAddress(@Valid Address address, BindingResult result, Model model) {
if (!result.hasErrors()) {
model.addAttribute("noErrors",
"No Errors This Time for postal code: " + address.getPostCode());
}
return FORM_VIEW;
}
}
Same Validation Using JSR 303 validator
public class Address {
// These JSR 303 built in annotations don't do anything
// When you've injected your own validator
@NotEmpty
@Size(min = 1, max = 12)
private String street;
@NotEmpty
private String town;
@NotEmpty
private String country;
@NotEmpty
private String postCode;
0 comments:
Post a Comment