Showing posts with label Jetty. Show all posts
Showing posts with label Jetty. Show all posts

Saturday, December 1, 2012

RESTful with RESTEasy - Part 2/4 (Client Consuming a POST and GET RESTful Service)

Overview:
This post looks at how to write a service client using RESTEasy framework, which is an excellent framework for developing RESTful services, and has gained a lot of popularity in the Mobile application development world.

Also Refer to,
RESTful with RESTEasy - Part 1/4 (Creating a POST and GET RESTful Service)

You can find the sample code here.

Prerequisite:JDK >= 1.5.x
Maven >= 2.2.x


Step 1: Maven Dependencies (pom.xml)
Update your client project's pom.xml by adding the following RESTEasy dependency.

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
   . . .
   <dependencies>  
     . . .  
     <dependency>  
       <groupId>org.jboss.resteasy</groupId>  
       <artifactId>resteasy-jaxrs</artifactId>  
       <version>${resteasy.version}</version>  
     </dependency>  
    . . .
   </dependencies>  
   . . .
 </project>  

Step 2: How to create a requests

   private static final String SERVICE_URL = "http://localhost:8080/greetingspring";  
   private static final String SERVICE_URL_ADD = "/add";  
   private static final String SERVICE_URL_UPDATED = "/update";  
   private static final String SERVICE_URL_GET = "/get/{id}";  
   private static final String SERVICE_URL_GET_ALL = "/getAll";  
   . . .  
   private static ClientRequest createRequest(String uri) {  
     ClientRequest request = new ClientRequest(SERVICE_URL + uri);  
     request.accept("application/json");  
     return request;  
   }  
   . . .  
   ClientRequest request = createRequest(SERVICE_URL_ADD)  
   ClientRequest request = createRequest(SERVICE_URL_GET)  
   ClientRequest request = createRequest(SERVICE_URL_UPDATE)  
   ClientRequest request = createRequest(SERVICE_URL_GET_ALL)  

Creating a POST request
 private static Long addUser(User newUser) throws Exception {  
     String requestJson = "{\"user\":" + JSON_CONVERTER.toJson(newUser) + "}";  
     displayRequest(requestJson);  
     ClientRequest request = createRequest(SERVICE_URL_ADD).body(CONTENT_TYPE, requestJson);  
     ClientResponse<String> response = request.post(String.class);  
     displayResponse(response, HTTP_CODE_CREATED);  
     return Long.parseLong(response.getEntity().toString());  
   }  

Creating a GET request
 private static User getUser(Long userId) throws Exception {  
     ClientRequest request = createRequest(SERVICE_URL_GET.replace("{id}", userId.toString()));  
     ClientResponse<String> response = request.get(String.class);  
     displayResponse(response, HTTP_CODE_OK);  
     String responseJson = response.getEntity().toString();  
     responseJson = responseJson.replace("{\"user\":", "").replace("}}", "}");  
     return JSON_CONVERTER.fromJson(responseJson, User.class);  
   }  

Complete Code for the Client


 package org.fazlan.resteasy.spring.client;  
 import com.google.gson.Gson;  
 import org.fazlan.resteasy.spring.entity.User;  
 import org.jboss.resteasy.client.ClientRequest;  
 import org.jboss.resteasy.client.ClientResponse;  
 import java.io.BufferedReader;  
 import java.io.ByteArrayInputStream;  
 import java.io.IOException;  
 import java.io.InputStreamReader;  

 public class RestClient {  

   private static final String SERVICE_URL = "http://localhost:8080/greetingspring";  
   private static final String SERVICE_URL_ADD = "/add";  
   private static final String SERVICE_URL_UPDATED = "/update";  
   private static final String SERVICE_URL_GET = "/get/{id}";  
   private static final String SERVICE_URL_GET_ALL = "/getAll";  
   private static final String CONTENT_TYPE = "application/json";  
   private static final Gson JSON_CONVERTER = new Gson();  
   private static final int HTTP_CODE_OK = 200;  
   private static final int HTTP_CODE_CREATED = 201;  

   public static void main(String[] args) throws Exception {  
     User newUser = new User("Firstname", "Lastname");  
     Long userId = addUser(newUser);  
     User user = getUser(userId);  
     displayUser(user);  
     user.setFirstName("Updated " + user.getFirstName());  
     userId = updateUser(user);  
     user = getUser(userId);  
     displayUser(user);  
     addUser( new User("AnotherFirstName", "AnotherLastName"));  
     getAllUsers();  
   }  
   private static Long addUser(User newUser) throws Exception {  
     String requestJson = "{\"user\":" + JSON_CONVERTER.toJson(newUser) + "}";  
     displayRequest(requestJson);  
     ClientRequest request = createRequest(SERVICE_URL_ADD).body(CONTENT_TYPE, requestJson);  
     ClientResponse<String> response = request.post(String.class);  
     displayResponse(response, HTTP_CODE_CREATED);  
     return Long.parseLong(response.getEntity().toString());  
   }  
   private static Long updateUser(User user) throws Exception {  
     String requestJson = "{\"user\":" + JSON_CONVERTER.toJson(user) + "}";  
     displayRequest(requestJson);  
     ClientRequest request = createRequest(SERVICE_URL_UPDATED).body(CONTENT_TYPE, requestJson);  
     ClientResponse<String> response = request.post(String.class);  
     displayResponse(response, HTTP_CODE_OK);  
     return Long.parseLong(response.getEntity().toString());  
   }  
   private static User getUser(Long userId) throws Exception {  
     ClientRequest request = createRequest(SERVICE_URL_GET.replace("{id}", userId.toString()));  
     ClientResponse<String> response = request.get(String.class);  
     displayResponse(response, HTTP_CODE_OK);  
     String responseJson = response.getEntity().toString();  
     responseJson = responseJson.replace("{\"user\":", "").replace("}}", "}");  
     return JSON_CONVERTER.fromJson(responseJson, User.class);  
   }  
   private static void getAllUsers() throws Exception {  
     ClientRequest request = createRequest(SERVICE_URL_GET_ALL);  
     ClientResponse<String> response = request.get(String.class);  
     displayResponse(response, HTTP_CODE_OK);  
   }  
   private static ClientRequest createRequest(String uri) {  
     ClientRequest request = new ClientRequest(SERVICE_URL + uri);  
     request.accept("application/json");  
     return request;  
   }  
   private static void displayUser(User user) {  
     System.out.println(user);  
   }  
   private static void displayRequest(String request) {  
     System.out.println(request);  
   }  
   private static void displayResponse(ClientResponse<String> response, int expectedResponseCode) throws IOException {  
     if (response.getStatus() != expectedResponseCode) {  
       throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());  
     }  
     BufferedReader br = new BufferedReader(new InputStreamReader(  
         new ByteArrayInputStream(response.getEntity().getBytes())));  
     String output;  
     System.out.println("Output from Server .... \n");  
     while ((output = br.readLine()) != null) {  
       System.out.println(output);  
     }  
   }  
 }  

Summary:
This tutorial looked at how we can consume RESTful Web Service using RESTEasy.

You can find the sample code here.

RESTful with RESTEasy - Part 1/4 (Creating a POST and GET RESTful Service)

Overview:
This post looks at RESTEasy framework, which is an excellent framework for developing RESTful services, and has gained a lot of popularity in the Mobile application development world.


Also Refer to,
RESTful with RESTEasy - Part 2/4 (Client Consuming a POST and GET RESTful Service)


You can find the sample code here.

Prerequisite:JDK >= 1.5.x
Maven >= 2.2.x

Project Structure: Following is the project structure I have used (Maven WAR project).

mvn archetype:generate -DgroupId=org.fazlan.resteasy.spring.servic -DartifactId=org.fazlan.resteasy.spring.servic -DarchetypeArtifactId=maven-archetype-webapp -Dversion=1.0.0-SNAPSHOT -DinteractiveMode=false



Step 1: Maven Dependencies (pom.xml)

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
   <modelVersion>4.0.0</modelVersion>  
   <groupId>org.fazlan</groupId>  
   <artifactId>org.fazlan.resteasy.spring.service</artifactId>  
   <packaging>war</packaging>  
   <version>1.0.0</version>  
   <name>org.fazlan.resteasy.spring.service Maven Webapp</name>  
   <url>http://maven.apache.org</url>  
   <properties>  
     <resteasy.version>2.3.4.Final</resteasy.version>  
     <org.springframework.version>3.1.2.RELEASE</org.springframework.version>  
     <slf4j.version>1.6.1</slf4j.version>  
   </properties>  
   <dependencies>  
     <!-- Spring 3 dependencies -->  
     <dependency>  
       <groupId>org.springframework</groupId>  
       <artifactId>spring-core</artifactId>  
       <version>3.1.2.RELEASE</version>  
     </dependency>  
     <dependency>  
       <groupId>org.springframework</groupId>  
       <artifactId>spring-web</artifactId>  
       <version>3.1.2.RELEASE</version>  
     </dependency>  
     <dependency>  
       <groupId>org.springframework</groupId>  
       <artifactId>spring-webmvc</artifactId>  
       <version>3.1.2.RELEASE</version>  
     </dependency>  
     <!-- jstl -->  
     <dependency>  
       <groupId>javax.servlet</groupId>  
       <artifactId>jstl</artifactId>  
       <version>1.2</version>  
     </dependency>  
     <dependency>  
       <groupId>org.jboss.resteasy</groupId>  
       <artifactId>resteasy-jaxrs</artifactId>  
       <version>${resteasy.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>org.jboss.resteasy</groupId>  
       <artifactId>resteasy-jaxb-provider</artifactId>  
       <version>${resteasy.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>org.jboss.resteasy</groupId>  
       <artifactId>resteasy-spring</artifactId>  
       <version>${resteasy.version}</version>  
       <exclusions>  
         <exclusion>  
           <artifactId>commons-logging</artifactId>  
           <groupId>commons-logging</groupId>  
         </exclusion>  
         <exclusion>  
           <artifactId>jaxb-impl</artifactId>  
           <groupId>com.sun.xml.bind</groupId>  
         </exclusion>  
         <exclusion>  
           <artifactId>sjsxp</artifactId>  
           <groupId>com.sun.xml.stream</groupId>  
         </exclusion>  
         <exclusion>  
           <artifactId>jsr250-api</artifactId>  
           <groupId>javax.annotation</groupId>  
         </exclusion>  
         <exclusion>  
           <artifactId>activation</artifactId>  
           <groupId>javax.activation</groupId>  
         </exclusion>  
       </exclusions>  
     </dependency>  
     <dependency>  
       <groupId>junit</groupId>  
       <artifactId>junit</artifactId>  
       <version>3.8.1</version>  
       <scope>test</scope>  
     </dependency>  
     <dependency>  
       <groupId>com.google.code.gson</groupId>  
       <artifactId>gson</artifactId>  
       <version>1.7.1</version>  
     </dependency>  
   </dependencies>  
   <build>  
     <finalName>UserService</finalName>  
     <plugins>  
       <plugin>  
         <groupId>org.mortbay.jetty</groupId>  
         <artifactId>maven-jetty-plugin</artifactId>  
         <version>6.1.10</version>  
         <configuration>  
           <contextPath>UserService</contextPath>  
           <scanIntervalSeconds>30</scanIntervalSeconds>  
           <stopKey>foo</stopKey>  
           <stopPort>9999</stopPort>  
         </configuration>  
       </plugin>  
     </plugins>  
   </build>  
 </project>  

Step 2: Creating POJO Classes and Service Implementation

User.java

 package org.fazlan.resteasy.spring.entity; 
 
 import javax.xml.bind.annotation.XmlRootElement;  

 @XmlRootElement  
 public class User {  

   private long id;  
   private String firstName;  
   private String lastName;  

   public User() {  
   }  

   public User(String firstName, String lastName) {  
     this.firstName = firstName;  
     this.lastName = lastName;  
   }  

   public long getId() {  
     return id;  
   }  

   @Override  
   public String toString() {  
     return "User{" +  
         "id=" + id +  
         ", firstName='" + firstName + '\'' +  
         ", lastName='" + lastName + '\'' +  
         '}';  
   }  

   public void setId(long id) {  
     this.id = id;  
   }  

   public String getFirstName() {  
     return firstName;  
   }  

   public void setFirstName(String firstName) {  
     this.firstName = firstName;  
   }  

   public String getLastName() {  
     return lastName;  
   }  

   public void setLastName(String lastName) {  
     this.lastName = lastName;  
   }  
 }  


UserService.java - The Service Interface
 package org.fazlan.resteasy.spring.service;  
 import org.fazlan.resteasy.spring.entity.User;  
 import javax.ws.rs.*;  
 import javax.ws.rs.core.MediaType;  
 import javax.ws.rs.core.Response;  

 @Path("/")  
 public interface UserService {  

   @POST  
   @Path("/add")  
   @Consumes(MediaType.APPLICATION_JSON)  
   Response add(User user);  

   @POST  
   @Path("/update")  
   @Consumes(MediaType.APPLICATION_JSON)  
   Response update(User user);  

   @GET  
   @Path("/get/{id}")  
   @Produces(MediaType.APPLICATION_JSON)  
   Response get(@PathParam("id") long id);  

   @GET  
   @Path("/getAll")  
   @Produces(MediaType.APPLICATION_JSON)  
   Response getAll();  
 }  

NOTE: This service class has been annotated to produce and consume certain methods in JSON(application/json) as the mime-type.

UserServiceImpl.java - Service Implementation
 package org.fazlan.resteasy.spring.service;  
 
 import org.fazlan.resteasy.spring.entity.User;  
 import org.springframework.stereotype.Component;  
 import javax.ws.rs.PathParam;  
 import javax.ws.rs.core.GenericEntity;  
 import javax.ws.rs.core.Response;  
 import java.util.Collection;  
 import java.util.HashMap;  
 import java.util.Map;  

 @Component  
 public class UserServiceImpl implements UserService {  

   private static long ID = 0L;  
   private static Map<Long, User> users = new HashMap<Long, User>();  

   public Response add(User user) {  
     user.setId(++ID);  
     update(user);  
     return Response.status(Response.Status.CREATED).entity(ID).build();  
   }  

   public Response update(User user) {  
     users.put(ID, user);  
     return Response.status(Response.Status.OK).entity(ID).build();  
   }  

   public Response get(@PathParam("id") long id) {  
     return Response.status(Response.Status.OK).entity(users.get(id)).build();  
   }  

   public Response getAll() {  
     GenericEntity<Collection<User>> usersEntity = new GenericEntity<Collection<User>>(users.values()) {  
     };  
     return Response.status(Response.Status.OK).entity(usersEntity).build();  
   }  
 }  

Step 3: Exposing the Service Beans as RESTful Web Service (applicationContext.xml)

 <?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"  
     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">  
   <context:annotation-config/>  
   <context:component-scan base-package="org.fazlan.resteasy.spring.service"/>  
 </beans>  

NOTE: This will scan all the Spring components defined in the source and load them into the Application's Spring context.

Step 4: Updating the web.xml to register the RESTEasy Servlet.
 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xmlns="http://java.sun.com/xml/ns/javaee"  
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"  
      id="WebApp_ID" version="3.0">  
   <display-name>Restful Web Application</display-name>  
   <!--<context-param>-->  
   <!--<param-name>resteasy.scan</param-name>-->  
   <!--<param-value>true</param-value>-->  
   <!--</context-param>-->  
   <context-param>  
     <param-name>contextConfigLocation</param-name>  
     <param-value>classpath:applicationContext.xml</param-value>  
   </context-param>  
   <listener>  
     <listener-class>  
       org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap  
     </listener-class>  
   </listener>  
   <listener>  
     <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>  
   </listener>  
   <servlet>  
     <servlet-name>resteasy-servlet</servlet-name>  
     <servlet-class>  
       org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher  
     </servlet-class>  
   </servlet>  
   <servlet-mapping>  
     <servlet-name>resteasy-servlet</servlet-name>  
     <url-pattern>/*</url-pattern>  
   </servlet-mapping>  
 </web-app>  


Step 5: Building the Project
mvn clean install

Step 6: Deploying the Service
Now you can deploy this service on to any container. Here we'll deploy this on Jetty using Maven.

mvn jetty:run

This should start a Jetty instance and deploy the application. You can access the HTTP GET service endpoints at the following endpoints.

http://localhost:8080/UserService/get/1 - Get the user with Id = 1
http://localhost:8080/UserService/getAll - List all users

Step 7: Testing the RESTful Web Service using CURL


We're going to test our Web Service using CURL, which I found as a very easy way to send REST Calls. I found this very nice blog about RESTing with Curl.

Installing CURL

sudo apt-get install curl

-I am using Ubuntu, if you're using Win or Mac, please do the necessary to install curl.

Now, after successfully installing CURL, we are ready to test the services.

GET Resources:
- Retrieving all the users.
 curl -v -H "Accept: application/json" http://localhost:8080/UserService/getAll

- Retrieving a user for a given id(id = 1).
 curl -v -H "Accept: application/json" http://localhost:8080/UserService/get/1

POST a Resource: Adding a new user resource.
- Adding the new user record in the add.json file.
 { 
  "user":{ 
    "id":1, 
    "firstName":"First Name1", 
    "lastName":"Last Name1" 
  } 
} 

 curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d @add.json http://127.0.0.1:8080/UserService/add


PUT a Resource: Updating an existing user resource.
- Updating an existing user record in the update.json file.
 { 
  "user":{ 
    "id":1, 
    "firstName":"Updated First Name1", 
    "lastName" :"Updated Last Name1" 
  } 
} 

 curl -v -H "Accept: application/json" -H "Content-type: application/json" -X PUT -d @update.json http://127.0.0.1:8080/UserService/update/

Summary:
This tutorial looked at how we can create RESTful Web Service using RESTEasy and test the services using CURL.

You can find the sample code here.

Monday, May 28, 2012

jQuery Tutorial: Integrating with Flickr's JSON API

Overview:
This will be another article on jQuery. Here, we'll be mainly focusing on how jQuery eases the usage of the Ajax API for JSON.

You may also refer to the first jQuery article "jQuery Tutorial: Ajax Processing - GET and POST".

The sample code for this article can be found here.

Application Demo:
The application displays images from Flickr.com that are tagged by the input provided by the user.

Home page:


Displaying the Result:



Project Structure:

 org.fazlan.jquery.flickr.app  
 |-- pom.xml  
 `-- src  
   `-- main  
     |-- resources  
     `-- webapp  
       |-- img  
       |  `-- ajax-loader.gif  
       |-- index.jsp  
       |-- jquery.js  
       `-- WEB-INF  
         `-- web.xml  

Step 1: Creating a the Web Project.

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
   <modelVersion>4.0.0</modelVersion>  
   <groupId>org.fazlan</groupId>  
   <artifactId>org.fazlan.jquery.flickr.app</artifactId>  
   <packaging>war</packaging>  
   <version>1.0.0-SNAPSHOT</version>  
   <name>org.fazlan.jquery.flickr.app Maven Webapp</name>  
   <url>http://maven.apache.org</url>  
   <dependencies>  
     <dependency>  
       <groupId>junit</groupId>  
       <artifactId>junit</artifactId>  
       <version>3.8.1</version>  
       <scope>test</scope>  
     </dependency>  
   </dependencies>  
   <build>  
     <finalName>jquery.flickr.app</finalName>  
     <plugins>  
       <plugin>  
         <groupId>org.mortbay.jetty</groupId>  
         <artifactId>maven-jetty-plugin</artifactId>  
         <version>6.1.10</version>  
       </plugin>  
       <plugin>  
         <groupId>org.apache.maven.plugins</groupId>  
         <artifactId>maven-compiler-plugin</artifactId>  
         <version>2.4</version>  
         <configuration>  
           <source>1.6</source>  
           <target>1.6</target>  
         </configuration>  
       </plugin>  
     </plugins>  
   </build>  
 </project>  

Step 2: Verifying the Flickr Endpoint

Click on the following link, this will generate a JSON output from Flickr.com.

http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?


Step 3: Defining the JSP


index.jsp
 <html>  
 <head>  
   <title>Flicker Image Library</title>  
   <script type="text/javascript" src="jquery.js"></script>  
   <script type="text/javascript">  
     // jQuery document ready
  
     $(function() {  
 /*  
            $("#tagDiv").ajaxStart(function(){  
             $('#loadImg').show();   
          });  
            $("#tagDiv").ajaxComplete(function(){  
             $('#loadImg').hide();   
          });  
 */  

       // when hit Enter on the text field  
       $('#tagField').keypress( function(evnt) {  
             var code = (evnt.keyCode ? evnt.keyCode : e.which);  
           // code to trap 'Enter' key  
           if( code == 13 ) {  
             getFlickrImages();  
           }  
       });  

       // when clicked on search button  
       $('#exploreBtn').click(function() {  
         getFlickrImages();  
       });  
     });  

     function getFlickrImages() {  
      var data = 'tags=' + $('#tagField').val().trim() + '&tagmode=any&format=json&jsoncallback=?';  
      $('#loadImg').show();  

     // sending a AJAX call to the flickr and expect JSON as return type  
      $.ajax({  
        type: 'GET',  
        url: 'http://api.flickr.com/services/feeds/photos_public.gne',  
        data: data,  
        dataType: 'json',  
        error: function(xhr, status, error) {  
             alert(status + '--> ' + error);  
           },  
        success: function(data) {  
             $('#loadImg').hide();                    
             $('#contentDiv').html(data.title);  
             $('#resultDiv').html('<center><table id="imageTable" style="border: 1px solid black; text-align:center"><tr></tr></table></center>');  
             $.each(data.items, function(index, item) {  
              // show FIVE images per row  
              if( index%5 == 0 ) {  
                   $('#imageTable tr:last').after('<tr></tr>')  
              }   
              //$('#imageTable tr:last').append('<td><img src=' + item.media.m + '></td>');    
              $('#imageTable tr:last').append('<td>' + item.description + '</td>');                           
             });  
         }  
      });  
     }  
   </script>  
 </head>  
 <body>  
 <h1 style="color: blue">Flicker Image Library</h1>  
 <div style="border: 1px solid blue" id="tagDiv">  
   <table style="color: blue">  
     <tr valign="middle">  
       <td><b>Tag Name</b></td>  
        <td><input type="text" id="tagField"/></td>  
       <td><button id="exploreBtn">Explore</button></td>  
       <td><img src="img/ajax-loader.gif" id="loadImg" style="display: none"/></td>  
     </tr>      
   </table>  
 </div>  
 <br>  
 <div id="contentDiv" style="border: 1px solid blue; color: blue"></div>  
 <div id="resultDiv"></div>  
 </body>  
 </html>  


The above Ajax call gives you more control over how you need to make the Ajax call. Conversely, you could also try the following:


var data = 'tags=' + $('#tagField').val().trim() + '&tagmode=any&format=json&jsoncallback=?';  

$.getJSON('http://api.flickr.com/services/feeds/photos_public.gne',  
      data,  
      function(result) {  
        $('#loadImg').hide();                    
        $('#contentDiv').html(result.title);  
        $('#resultDiv').html('<center><table id="imageTable" style="border: 1px solid black; text-align:center"><tr></tr></table></center>');  
        $.each(result.items, function(index, item) {  
         // show FIVE images per row  
         if( index%5 == 0 ) {  
             $('#imageTable tr:last').after('<tr></tr>')  
         }   
         //$('#imageTable tr:last').append('<td><img src=' + item.media.m + '></td>');    
         $('#imageTable tr:last').append('<td>' + item.description + '</td>');                           
        });  
 });  
Step 4: Building and Deploying the Application

$ mvn clean install
$ mvn jetty:run

mvn:jetty:run - would run the web app on the jetty server.

Now, you can access the application with the following URL.
http://localhost:8080/org.fazlan.jquery.flickr.app

Summary:
This article looked at how jQuery can be used to easily manipulate Javascript and simplify the usage of Ajax API for JSON.

The sample code for this article can be found here.

Sunday, May 27, 2012

jQuery Tutorial: Ajax Processing - GET and POST

Overview:
This article will be on jQuery. jQuery simplifies the manipulation of DOM elements. Here, we'll be mainly focusing on how jQuery eases the usage of the Ajax API.

The sample code can be found here.

Application Demo:
The application is to add and display weather information about cities.

Home page:

Select City:



Display Selected City:


Adding a New City:



Submitting the New:


Project Structure:
 org.fazlan.jquery.app  
 |-- pom.xml  
 `-- src  
   `-- main  
     |-- java  
     |  `-- org  
     |    `-- fazlan  
     |      `-- jquery  
     |        `-- app  
     |          |-- domain  
     |          |  `-- Weather.java  
     |          `-- service  
     |            `-- WeatherService.java  
     |-- resources  
     `-- webapp  
       |-- img  
       |  `-- ajax-loader.gif  
       |-- index.jsp  
       |-- jquery.js  
       |-- jsp  
       |  |-- add_weather_ajaxprocessor.jsp  
       |  `-- list_weather_ajaxprocessor.jsp  
       `-- WEB-INF  
         `-- web.xml  

Step 1: Creating a the Web Project.

 mvn archetype:generate -DgroupId=org.fazlan -DartifactId=org.fazlan.spring.mvc -Dversion=1.0.0-SNAPSHOT -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false  

Step 2: Updating the Maven Dependencies (pom.xml)

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
   <modelVersion>4.0.0</modelVersion>  
   <groupId>org.fazlan</groupId>  
   <artifactId>org.fazlan.jquery.app</artifactId>  
   <packaging>war</packaging>  
   <version>1.0.0-SNAPSHOT</version>  
   <name>org.fazlan.jquery.app Maven Webapp</name>  
   <url>http://maven.apache.org</url>  
   <dependencies>  
     <dependency>  
       <groupId>junit</groupId>  
       <artifactId>junit</artifactId>  
       <version>3.8.1</version>  
       <scope>test</scope>  
     </dependency>  
   </dependencies>  
   <build>  
     <finalName>jquery.app</finalName>  
     <plugins>  
       <plugin>  
         <groupId>org.mortbay.jetty</groupId>  
         <artifactId>maven-jetty-plugin</artifactId>  
         <version>6.1.10</version>  
       </plugin>  
       <plugin>  
         <groupId>org.apache.maven.plugins</groupId>  
         <artifactId>maven-compiler-plugin</artifactId>  
         <version>2.4</version>  
         <configuration>  
           <source>1.6</source>  
           <target>1.6</target>  
         </configuration>  
       </plugin>  
     </plugins>  
   </build>  
 </project>  

Step 3: Defining the Java Backend Logic

Weather.java
 package org.fazlan.jquery.app.domain;  
 public class Weather {  
   private String code;  
   private String city;  
   private String description;  
   private int temperature;  
   private int humidity;  
   public Weather(String code, String city, String description, int temperature, int humidity) {  
     this.code = code;  
     this.city = city;  
     this.description = description;  
     this.temperature = temperature;  
     this.humidity = humidity;  
   }  
   public String getCode() {  
     return code;  
   }  
   public String getCity() {  
     return city;  
   }  
   public String getDescription() {  
     return description;  
   }  
   public int getTemperature() {  
     return temperature;  
   }  
   public int getHumidity() {  
     return humidity;  
   }  
   @Override  
   public String toString() {  
     return "Weather{" +  
         "code='" + code + '\'' +  
         ", city='" + city + '\'' +  
         ", description='" + description + '\'' +  
         ", temperature=" + temperature +  
         ", humidity=" + humidity +  
         '}';  
   }  
 }  

WeatherService.java
 package org.fazlan.jquery.app.service;  
 import org.fazlan.jquery.app.domain.Weather;  
 import java.util.HashMap;  
 import java.util.Map;  
 public class WeatherService {  
   private static final Map<String, Weather> weather_map = new HashMap<String, Weather>();  
   static {  
     weather_map.put("SYD", new Weather("SYD", "Sydney", "Sunny", 22, 50));  
     weather_map.put("MEL", new Weather("MEL", "Melbourne", "Cloudy", 14, 45));  
     weather_map.put("QLD", new Weather("QLD", "Queensland", "Hot and Humid", 26, 65));  
     weather_map.put("PER", new Weather("PER", "Perth", "Sunny", 28, 55));  
     weather_map.put("ADL", new Weather("ADL", "Adelaide", "Mild", 18, 45));  
     weather_map.put("DWN", new Weather("DWN", "Darwin", "Sunny", 24, 45));  
     weather_map.put("TAS", new Weather("TAS", "Tasmania", "Cold", 12, 35));  
   }  
   public Weather get(String code) {  
     return weather_map.get(code);  
   }  
   public void add(Weather weather) {  
     weather_map.put(weather.getCode(), weather);  
   }  
 }  

Step 4: Defining the JSPs for Processing Requests
These JSP pages will act as Controllers, and invoke the backend business logic classes to process the requests.

list_weather_ajaxprocessor.jsp - This handles the requests for retrieving information related to the selected city from the dropdown.

 <%@ page import="org.fazlan.jquery.app.service.WeatherService" %>  
 <%@ page import="org.fazlan.jquery.app.domain.Weather" %>  
 <%!  
   // create an instance of the service  
   WeatherService weatherService = new WeatherService();  
   Weather weatherResult = null;  
 %>  
 <%  
   // get the selected city code from the request  
   String cityCode = request.getParameter("cityCode");  
   System.out.println("City Code: " + cityCode);  
   if (cityCode != null && !"".equals(cityCode)) {  
     // get the corresponding weather details for the requested citycode  
     weatherResult = weatherService.get(cityCode);  
     // delay to show the progress image in the UI using Ajax/jQuery  
     try {  
       Thread.sleep(2000);  
     } catch (Exception e) {  
     }  
   } else {  
     return;  
   }  
 %>  
 <!-- put the result into a HTML table and return that-->  
 <table width="500px">  
   <tr>  
     <td width="40%"><b>City</b></td>  
     <td style="color: blue;"><%= weatherResult.getCity() %>  
     </td>  
   </tr>  
   <tr>  
     <td width="40%"><b>Description</b></td>  
     <td style="color: blue;"><%= weatherResult.getDescription() %>  
     </td>  
   </tr>  
   <tr>  
     <td width="40%"><b>Temperature</b></td>  
     <td style="color: blue;"><%= weatherResult.getTemperature() %>  
     </td>  
   </tr>  
   <tr>  
     <td width="40%"><b>Humidity</b></td>  
     <td style="color: blue;"><%= weatherResult.getHumidity()%>  
     </td>  
   </tr>  
 </table>  

add_weather_ajaxprocessor.jsp - This handles the requests for submitting information related to the new city.
 <%@ page import="org.fazlan.jquery.app.service.WeatherService" %>  
 <%@ page import="org.fazlan.jquery.app.domain.Weather" %>  
 <%!  
   WeatherService weatherService = new WeatherService();  
 %>  
 <%  
   // get the form parameters  
   String code = request.getParameter("code");  
   String city = request.getParameter("city");  
   String description = request.getParameter("description");  
   int temperature = Integer.parseInt(request.getParameter("temperature"));  
   int humidity = Integer.parseInt(request.getParameter("humidity"));  
   // create a new Weather object and populate with the form values  
   Weather weather = new Weather(code, city, description, temperature, humidity);  
   // delay to show the progress image in the UI using Ajax/jQuery  
   try {  
     Thread.sleep(2000);  
   } catch (Exception e) {  
   }  
   // add the new Weather information  
   weatherService.add(weather);  
   // return the new city code to be added to the dropdown list  
   out.println("<option value=" + weather.getCode() + "> " + weather.getCity() + "</option>");  
 %>  

Step 5: Defining the Actual JSP View
Index.jsp
 <html>  
 <head>  
   <script type="text/javascript" src="jquery.js"></script>  
   <script type="text/javascript">  
     // jQuery document ready  
     $(function() {  
       /* jQuery event handling for city dropdown list */  
       $('#citySelect').change(function() {  
         $('#newEntryDiv').hide();  
         var cityCd = $(this).val();  
         $('#loadImg').show();  
         $.get(  
           'jsp/list_weather_ajaxprocessor.jsp',  
           {  
             cityCode: cityCd  
           },  
           function(data) {  
              $('#loadImg').hide();  
              $('#contentDiv').html(data);  
           });  
       });  
       /* jQuery event handling for adding a new city entry */  
       $('#addbtn').click(function() {  
         $('#newEntryDiv').show();  
         $('#contentDiv').html('');  
       });  
       /* jQuery event handling for submitting the new entry */  
       $('#newEntryForm').submit(function() {  
         $('#saveImg').show();  
         $.post(  
           'jsp/add_weather_ajaxprocessor.jsp',  
           $('#newEntryForm').serialize(),  
           function(data) {  
              $('#saveImg').hide();  
              $('#citySelect').append(data);  
              $('#newEntryDiv').hide();  
           });  
           clearForm($(this));  
         /*DO NOT REFRESH page after submit*/  
         return false;  
       });  
     });  
     /** function to clear the form */  
     function clearForm(form) {  
       $(":input", form).each(function() {  
         var type = this.type;  
         var tag = this.tagName.toLowerCase();  
         if (type == 'text') {  
           this.value = "";  
         }  
       });  
     }  
   </script>  
 </head>  
 <body>  
 <h1>Weather in Australia and Around the Globe</h1>  
 <div id="formDiv" style="border: 1px solid blue">  
   <table>  
     <tr valign="middle">  
       <td><b>Select City</b></td>  
       <td>  
         <form>  
           <select name="citySelect" id="citySelect">  
             <option value="">--- Select ---</option>  
             <option value="ADL">Adelaide</option>  
             <option value="DWN">Darwin</option>  
             <option value="MEL">Melbourne</option>  
             <option value="PER">Perth</option>  
             <option value="QLD">Queensland</option>  
             <option value="SYD">Sydney</option>  
             <option value="TAS">Tasmania</option>  
           </select>  
         </form>  
       </td>  
       <td><img src="img/ajax-loader.gif" style="display:none;" id="loadImg"/></td>  
     </tr>  
     <tr>  
       <td colspan="3">  
         <button id="addbtn" type="submit">Add New</button>  
       </td>  
     </tr>  
   </table>  
 </div>  
 <br>  
 <div id="newEntryDiv" style="display: none; border: 1px solid blue">  
   <form id="newEntryForm">  
     <table width="500 px">  
       <tr>  
         <td width="40%"><b>Code</b></td>  
         <td><input type="text" name="code"></td>  
       </tr>  
       <tr>  
         <td width="40%"><b>City</b></td>  
         <td><input type="text" name="city"></td>  
       </tr>  
       <tr>  
         <td width="40%"><b>Description</b></td>  
         <td><input type="text" name="description"></td>  
       </tr>  
       <tr>  
         <td width="40%"><b>Temperature</b></td>  
         <td><input type="text" name="temperature"></td>  
       </tr>  
       <tr>  
         <td width="40%"><b>Humidity</b></td>  
         <td><input type="text" name="humidity"></td>  
       </tr>  
       <tr>  
         <td><input type="submit"></td>  
         <td><img src="img/ajax-loader.gif" style="display:none;" id="saveImg"/></td>  
       </tr>  
     </table>  
   </form>  
 </div>  
 <div id="contentDiv" style="border: 1px solid blue">Weather information will appear here.</div>  
 </body>  
 </html>  


Step 6: Building and Deploying the Application

$ mvn clean install
$ mvn jetty:run

mvn:jetty:run - would run the web app on the jetty server.

Now, you can access the application with the following URL.
http://localhost:8080/org.fazlan.jquery.app/

Summary:
This article looked at how jQuery can be used to easily manipulate Javascript and simplify the usage of Ajax API.

The sample code can be found here.

Monday, May 21, 2012

Spring MVC 3: Part 2 - Form Processing

Overview:
This will is a TWO part series article that looks at Spring MVC 3. To better understand the usage of the framework + to keep the tutorial short and keep the reader interested, I have split this into TWO parts.

Part 1: Listing and Viewing Person Details (Retrieve)
Part 2: Form Processing ( Create, Update and Delete)

The example used for both the articles will be same, and will be concentrating on CRUD operations. The example will be a People Management Application.

The sample code for BOTH these articles are here.

Part 2: Form Processing (Create, Update and Delete)

Application Demo:


Listing All People Details.

Edit Details of a Person




Project Structure: Following is the project structure used in the article (Maven wed application).

Java package structure

Web app structure

Step 1: Creating the Web Project.

Refer to Part 1.

Step 2: Maven Dependencies (pom.xml)


Refer to Part 1.

Step 3: Defining the Spring MVC Model, and Updated Backend Logic.

Person.java - represent the M in MVC(Refer Part 1).

 package org.fazlan.spring.mvc.model;  
 public class Person {  
   //model properties
   private Long id;  
   . . .

   // model constructors  
   public Person(long id, String firstName, String lastName) {  
   . . .
   }  

   // getter/setter and rest of the methods
   . . .  
 }  

IManager.java and PersonManager - the updated backend service implementation.

IManager.java

 package org.fazlan.spring.mvc.manager;  

 import java.util.List;  

 public interface IManager<T> {  
   List<T> getAll();  
   T get(Long id);  
   void save(T t);  
   void update(T t);  
   void delete(T t);  
 }  

PersonManager.java

  package org.fazlan.spring.mvc.manager; 
  
  import org.fazlan.spring.mvc.model.Person;   
  import java.util.ArrayList;   
  import java.util.HashMap;   
  import java.util.List;   
  import java.util.Map;  
 
  public class PersonManager implements IManager&lt;Person&gt;{   
   private final Map&lt;Long, Person&gt; PERSON_MAP = new HashMap&lt;Long, Person&gt;();   
   private static Long INDEX = 1L;   
   {   
    PERSON_MAP.put(INDEX, new Person(INDEX, "First Name", "Second Name"));   
   }   
   @Override   
   public List&lt;Person&gt; getAll() {   
    return new ArrayList&lt;Person&gt;(PERSON_MAP.values());   
   }   
   @Override   
   public Person get(Long id) {   
    return PERSON_MAP.get(id);   
   }   

   &lt;!-- Newly Added CUD Operation --&gt;
   @Override   
   public void save(Person person) {   
    person.setId(++INDEX);   
    update(person);   
   }   
   @Override   
   public void update(Person person) {   
    PERSON_MAP.put(person.getId(), person);   
   }   
   @Override   
   public void delete(Person person) {   
    PERSON_MAP.remove(person.getId());   
   }   
  }   

Step 4: Updated Spring MVC Controller.
A controller receives web requests, performs business logic, and populates the model (Person.java) for the view to present.

 package org.fazlan.spring.mvc.controllers;
  
 import org.fazlan.spring.mvc.manager.IManager;  
 import org.fazlan.spring.mvc.model.Person;  
 import org.fazlan.spring.mvc.validators.PersonValidator;  
 import org.springframework.beans.factory.annotation.Autowired;  
 import org.springframework.beans.propertyeditors.StringTrimmerEditor;  
 import org.springframework.stereotype.Controller;  
 import org.springframework.ui.Model;  
 import org.springframework.validation.BindingResult;  
 import org.springframework.web.bind.WebDataBinder;  
 import org.springframework.web.bind.annotation.*;  
 import org.springframework.web.bind.support.SessionStatus;  

 import java.util.List;  

 @Controller  
 @SessionAttributes("person")  
 public class PersonForm {  
   @Autowired  
   private IManager<Person> manager;
  
   @Autowired  
   private PersonValidator validator;
  
   @RequestMapping("/list")  
   @ModelAttribute("personList")  
   public List<Person> getAll() {  
     return manager.getAll();  
   }  

   @RequestMapping("/view")  
   public Person get(@RequestParam(value = "id", required = true) Long personId) {  
     return manager.get(id);  
   }  

   @InitBinder  
   public void initBind(WebDataBinder binder) {  
     binder.setDisallowedFields("id");  
     binder.setRequiredFields("firstName", "lastName");  
     binder.registerCustomEditor(String.class, new StringTrimmerEditor(false));  
   }  

   @RequestMapping(value="/add", method = RequestMethod.GET)  
   public Person setup(@RequestParam(value = "id", required = false) Long personId) {  
     Person p;  
     if (personId == null) {  
       p = new Person();  
     } else {  
       p = manager.get(personId);  
     }  
     return p;  
   }  

   @RequestMapping(value="/add", params = "create", method = RequestMethod.POST)  
   public String save(Person person, BindingResult result, SessionStatus status) {  

     validator.validate(person, result);  

     if (result.hasErrors()) {  
       return "add";  
     } else {  
       manager.save(person);  
       status.setComplete();  
       return "redirect:list.html";  
     }  
   }  

   @RequestMapping(value="/add", params = "update", method = RequestMethod.POST)  
   public String update(Person person, BindingResult result, SessionStatus status) {  

     validator.validate(person, result);  

     if (result.hasErrors()) {  
       return "add";  
     } else {  
       manager.update(person);  
       status.setComplete();  
       return "redirect:list.html";  
     }  
   }  

   @RequestMapping(value="/add", params = "delete", method = RequestMethod.POST)  
   public String delete(Person person, BindingResult result, SessionStatus status) {  
     manager.delete(person);  
     status.setComplete();  
     return "redirect:list.html";  
   }  
 }  

The above class defined the controller to handle the requests for managing a Person. For now, let's look at the following elements,

Form Backing Object
This is used to pre-populate the data in the form. Lets look at the following code snippet to better understand form backing object.

@RequestMapping(value="/add", method = RequestMethod.GET)  
public Person setup(@RequestParam(value = "id", required = false) Long personId) {  
  Person p;  
  if (personId == null) {  
    p = new Person();  
  } else {  
    p = manager.get(personId);  
  }  
  return p;  
}  

When the controller receives a HTTP.GET request, the setup() gets invoked and populates the form with a Person JavaBean based on the personId parameter. When the personId is available, then it's a request for either update or delete operation, and hence an existing Person JavaBean object is returned. If the personId parameter is empty, then the request is for create new operation, and hence a new Person JavaBean object is returned.

Saving, Updating and Deleting
These operations are pretty much alike. They receive data (Person JavaBean argument) from the form and process the backend logic.

   @RequestMapping(value="/add", params = "create", method = RequestMethod.POST)  
   public String save(Person person, BindingResult result, SessionStatus status) {  
      . . .
   }  

   @RequestMapping(value="/add", params = "update", method = RequestMethod.POST)  
   public String update(Person person, BindingResult result, SessionStatus status) {  
      . . .
   }  

   @RequestMapping(value="/add", params = "delete", method = RequestMethod.POST)  
   public String delete(Person person, BindingResult result, SessionStatus status) {  
     . . .  
   }  


The params attribute in each of the above method signatures refer to a parameter passed by the HTML form into the controller.

 . . .  
 <form:form method="post" commandName="person" action="add.html" cssClass="box-form-a">  
    . . .  
    <button type="submit" name="create"><spring:message code="navigation.add"/></button>  
    . . .  
    <button type="submit" name="update"><spring:message code="navigation.edit"/></button>  
    <button type="submit" name="delete"  
            onclick="return confirm('Are you sure to delete ${person.firstName} ${person.lastName}?')">  
          <spring:message  
              code="navigation.delete"/></button>  
   . . .  
 </form:form>  
 . . .  

Here, they are names of the buttons in the HTML form., and when one of those buttons clicked, the corresponding method will be invoked.

Returning Logical Views

Please note that some of the methods return a String value. When a String is returned from a method annotated with @RequestMapping, it represents a logical view name. Here, we are telling Spring exactly which page to display next.

As an example,  the create() and update() methods takes the user back to /jsp/add.jsp if any validation errors found. If the input is valid, then /jsp/list.jsp page is displayed.

The redirect: prefix triggers an HTTP redirect to the browser. This is required when delegating the response to another controller, rather than just rendering the view.

In this example, when valid data has been submitted from the form, it takes the user to the people list page. Redirection ensures that the getAll() method is called on the PersonForm class, and the necessary data is added to the model.


@SessionAttributes
The Person object returned by setUp() is not the same object as the one passed into the create(), update() or delete() methods. Thus, only data from the form (which doesn't include all of the properties in our backing object) will be bound to the Person objects in these methods. 


However, more often than not, what we really need is to access the original object (one populated in the setup() method) plus any changes made to data on the form.


The type level @SessionAttributes annotation does just this by specifying the objects, by name or by type, to be kept in session between requests. The setComplete() method on the SessionStatus class, marks session processing as complete, and allows the session attributes to be cleaned up.

Step 5: Defining the Spring MVC Form Validation
This section will cover some of the annotations used in the controller for processing data.

@InitBinder
Is used to bind the data between the HTML form and the controller.
 @InitBinder   
 public void initBind(WebDataBinder binder) {   
  binder.setDisallowedFields("id");   
  binder.setRequiredFields("firstName", "lastName");   
  binder.registerCustomEditor(String.class, new StringTrimmerEditor(false));   
 }  

setDisallowedFields() - registers fields that are not allowed for binding. This example makes sure that the user does not make potentially unauthorized changes(e.i: Inspect Element from the browser)

setRequiredFields()      - lists the form fields that are mandatory. An error will be raised if any values for items in the list are missing.


Custom Validation
The following is how you can introduce your own custom validation logic into the controllers. Then, from the controller, you can invoke these validation methods.

@RequestMapping(value="/add", params = "create", method = RequestMethod.POST)   
public String save(Person person, BindingResult result, SessionStatus status) {   
 validator.validate(person, result);   
  . . .  
}   
@RequestMapping(value="/add", params = "update", method = RequestMethod.POST)   
public String update(Person person, BindingResult result, SessionStatus status) {   
 validator.validate(person, result);   
 . . .  
}      

Validation Error Codes
msg-properties/messages_en_US.properties
msg-properties/messages.properties

 person.details=Person Details  
 person.firstName=First Name  
 person.lastName=Second Name  
 field.required=Required field missing  
 firstName=First Name  
 required=Required field missing  
The 'required' entry is a special code used by Spring when a field that is specified in the setRequiredFields() method, is not supplied.

Rending the Errors on View 
To include the errors on the view, include the tag along side each of the tags in our JSP page.

 <table class="gradient">  
   <tr>  
     <td>First Name</td>  
     <td>  
       <form:input path="firstName"/><form:errors path="firstName" cssClass="errors"/>  
     </td>  
   </tr>  
   <tr>  
     <td>Last Name</td>  
     <td><form:input path="lastName"/><form:errors path="lastName" cssClass="errors"/></td>  
   </tr>  
 </table>  


Step 6: Updated Spring MVC Views.


add.jsp
Now, we introduce a new JSP page to create and update People. The same page is used for both the operations.
Create a Person
When the add.html gets a HTTP.GET request without the id parameter, the form backing object returns a new Person instance, and populates the view.

As an example, the following snippet in the /jsp/list.jsp would called when creating a new Person.
 <a href='add.html'><spring:message code="navigation.add"/></a>  

Update a Person
Similarly, when the add.html gets a HTTP.GET request with the id parameter, the form backing object returns an existing Person instance corresponding to the given id parameter, and populates the view.

As an example, the following snippet in the /jsp/list.jsp would called when creating a new Person.
 <a href="add.html?id=${person.id}"><spring:message code="navigation.edit"/></a>  

The isNew() method on the Person class from the model is used to determine the mode of the screen.
 public boolean isNew() {  
     return id == null;  
 }  


add.jsp JSP

 <body>  
 <div>  
   <form:form method="post" commandName="person" action="add.html" cssClass="box-form-a">  
     <c:choose>  
       <c:when test="${person.new}">  
         <h1>Sign-up Here</h1>  
         <p>Person registration form</p>  
       </c:when>  
       <c:otherwise>  
         <h1>Update Here</h1>  
         <p>Person updation form</p>  
       </c:otherwise>  
     </c:choose>  
     <table class="gradient">  
       <tr>  
         <td>First Name</td>  
         <td>  
           <form:input path="firstName"/><form:errors path="firstName" cssClass="errors"/>  
         </td>  
       </tr>  
       <tr>  
         <td>Last Name</td>  
         <td><form:input path="lastName"/><form:errors path="lastName" cssClass="errors"/></td>  
       </tr>  
     </table>  
     <c:choose>  
       <c:when test="${person.new}">  
         <button type="submit" name="create"><spring:message code="navigation.add"/></button>  
       </c:when>  
       <c:otherwise>  
         <button type="submit" name="update"><spring:message code="navigation.edit"/></button>  
         <button type="submit" name="delete"  
             onclick="return confirm('Are you sure to delete ${person.firstName} ${person.lastName}?')">  
           <spring:message  
               code="navigation.delete"/></button>  
       </c:otherwise>  
     </c:choose>  
   </form:form>  
   <a href="list.html"><spring:message code="navigation.back"/></a>  
 </div>  
 </body>  


Step 7: Spring MVC Configuration


Refer to Part 1.


Step 8: Building and Deploying the Application

Refer to Part 1.


Now, you can access the application with the following URL.
http://localhost:8080/org.fazlan.spring.mvc/list.html

Summary:
The Part 2 of the Spring MVC 3 article focused on how to use the framework to process form data and render on JSPs.

The sample code for BOTH these articles are here.

That's all Folks!!!