JSR 303 Bean Validation + Javascript Client-Side Validation
I would suggest that you look at Spring JS, which relies heavily on Dojo. A tutorial can be found here.
Easiest way for yourself to start playing with it is to download Spring Roo, create the petclinic sample application with one of the example-scripts (this takes you 5 minutes) and then play around with how the javascript is integrated. Spring Roo creates an app with the same technology stack that you use (Spring+hibernate+implementation of jsr 303)
I found this open source project but it looks dead, maybe it is worth resurrecting.
http://kenai.com/projects/jsr303js/pages/Home
This library provides client side validation of an HTML form based on JSR-303 and Hibernate Validator annotations, integrated with Spring MVC. The library provides a JavaScript validation code base that handles basic interaction with HTML forms, as well as JavaScript functions implementing the validation annotations supported by Hibernate Validator (including those not from the JSR-303 spec). This JavaScript code base can be included in a page by using a provided taglib or by extracting the JavaScript file from the jar and including it using a tag. Once this code base has been included in a page, a second taglib is used to generate the JavaScript code for validating an HTML form. You can also provide a JSON object in the body of the tag to specify additional configuration information.
Here's how I'm doing it using Spring MVC + JQuery + Bootstrap, partially based on a recent blog post at SpringSource:
AddressController.java
@RequestMapping(value="/validate")public @ResponseBody ValidationResponse processForm(Model model, @Valid AddressForm addressForm, BindingResult result) { ValidationResponse res = new ValidationResponse(); if (result.hasErrors()) { res.setStatus("FAIL"); for (ObjectError error : result.getAllErrors()) { if (error instanceof FieldError) { FieldError fieldError = (FieldError) error; res.addError(fieldError.getField(), fieldError.getDefaultMessage()); } } } else { res.setStatus("SUCCESS"); } return res;}
AddressForm.java
public class AddressForm { @NotNull @Size(min=1, max=50, message="Address 1 is required and cannot be longer than {max} characters") private String address1; @Size(max=50, message="Address 2 cannot be longer than {max} characters") private String address2; // etc}
ValidationResponse.java:
public class ValidationResponse { private String status; private Map<String,String> errors; // getters, setters}
address.jsp:
<f:form commandName="addressForm"> <div class="control-group"> <label for="address1">Address 1</label> <div class="controls"> <f:input path="address1" type="text" placeholder="Placeholder Address 1" class="wpa-valid" /> <span class="help-inline"></span> </div> </div> <!-- etc --> <div class="form-actions"> <button type="submit" class="btn btn-primary">Save</button> <button type="button" class="btn">Cancel</button> </div></f:form><script type="text/javascript">function collectFormData($fields) { var data = {}; for (var i = 0; i < $fields.length; i++) { var item = $($fields[i]); data[item.attr("id")] = item.val(); } return data;}function clearErrors($fields) { for (var i = 0; i < $fields.length; i++) { var item = $($fields[i]); $("#"+item.attr("id")).parents(".control-group").removeClass("error"); $("#"+item.attr("id")).siblings(".help-inline").html(""); }}function markErrors(errors) { $.each(errors, function(key, val) { $("#"+key).parents(".control-group").addClass("error"); $("#"+key).siblings(".help-inline").html(val); });}$(document).ready(function() { var $form = $("form.validate"); $form.bind("submit", function(e) { var $fields = $form.find(".validate"); clearErrors($fields); var data = collectFormData($fields); var validationUrl = "validate"; $.get(validationUrl, data, function(response) { $("#alert").removeClass(); if (response.status == "FAIL") { markErrors(response.errors); $("#alert").addClass("alert alert-error"); $("#alert").html("Correct the errors below and resubmit."); } else { $("#alert").addClass("alert alert-success"); $("#alert").html("Success!"); $form.unbind("submit"); $form.submit(); } }, "json"); e.preventDefault(); return false; });});</script>
It could use some refactoring, but this will do an ajax GET with the form data and update the page based on the result.