Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreI 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.
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!
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:
<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"/>
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.