Spring MVC Application with JQuery for View

P.Madhanasekaran

There is increase in the adoption of server side JavaScript frameworks especially “Node.js” for various reasons. 1) Being reactive, it provides solution to “10CK” problem, serving millions of concurrent requests 2) the users are able to use JavaScript, the language they use in the Browser and follow the same programming model when they use Node. The reasons have given Node an edge. But still “JAVA” frameworks based on traditional multi-threaded but blocking Servlet design model are in wide use on the server side, though Node-like frameworks like Vertx, Play  and Project Reactor(from Spring Source) have emerged as alternatives .  But, the role of Servlet based frameworks has also somewhat changed, as can be seen from the opinion of an authority quoted below. Even in projects where Java is used is for the back-end, there is a movement away from server-side view rendering technologies like JSP to client- side JavaScript view- rendering technologies like JQuery, Angular etc..

I think we’re at a stage now  where the Java language itself is becoming less important - that’s not particularly because Java is in decline but because more and more people are involved in polyglot programming projects.  Now I’m not talking about using Scala, Clojure or whatever is hype on the JVM but what is really creeping in is Javascript.  At first a little bit of dynamic browser code to produce a visual effect or an animation, then developers start putting using jquery to add client-side functionality, such as form validation.
Eventually a green field project in your organisation uses a javascript framework such as Angular or Backbone and the only thing left for Java/The JVM to do is produce JSON.  Now not everyone will be going down this path but an increasing chunk of development applications will be.  At the same time Java is continuing its push into event driven applications and the high performance space.  So the future for both Java and the JVM is really to be more about data analysis and event processing and less about UIs.

In our sample Spring MVC project now, we will see how Spring MVC can work together with a JavaScript library like JQuery. The immediate benefit is that we can make the view Ajax-enabled. As you know in Ajax, once a page is loaded it will not be refreshed; but only a part of it will be re-loaded with fresh data received from the server. As pointed out in an earlier article JQuery plays its role after the page is loaded to provide user interaction and to easily and quickly add enhancements to the appearance and behaviors of their web pages. JavaScript code usually is used to traverse the (DOM) tree and locate specific portions of an HTML document's structure and manipulate them. With jQuery, developers have a robust and efficient selector mechanism at their disposal, making it easy to retrieve the exact piece of the document that needs to be inspected or manipulated. jQuery can modify the content of a document itself with a few keystrokes. Text can be changed, images can be inserted or swapped, lists can be reordered, or the entire structure of the HTML can be rewritten and extended. The jQuery library offers an elegant way to intercept a wide variety of events, such as a user clicking on a link, without the need to clutter the HTML code itself with event handlers. At the same time, its event-handling API removes browser inconsistencies that often plague web developers. The jQuery library facilitates this by providing an array of effects such as fades and wipes, as well as a toolkit for crafting new ones. In addition to all of the document specific features of jQuery, the library provides enhancements to basic JavaScript constructs such as iteration and array manipulation.

As against it, a SPA(Single Page Application) like Angular or Backbone takes over before the page is loaded and composes the page from the elements received from the server and renders it.   

Sample app

In NetBeans-7.3 choose File -> New Project and choose in the New Project wizard Select Java web choose Web Application and click Next and in the Name and Location wizard that follows give a Project Name and for Project Location and Project Folder default values can be accepted. Click Next. The Server and Setting wizard may appear as in Figure-1.

Click Next. In the New WEB Application wizard that follows select Spring Web MVC and select Libraries expand Spring Library. The wizard may appear as in Figure-2 .Choose Spring Framework 3.1.1 RELEASE and click Finish. Necessary project structure and skeleton files and folders will be created.

Folders and files to be added.

Under Source Packages create a Java Package com.ram. The domain and the controller classes to be created in this package are given below:

Book.java

package com.ram;

public class Book {
 private String title =null;
 private String author = null;

    /**
     * @return the title
     */
    public String getTitle() {
        return title;
    }

    /**
     * @param title the title to set
     */
    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

   
    public void setAuthor(String author) {
        this.author = author;
    }
}

 

BookController.java

package com.ram;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ValidationUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class BookController {
                private List<Book> bookList = new ArrayList<Book>();
               
                @RequestMapping(value="/AddBook.htm",method=RequestMethod.GET)
                public String showForm(){
                                return "AddBook";
                }
               
                @RequestMapping(value="/AddBook.htm",method=RequestMethod.POST)
                public @ResponseBody JsonResponse addBook(@ModelAttribute(value="book") Book book, BindingResult result ){
                                JsonResponse res = new JsonResponse();
                                ValidationUtils.rejectIfEmpty(result, "title", "Title can not be empty.");
                                ValidationUtils.rejectIfEmpty(result, "author", "Author can  not be empty");
                                if(!result.hasErrors()){
                                                bookList.add(book);
                                                res.setStatus("SUCCESS");
                                                res.setResult(bookList);
                                }else{
                                                res.setStatus("FAIL");
                                                res.setResult(result.getAllErrors());
                                }
                               
                                return res;
                }

 

}

If you compare the above code for addBook() for POST requests  with the ones in our earlier Spring MVC samples, you can note one main difference. As against a “String” which was logical name for the view that was returned earlier, now the method is annotated with @ResponseBody and it returns an object .The client tells the form in which it wants the response through “Accept” header. The Spring MVC has a number of built-in HTTPMessageConverters to convert an object of a specific class into a Media type, when a method is decorated with @ResponseBody annotation. Most of the HTTP message converters are registered by default, so no explicit Spring configuration is required to use them. But we need to add additional libraries to our application’s class-path to support them. For example have a at the following important MessageConverters :

  • “Jaxb2RootElementHttpMessageConverter”:  Reads and writes XML (where the Accept header in the Browser reads “text/xml or application/xml”) from/to JAXB2-annotated objects. Registered, if JAXB v2 libraries are present on the class
  • MappingJacksonHttpMessageConverter Reads and writes JSON(where the header is Accept: application/json) from/to typed objects or untyped HashMaps. Registered if Jackson JSON library is present on the classpath.

For our sample download the following jar files from Maven Central and add them to our Project.

1)jackson-mapper-asl-1.7.7.jar  2) jackson-core-asl-1.7.7.jar

To enable the controller method to return a typed object, the following POJO class may be used. Jackson will convert that into Json.:

JsonResponse.java

package com.ram;

public class JsonResponse {
private String status = null;
private Object result = null;  

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public Object getResult() {
return result;
}

 public void setResult(Object result) {
this.result = result;
}
}

JavaScript folder and files

Under the folder “Web Pages” create a sub-folder “js” and copy the downloaded “JQuery”( preferably version 1 and not 2)  into it. Also create the file “book.js” under this folder. The code for this “js” file is given below:

book.js

// all code is wrapped inside a function
function doAjaxPost() { 
// get the form values 
var title = $('#title').val();   //--------1)
var author = $('#author').val();

$.ajax({      //--------------------2)
type: "POST", 
url: contexPath + "/AddBook.htm",   // url optional
data: "title=" + title + "&author=" + author, 
success: function(response){  // object parameter is the return value of an anonymous function
// we have the response
if(response.status == "SUCCESS"){
bookInfo = "<ol>";  // ordered list
for(i =0 ; i < response.result.length ; i++){
bookInfo += "<br><li><b>Title</b> : " + response.result[i].title +
";<b> Author</b> : " + response.result[i].author;
}
bookInfo += "</ol>";
$('#info').html("Book has been added to the list successfully. " + bookInfo);  //----3)
$('#title').val('');
$('#author').val('');
$('#error').hide('slow');
$('#info').show('slow');
}else{
errorInfo = "";     //errorInfo is a string
for(i =0 ; i < response.result.length ; i++){
errorInfo += "<br>" + (i + 1) +". " + response.result[i].code;
}
$('#error').html("Please correct following errors: " + errorInfo);
$('#info').hide('slow');
$('#error').show('slow');
}             
}, 
error: function(e){ 
alert('Error: ' + e); 

}); 

1] $() function returns a JQuery object for the DOM element passed to it. Here to a CSS selector (#title) DOM element “title” is passed and the returned JQuery object corresponding to it  invokes the val() method. In jQuery, the dollar sign ($) is simply an alias for jQuery.

2] “$.” is the syntax for invoking a function defined in JQuery. Here ajax() function is invoked. This function takes an optional ”url” string and an object as its second parameter. Here it accepts an object containing options that can be used to customize its behavior. This settings object has over 30 possible options, offering a great deal of flexibility.

3] .html(value) sets the HTML content of  matched element to value. The Dom Element div “info” will be updated with bookInfo and in AddBook.jsp <div id="info" class="success"> will be refreshed, every time a new book is added.

Modification to the generated code: The generated code includes “applicationContext.xml”, the configuration file of Spring IOC. For a small application like ours a separate “applicationContext” is not necessary, as “dipatcherServlet”, the configuration file of Spring MVC can contain the information relevant for Spring IOC also. Hence “applicationContext.xml” and the connected information in “web.xml”-  the configuration file of the Servlet container- given below can be deleted. 

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

The modified “web.xml” will read as under:

WEB_INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>redirect.jsp</welcome-file>
</welcome-file-list>
</web-app>

The modified dispatcher Servlet is given below:

WEB-INF/dipatcherServlet

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

<!-- Application Message Bundle -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="/WEB-INF/messages" />
        <property name="cacheSeconds" value="3000" />
    </bean>

                <!-- Scans the classpath of this application for @Components to deploy as beans -->
<context:component-scan base-package="com.ram" />

<!-- Configures the @Controller programming model -->
<mvc:annotation-driven />

<!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>

</beans>

The message.properties referred in the above file is given below:

WEB-INF/message.properties

Error.Title.Empty = Title should not be empty.
Error.Author.Empty = Author should not be empty.

JSP files We mentioned that we will be using JQuery for our view. For that purpose we have to refer the JQuery library and the relevant “js” files in our html file. As you know a jsp file is nothing but an html file. The code for “redirect.jsp”- welcome file referred in “web.xml”- can be modified as under:

redirect.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<jsp:forward page="/AddBook.htm"></jsp:forward>

 Actually the request is forwarded to the following method in BookController.java

@RequestMapping(value="/AddBook.htm",method=RequestMethod.GET)
public String showForm(){
return "AddBook";  // logical view name is resolved into a html file and html is returned
}

The above method returns control to “AddBook.jsp”-. The code for the file is given below:

WEB-INF/jsp/AddBook.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Add Books using ajax</title>
<script src=" "<%=request.getContextPath() %>/ js/jquery.js"></script> //------1)
<script type="text/javascript">
var contexPath = "<%=request.getContextPath() %>";
</script>
<script src="<%=request.getContextPath() %>/js/book.js"></script>
</head>
<body>
<h1>Add books using Ajax ........</h1>
<table>
<tr><td colspan="2"><div id="error" class="error"></div></td></tr>
<tr><td>Enter Title : </td><td> <input type="text" id="title"><br/></td></tr>
<tr><td>Author : </td><td> <input type="text" id="author"><br/></td></tr>
<tr><td colspan="2"><input type="button" value="Add Books" onclick="doAjaxPost()"><br/></td></tr>
<tr><td colspan="2"><div id="info" class="success"></div></td></tr>  //--2)
</table>
</body>
</html>

  • Explicitly specify where the js files are kept and how to access them.
  • <div “info”/> is the placeholder for bookInfo from  book.js

Run the Application

In the “Projects” window we can right click and choose “Clean and Build”. Once we get “Build Successful” message we can once again right click and choose Deploy. Once we get the message project has been started go to “Services” window and expand Servers àApache TomCat àWeb Applications and right click on your project and choose Open in Browser. The configured Browser will open and show the following Figure-3.After adding a few books the Browser may appear as in Figure-4.

Conclusion:

Though changes in Java are coming rather slowly, efforts are there to keep abreast with times -support for Functional paradigm and more efficient concurrent programming model. Lambdas and streams in Java-8 and Node-like reactive libraries, like Vertx and Reactor, are proofs for the same. In-fact you can use Vertx-3 and Reactor with Java-8. But Vertx is polyglot .In other words though Vertx is written in Java, you can use Java, Scala, Groovy or JavaScript. Vertx will translate them into Java on the fly and run them. We will see about Vertx-3 later.

Figure-3

Figure-4








}