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