No More Page Refreshes: use jQuery!
Here's an open apology to users of web sites I helped build: “Sorry I made you suffer through unnecessary page refreshes.” That's the first thing that popped into my head after learning about jQuery earlier this year.
jQuery is a powerful yet unobtrusive JavaScript library with a lousy name. It's concise, very readable syntax has me exciting about writing JavaScript again. It's unobtrusiveness makes it easy to add rich behavior—such as background form submissions—to web applications with very little modification of existing code. Being unobtrusive is particularly important when you are working with a large code base, or where extensive refactoring just isn't going to get funding. My boss is not going to give me 4 weeks to go back and add some visual goodness to an existing site. But I might get 4 hours, and that's where jQuery can help.
As a simple example, imagine an automobile search function that returns results based on a vehicle Model. Enter text into the field, click submit, and the results are displayed. The JSP might look like:
After the user enters a name and clicks submit, the entire screen turns white while the page refreshes and then the results are displayed. This is not a good user experience. Now, let's use jQuery to improve that experience by refreshing only the part of the page that actually needs to change. The modifications made to the existing page are:
- Split the search form and search results into 2 separate JSPs so the results can be displayed separately, without having to re-render the search form.
- Add a placeholder <div> on the search form JSP to hold the search results.
- Add a line of jQuery that submits the search form in the background using AJAX, placing the results in the placeholder <div>.
The resulting code looks like this:
When the user enters a name and clicks submit, only the search results <div> will refresh. The user experience is improved, and we didn't have to write a lot of JavaScript. Let's look at the jQuery script fragment in a little more in depth:
The code reads:
Line 2 -- “When the page gets loaded...”
Line 3 -- “Select a form with an id= 'searchForm', and make it AJAX-enabled (submit in the background)”
Line 4 -- “Use POST as opposed to GET”
Line 5 -- “Puts the results in a DIV with an id of 'searchResults'”
Lines of jQuery code start with “$()” and always select an element such as “document” or “#searchForm” to operate on. jQuery acts like a decorator and allows you add all kinds of interesting behavior to elements such as AJAX-enabling forms, visual effects, drag-and-drop, and more.
The example shows a lot of functionality baked into a couple of lines of code, and demonstrates why I like jQuery: the decorator approach makes it ideal for enhancing existing web apps. Rather than rewriting existing HTML, you can apply jQuery to decorate it and add new behavior.
Returning data instead of HTML using Spring MVC and XStream/Jettison
In the first example, jQuery was used on the client, but nothing significant was changed on the server. We still kept the basic flow, which involved the user clicking on something in the browser, a server request being created, and HTML being returned. But what if the server can return data in the form of JSON or XML instead of HTML?
Returning data rather than renderable HTML allows the client to potentially cache the result, which reduces the number of server requests. Data is potentially more terse than HTML—this also reduces the size of the result when it needs to be returned. Look at the following example:
In the standard flow, three user interactions with browser result in three server requests. Now let's look at an optimized flow where the server returns data instead of HTML:
In the optimized flow, three user interactions only generated one server request.
There are many potential data formats that can be returned by the server. Which one to select depends on the situation. Some options and reasons for selecting them:
Server Response Format | When to Use | Frequency of Use |
Entire HTML pages | Initial page load | Low |
HTML snippets | Places were server-side rendering is easier or necessary. For example you're rendering a table with the popular <displaytag> tag library. | Low |
JSONB { "car": { "id": "5", "make": "Acura", "model": "MDX" } } |
Good general purpose data format that can be used for most server responses. Concise and easy to work with in JavaScript. | High |
XML <car id="5"> <make>Acura</make> <model>MDX</model> </car> |
Complex data that cannot be easily represented in JSON. XML's structure contains elements and attributes, while JSON only has elements. | Low |
Let's look at a code example where the server returns JSON data to the browser. Let's replace the original car model search page with a page that includes both a make and model drop-down. When the user selects make, the models for that make are populated. When the user selects a model, a table listing the available model years is populated.
Starting on the server side, we will see how we can use Spring MVC along with XStream and Jettison to serve up JSON data. First we'll build a Spring MVC controller:
Line 1 – The @Controller annotation tells Spring MVC to use this class as, you guessed it, a controller
Line 4 – The @RequestMapping annotation maps the request URL to the handler method
Line 6 – A ModelAndView object is created with a view name of “carselector” which will get mapped to carselector.jsp
Line 7 – A list of Makes is added to the ModelAndView using the key “makeList”. This object will be available in the JSP using the expression: ${makeList}
Line 11 – Again, the @RequestMapping annotation maps the request URL to the handler method
Line 12 – The @RequestParam annotation maps a request parameter to a method argument
Line 13 – This ModelAndView is created using a simple JSON-rendering View class that I wrote called JsonView. Spring MVC makes is quite easy to write custom views, and JsonView is where XStream gets hooked in.
Line 14 – A list of Models is added to the ModelAndView using a key that is expected by JsonView.
In summary, the controller responds to two URLs, “carselector.html” and “models.html”. It renders an HTML page as the response to the “carselector.html” URL, via a standard JSP view. Let's take a look at the JsonView class, which renders the JSON result for the “models.html” request:
Line 4 – XStream is instantiated using the JettisonMappedXmlDriver to output JSON instead of XML
Line 6 – Spring MVC View classes must implement a render() method
Line 9 – Get the data out the model that was created by the controller
Line 11 – Actually generate the JSON (despite the fact that the method is named toXML)
It really is that easy. The XStream library also includes a set of annotations that you can place on your domain or transfer objects to provide hints on how to render the JSON, but in general the library works with minimal configuration.
Now the server is generating JSON, but how does the client use it? For that answer, we'll look at jQuery again. Remember, there are 2 events that we need to handle: selecting a value from the “make” dropdown populates the “model” dropdown. Selecting a value from the model dropdown populates the model year table. Here's the jQuery ready function that sets up the event handlers:
The “select[name^=make]” expression looks a lot like a CSS selector, and that's because jQuery selectors are a super set of CSS selectors (kind of like if CSS and Regex had a baby together). These expressions are very powerful, and can be used to select single or multiple items at a time. In this case, the expression reads, “Select a <select> element whose name attribute is 'make' and bind the loadModels function to the change event". Every time a user selects a value from the dropdown, the change event is generated by the browser, and the loadModels function will get invoked.
Now let's take a look at one of the event handlers:
Line 2 - The getJSON method will perform a AJAX request and expect JSON returned by the server. It requires 3 parameters: the request URL, any request parameters, and a callback function to invoke once the server responds.
Line 4 - The callback function is a closure. Closures in JavaScript are similar to anonymous inner classes in Java, and they are very useful to use as callbacks. Notice that this function expects the JSON returned from the server to be passed in as a parameter.
Line 6 - At this point we need to know a little bit about the structure of the JSON we're working with. In this simple example, the model data is structured as the following:
The code at line 6 reads, "For each model..."
Line 7 & 8 - Construct an element from each model
Line 10 - Select the <select> element where name=model, and replace the option list with the options that were just constructed.
With the bare minimum of JavaScript, we were able to:
- register an event handler,
- get JSON data asynchronously
- update the options in a dropdown based on that JSON.
That's powerful stuff, and one of the reasons I really like jQuery. Now what about caching? It is a trivial case to add an "if" statement prior to the getJSON call to see if the result already exists in cache. There is a nice little jQuery plugin called jCache that you can use.
Conclusion
jQuery + Spring MVC + XStream/Jettison provides a really nice stack to rapidly develop web applications that cleanly separate data and presentation, provide the user with a better experience, and potentially improve performance along the way. Are there other high-quailty frameworks that can help you do this? Sure, but I like the combination of jQuery, Spring MVC and XStream/Jettison, and I feel each are "best-of-breed" in their particular niches.
YOu can download the full example code HERE.
About the Author
Since his first Java assignment, printing reports with Java 1.02, Joel Confino has been hooked on Java technology. He has been working on distributed systems, various web architectures, and JEE design and programming for the past 10 years. Confino has consulted at many large financial services and pharmaceutical companies, and helped them use Java to expand their business and reach their customers with sophisticated web-based systems. He is currently a Java architect at Chariot Solutions.
About Chariot Solutions, LLC
Chariot Solutions is an IT consulting firm specializing in application development and systems integration using Java and open source technologies. Chariot consultants include some of the top software architects in the country, all of whom possess a rare combination of deep technical expertise, applied industry knowledge and a genuine love for what they do. Chariot's consulting team has made the company the optimal partner to design, develop, deploy, integrate, support and tune mission-critical systems for companies of all sizes. Visit Chariot on the web at www.chariotsolutions.com.