Blogs

SpringSource Blog

Integrating Spring MVC with jQuery for validation rules

Michael Isvy

I was thrilled to see in a recent survey from zeroturnaround that Spring MVC was voted the most popular web framework for Java.

This framework is very flexible and there are dozens of ways to use it. As with all flexible frameworks that have many options, it is important to discuss common practices.

The project I have created for this blog entry uses features common in many Spring MVC applications. You will find something like this:

In controllers you will find typical Spring MVC features for mapping requests, extracting request data through annotations, data binding, file upload…

On the other hand, inside JSPs, most of the HTML is written natively (as opposed to being generated by Spring MVC tags). Moreover, the Spring MVC tag libraries do not generate any Javascript code.

We are first going to discuss how to integrate Spring MVC with jQuery and Bean Validation. We will then see how to make those JSPs less verbose.

Bean Validation?

JSR 303 Bean Validation provides a comprehensive way to declare validation rules. Here is an example:

public class DiningForm {
  @Pattern(regexp="\\d{16}")

  private String creditCardNumber;

  @Size(1)
  private String merchantNumber;

  @Min(0)
  private double monetaryAmount;

  @NotNull
  private Date date;

  ...

}

When validation is called, an instance of DiningForm is validated against the annotations above.

From Spring 3.0, Spring MVC integrates with Bean validation for validation rules (that’s not the only way to do validation with Spring @MVC but it is obviously becoming the most common approach).

In a controller method, we can use @Valid as follows:

@RequestMapping(value="/update", method=RequestMethod.POST)
  public String update(@Valid DiningForm diningForm, BindingResult result) {

    if (result.hasErrors()) {
      return “rewards/edit”;
    }

    // continue on success...

  }
}

At the JSP level, error messages can be displayed using <form:errors />:

<form:form modelAttribute="diningForm">
  <form:input path="firstName"/>
  <form:errors path="firstName"/>
  …
</form:form>

The code above is fairly simple and works well. But it does not generate any Javascript. Consequently it does not allow partial rendering or client side validation. Let’s see how to improve that!

Adding Javascript for partial rendering

Let us consider what happens when “first name” is empty.

In the previous example, the whole page was refreshed every time the form was submitted. Here is an extract of the HTML response:

Our target is to minimize the response size. We should be able to have such response instead (using json syntax):

{"status":"FAIL","result":[{"fieldName":"firstName","message":"firstName  may not be empty"}]}

Firstly, we will use a jQuery form submission to validate the form. When the form will be considered as valid, form submission will be triggered using regular HTML form submission (in that way we'll be able to redirect to a different page).

Let us first create a simple ValidationResponse class as follows:

public class ValidationResponse {
 private String status;
 private List errorMessageList;

 public String getStatus() {
   return status;
 }
 public void setStatus(String status) {
   this.status = status;
 }
 public List getErrorMessageList() {
   return this.errorMessageList;
 }
 public void setErrorMessageList(List errorMessageList) {
   this.errorMessageList = errorMessageList;
 }
}

Inside the controller class, we can add an action method:

@RequestMapping(value="/user.json")
public @ResponseBody ValidationResponse processForm (Model model, @Valid User user, BindingResult result ) {
 ValidationResponse res = new ValidationResponse();
 if(!result.hasErrors()){
   res.setStatus("SUCCESS");
 }
 // …
 return res;
}

Thanks to the @ResponseBody annotation, the returned object will be converted into JSON as explained in the diagram below:

Inside the JSP, the error message is parsed and displayed if appropriate. You can browse the Javascript code for more details.

According to progressive enhancement best practices, all Javascript code has been placed outside the HTML form. In case Javascript is disabled on a client’s browser, the form falls back into full page refresh.

Now that we have partial refresh working for validation rules, there are 2 points that still need improvement:

  • This page does not look cool!
  • This hello-world-style page has 100 lines already. There should be some ways to make it shorter.

Let’s make it pretty with Bootstrap

Even though this is not directly related to Spring MVC, it was hard for me to present a sample application with such a poor UI design. In case you haven’t heard of it yet, twitter Bootstrap is becoming the de facto CSS framework.  Many developers love it because it allows to make an acceptable design for a website with little effort. After copying the Bootstrap CSS and images, I just need to use the Boostrap CSS classes (see the JSP source code for more details). My form now looks like this:

Using custom tags to avoid the “JSP soup” syndrome

That’s where things become really interesting: even though we have some code which is working already, it is pretty hard to read. We are mixing together HTML, Javascript, CSS and JSP Expression Language. It would be more readable if my JSP code looked something like this:


<html:form modelAttribute="user"  id="add-user-form" formUrl="/userAjaxCustomTag.htm">
 <html:inputField name="firstName" label="Enter your first name:" />
 <html:inputField name="lastName" label="Enter your last name:" />
 <div>
   <button type="submit">Save changes</button>
   <button type="reset">Cancel</button>
 </div>
</html:form>

Custom tags are part of Java EE and also work great on Apache Tomcat. It is surprisingly easy to create a custom tag. Let us take a simple example with form input fields. We currently use this syntax (8 lines):

<div id="firstName">
 <label>Enter your first name:</label>
 <div>
   <form:input path="firstName" />
   <span>
     <form:errors path="firstName" />
   </span>
 </div>
</div>

Our goal is to use this instead (1 line):

<html:inputField name="firstName" label="Enter your first name:" />

In the WEB-INF folder, I can create a new tag file as follows:

Its content is the following:

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ attribute name="label" required="true" rtexprvalue="true" %>
<div id="${name}">
 <label>${label}</label>
<div>
  <form:input path="${name}"/>
  <span><form:errors path="${name}"/></span>
</div>

Back in userForm.jsp, I just need to declare the tag folder:

<%@ taglib prefix="html" tagdir="/WEB-INF/tags/html" %>

And I can use this newly created tag as follows:

<html:inputField name="firstName" label="Enter your first name:" />

Custom tags are well integrated in Eclipse/STS and I even have access to code completion:

In a similar fashion, I can also externalize the JavaScript code into a tag so I just have one line to call:

<ajax:formPartialRefresh validateUrl="/userAjaxBootstrap.json" formName="add-user-form"/>

Conclusion

We have discussed partial rendering in form validation with Spring MVC. In just a few minutes, we have turned JSP soup into something which is much simpler and easier to understand.

You are welcome to have a look at the corresponding sample application on github.

Credits: I would like to thank my friend Nicholas Ding who worked with me on building the code samples for this blog entry.

Similar Posts

Share this Post
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • DZone
  • LinkedIn
  • Slashdot
  • Technorati
  • Twitter
 

35 responses


  1. Browsing the sample application on github, I expect the final version of the JSP, that invokes your html: and ajax: tags, to be here:

    https://github.com/michaelisvy/ajax-samples/blob/master/src/main/webapp/WEB-INF/jsp/04-custom-tag/userForm.jsp

    But this file looks a bit… sparse. Is the rest of the JSP elsewhere?


  2. Thanks for this post because i LOVE this architecture : Spring MVC, JSON, JQUERY, BOOTSTRAP ! The big benefit here is decoupling layers then you have a "web services" layer thanks to Spring MVC and the whole in a very straightforward way ! Spring I LOVE YOU !!!!!


  3. @Corby: it seems that github only shows the first line of the file in the preview. You need to click on RAW if you want to see the whole file.


  4. @Michael: Thanks! That's odd, the other JSP pages in the Github project don't have that issue:

    https://github.com/michaelisvy/ajax-samples/blob/master/src/main/webapp/WEB-INF/jsp/03-bootstrap/userForm.jsp


  5. Thanks for this usefull post!
    Just one question… If I want to use this architecture for building an Intranet Portal can I implement all the view layer just with bootstrap css or is it better to use some template approach such as tiles or velocity ?

    Regards


  6. @Michael
    After reading the post i thought that form submission via jquery provides a new entry point to an application (which is written with plain old JSP). Fortunately, I did download project from GitHub and after looking at sources i think i grab the idea – jquery form submission is just to validate form, and only if validation is successful, old-style form submission (with page refresh) is performed. Maybe it would make sense to explain it upfront in the post.
    Beside, I am not sure if double validation (first for AJAX and then for full page refresh requests) will always make sense. In case you use complex validations ( or even access DB from validators) double-validation-approach could hurt users more than full page refresh…


  7. Two notes:
    - use jspx/tagx instead of jsp
    - the idea of java script validation is that it doesn't need to hit server at all.
    Your solution still makes a call to the backend to do the validation. This is not ideal. Better if validation is done entirely in javascript, and call to backend is only done if javascript is not available.


  8. @Tim
    I do not agree with your comment… For security reason the last validation MUST be done on the server side! Bypassing a javascritp validation it's a work that every "script kid" can do by just using firebug or any javascript debugger.
    You cannot trust the client for validation… only the server can be used to validate before doing business logic or saving data on the db…

    Cheers..

    Fabio


  9. @Michael,

    This is great…
    I've been pushing for this integrations jQuery-Web MVC eons ago.
    Finally it has resonated with someone out there.

    Nice work!

    B. Roogards
    jD @ http://pragmatikroo.blogspot.com/2011/11/spring-roo-synergy-automatic-datatype.html


  10. Hi,

    Thanks for the post. Its very useful for all developers who are using Spring MVC and Jquery.
    I have implemented the above architecture. However, i am facing errors when there are non-string properties in my class.
    for ex:
    class employee {
    Integer empid;
    }

    @ResponseBody … registration(@RequestBody employee emp, Bin….)

    everything works fine when i change Integer to String. Spring itself is returning error to my AJAX call saying 400 BAD request.

    on the client side, am making AJAX calls using JQuery. Am not using spring tag libraries.
    Kindly let me the solution for this. Does it require any specific configuration?
    Am using latest Spring 3.2

    Thanks,
    Abdul


  11. Hi Michael,

    Thanks for the post. This would be very helpful for all developers using Spring MVC.
    I have implemented similar functionality. However, i am facing issues when i use non-string properties in my class.
    for ex:
    Class employee {
    Integer empid;
    }
    When i try to use this in my Controller function in below way, Spring is sending ERROR to client.
    @ResponseBody succes registration(@RequestBody employee emp, BindingResult res){

    }

    When i change the Integer to String, everything works fine. If it is Integer, Spring replies back to client with 400 Bad request.

    Am using Jquery AJAX calls to POST the data. and not using spring tag libraries.
    Am i missing something here? Does this conversion require any special configuration?
    Kindly let me know your suggestions.

    Thanks,
    Abdul


  12. @Fabio (about using Bootstrap in a portal environment)
    twitter Bootstrap certainly works in a Portal environment (I'm guessing that there are probably a few Bootstrap styles that you can't use in a Portal but it'll be fine for most of them).
    Apart from that, you still could use Tiles in addition to custom tags if you'd like. Being in a Portal environment won't make any difference there (it's just a matter of whether or not you want to use templates at the page level).


  13. @Tim
    (regarding tagx/jspx)
    I didn't use them because, when working with tagx/jspx, I've always had some issues with code completion in Eclipse. I had it work a couple of times but I do find it much less stable than using the "old" syntax.

    (regarding true client-side validation)
    As you pointed out, in my example, all the validation logic is on the server-side. So we do have partial-refresh but we do not have "true client-side validation". And there are many cases where it would be more suitable to have "true client-side validation" indeed. But I couldn't show that in a blog entry: we need to parse the POJO classes at startup time and generate JavaScript calls accordingly. That's a much more technical and complex task to achieve.
    Also, I had a quick look at other Java web frameworks. Most of them integrate with Bean Validation in the way I've shown (partial-refresh with validation logic on the server side). The only one that seems to provide true client-side validation is Rich Faces (from their website, I haven't tested it myself).


  14. @Abdul
    I just tried in my sample application and it works fine.
    Have you used the right bean validation annotation? (it should be @NotNull instead of @NotEmpty)

    public class User {

    @NotEmpty
    private String firstName;

    @NotEmpty
    private String lastName;

    @NotNull
    private Integer age;

    }


  15. @Miluch
    Thanx for your feedback. I've updated this blog entry to explain better that we indeed require 2 form submission steps.


  16. Ah! Figured it out. Problem was different.

    Thanks for the response Michael.
    When i use '@ModelAttribute' in my mapping method, am receiving all empty data
    public @ResponseBody JsonResponse DoRegistration(@ModelAttribute(value="boutique") @Valid BoutiqueNew boutique, BindingResult result)

    If i change the ModelAttribute to @RequestBody, Spring is throwing error that BindingResult must be succeeded with ModelAttribute.
    public @ResponseBody JsonResponse DoRegistration(@RequestBody @Valid BoutiqueNew boutique, BindingResult result)

    Would @Valid work only on ModelAttributes? Is there any other way of making it work?

    This is my request payload for first case where @ModelAttribute field returns empty,
    {"boutique":{"email":"isha@gmail.com","password":"isha","username":"isha","name":"isha","country":"India","state":"AP","city":"hyd","address":"hyd","zipcode":"500029","mobile":"9000766605","telephone":"23456789","website":"http://netvogue.org","estdyear":1989,"productlines":[],"brandsselected":[]}}

    This is my request payload for second case.i.e.while using @RequestBody,
    {"email":"isha@gmail.com","password":"isha","username":"isha","name":"isha","country":"India","state":"AP","city":"hyd","address":"hyd","zipcode":"500029","mobile":"9000766605","telephone":"23456789","website":"http://netvogue.org","estdyear":1989,"productlines":[],"brandsselected":[]}

    Kindly suggest me how to resolve this.

    Thanks,
    Abdul


  17. I would prefer a solution that handles the REST verb and error validation in a single method rather than writing lots of separate validation routines. Surely this is possible w/ Spring 3.1 which supports both @RequestBody and @Valid annotations on the same parameter.


  18. Hi,

    Thanks for the reply.
    How can i check the validation results if i have @RequestBody and @Valid?, as BindingResult is applicable only in the case of @ModelAttribute.

    Also,
    Can you give me any pointers for implementing error validations in single method? As of now, i couldn't find out any article for that.

    Thanks once again,
    Abdul


  19. Hi Abdul,

    My comment was for the article author :-) But WRT to your question, you can annotate w/ @Valid and include a BindingResult parameter and it will be initialized.

    Chance


  20. Hi Chance,

    When i tried adding BindingResult parameter with @RequestBody @Valid, its giving me below error,
    Code:
    public @ResponseBody JsonResponse DoRegistration(@RequestBody @Valid BoutiqueNew boutiqueNew, BindingResult result) throws Exception {

    Error:
    rg.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: An Errors/BindingResult argument is expected to be immediately after the model attribute argument in the controller method signature: public org.netvogue.server.webmvc.domain.JsonResponse org.netvogue.server.webmvc.controllers.BoutiqueNewController.DoRegistration(org.netvogue.server.webmvc.domain.BoutiqueNew,org.springframework.validation.BindingResult)


  21. Ah, I see. I guess you have to use a Validator instead of a BindingResult then.


  22. Ah I see. I guess you have to use a Validator instead of a BindingResult then.


  23. @Michael Isvy
    Anyone who works at springsource will tell you jspx/tagx is best practice. Although, I know several cases where its a pain.

    I agree with what you said about cilent/server side validation.

    What I would like to see:
    - DWR like frame work that generates the client side javascript based on the server side JSR303 validation. DWR already generates javascript objects for pojo's, so its not much further to go.

    Also, there are cases where client side validation is not possible, eg:
    check is username is already taken.
    in this case, your pattern is ideal.


  24. GREAT post!


  25. This will be very handy!


  26. Helpful coding stuff.


  27. Great post and a great exercise, Mike!

    Still, if Javascript is enabled and the goal is to minimize traffic, better than just do the validation on the client size. There are plenty of JQuery validation plugins out there. I don't see any reason why to contact the server with a REST-WS request just to pick up (validation) info that can be computed by the client.
    The target niche o REST-WS is really to pickup data that the client does not have and can not infer — and without always using synchronous transfer of HTML.
    Any way, great toy solution for Spring students learning purpose…but, from my part at least, with some reservation for suitability to real world and/or take the badge of a best practice.

    Cheers, Jorge.


  28. Hi Jorge,
    you're right, "true client-side validation" would be better. But the idea was to use Bean-validation as a single point for declaring validation rules.
    What you're saying would be easy if we had easy-access to bean validation rules from Javascript (including translation of Bean Validation expressions to Javascript). Not that it's impossible, but it requires much more work :) .


  29. Mike, two solutions:
    1) (manual away) Make the JS validation rules consistent with the BeansValidation annotations. e.g.:
    @Pattern("regex") String phone;

    , is mapped to JS rule:

    $("#formId").validate({phone: { pattern; "regex"}, ..})

    , assuming a typical syntax for JS/JQuery plugins.

    2) (auto way) Use (or implement your own) JSP Taglib that that generated the JS code, by looking at the BeansValidation annotation.
    (BTW, I'm working on that approach my self — for release with my delaye by upcoming finite future alway present company :O)
    TIP: You could do the same by extending the Spring form Taglib. Maybe you could get a salary raise. If I got one, I would do it my self. :o )

    Cheers,
    Jorge.


  30. Hi Michael!

    great article and congrats for having the sample application on github for us to browse. I am fairly new to Spring MVC and I have one question.
    I wandering how it is possible to also style the input field with twitter bootstrap class error? The problem is that it requires the class "error" to be added in the div of class "control-group". For instance:

    Input with error

    Please correct the error

    I would really appreciate your help on this!

    Cheers


  31. @Yiannis thanx for your feedback!
    Unfortunately your question is more related to CSS and Bootstrap and I don't know a lot about those topics myself. Just ask the twitter Bootstrap community forums here:
    http://www.twitterbootstrap.net/forum/forum.php?s=26c2b948745bedf3e2f9f0bdda0cfd38

    Cheers,
    Michael.


  32. Good presentation, Your information is very helpful for me. Thank you very much….


  33. @Tim I have just migrated this app to JSPX.
    It's true that I didn't seem to have any auto-complete issue in Eclipse anymore.
    However using CDATA for all Javascript code is a bit annoying (especially because error messages are unclear in case you forgot to use CDATA). I wish jspx were better integrated in Eclipse.


  34. @Michael can you put all your javascript code in external js files?

    I agree, jspx does cause some problems..


  35. @Tim yes it is possible. But even your script tags, when referring to a file, should be surrounded with a CDATA bloc.

    < ![CDATA[