Showing posts with label JQuery. Show all posts
Showing posts with label JQuery. Show all posts

Wednesday, June 20, 2012

File Upload with Spring and jQuery (Part 1)

Introduction

In this article, we will study how to do file uploads with Spring and jQuery. We will learn how to attach multiple files and use the jQuery-File-Upload plugin to provide a seamless file upload experience.


Dependencies


Github

To access the source code, please visit the project's Github repository (click here)

Functional Specs

Let's define our application's requirements:
  • Create a simple form where users can upload multiple files
  • Users should be able to add an owner name and description for each upload
  • Provide an AJAX-like experience

Here's our Use Case diagram:


[User]-(Add files)
[User]-(Upload)

File Upload Strategy
To achieve an AJAX-like experience we have to resort to a different strategy when uploading and sending form data. Instead of sending all form data in one go, we will upload the file separately (behind the scenes without user intervention).

Here are the steps:
  1. User fills-in the form's text inputs, i.e owner and description
  2. User clicks on "Add a file" link. Browsers for a file and attaches it
  3. Behind the scene, the form uploads the file to the server. The server saves the file and returns the file details, i.e filename and file size
  4. User clicks on "Upload" button. The form does a POST action to send the form data. But it never sends the file itself. Instead it sends the filename that was saved by the server. The user is tricked into thinking that the file hasn't been uploaded yet.

Screenshots

Let's preview how our application will look like after it has been completed. This is also a good way to clarify further our application's specs

This is the entry page where users can upload files. Users are allowed to attach multiple files.


Upload Form

When attaching multiple files, this is the expected output.


Multiple files attachment

This alert shows whenever files have been successfully uploaded.


Successful upload alert

This alerts shows whenever files have failed to be uploaded.


Form fields cleared alert

Next

In the next section, we will start writing the Java classes. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: File Upload with Spring and jQuery (Part 1) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

File Upload with Spring and jQuery (Part 2)

Review

In the previous section, we have laid down the functional specs of the application. In this section, we will start writing the Java classes and discuss the project's structure.


Project Structure

Our application is a Maven project which means our project follows the Maven structure.

Here's a preview of our project's structure:





Domain Layer

The domain layer contains a Message class that is used as a container to hold file details.

Message.java


The domain layer also contains an UploadedFile class which is used for sending file information after it has been processed by the controller.

UploadedFile.java


Controller Layer

The controller layer contains a simple controller that serves a form for uploading files. There are two important endpoints here:
  • /message - processes the file descriptions
  • /file - receives the files themselves

To simplify this tutorial, we're not persisting the messages and files in a database or to the disk.

UploadController.java


Others

StatusResponse is used to determine the status of a request, and includes an error message if any.

StatusResponse.java


Next

We've completed writing our Java classes. In the next section, we will start writing the configuration files. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: File Upload with Spring and jQuery (Part 2) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

File Upload with Spring and jQuery (Part 3)

Review

In the previous section, we have implemented the Java classes. In this section, we will start writing the configuration files.


Configuration

To complete our application, here are the important configuration files that needs to be declared:
  • applicationContext.xml
  • spring-servlet.xml
  • web.xml

applicationContext.xml
Pay attention to the CommonsMultipartResolver and the MappingJacksonJsonView.
  • The CommonsMultipartResolver is a requirement for processing MultipartFile files
  • The MappingJacksonJsonView is required for serializing JSON responses properly. The extractValueFromSingleKeyModel is meant to remove the wrapper object when responding with single key model (see the Stack Overflow link for details).


spring-servlet.xml


web.xml


Next

In the next section, we will discuss the HTML form for uploading files. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: File Upload with Spring and jQuery (Part 3) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

File Upload with Spring and jQuery (Part 4)

Review

In the previous section, we have written the configuration files. In this section, we will write the HTML form for uploading files.


To achieve a seamless AJAX-like file upload experience, we will be using blueimp's jQuery-File-Upload plugin for jQuery.

What is jQuery-File-Upload?

File Upload widget with multiple file selection, drag&drop support, progress bars and preview images for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.

Source: https://github.com/blueimp/jQuery-File-Upload

To test-drive this plugin, please visit the following demos:

For our purposes, we will follow the minimal setup guide, so that we can create our custom UI and eliminate extraneous steps.

Warning!
Make sure to test the plugin on different browsers. Not all browsers behave the same way. In my opinion, Chrome and Firefox are the best for development.

Html Form

Here's our upload form again:

Upload Form

Here's the full source:



Let's dissect this source and make sense of it.

Endpoint Urls
We've declared two global urls: messageUploadUrl and fileUploadUrl. These are the endpoints for uploading messages and files respectively.



Import Scripts
Based on the jQuery-File-Upload basic plugin guide, we need to import the following scripts: jquery.ui.widget.js, jquery.iframe-transport.js, and jquery.fileupload.js. The util.js contains a method for posting JSON objects. The remaining scripts are for the jQuery framework itself.



Initialization Function
This function contains the following initialization steps:
  • Beautify buttons
  • Attach submit function
  • Attach clear function
  • Attach file upload function
  • Initialize filelist data



File Display Function
This is used for formatting filenames. The output is similar to the following: filename (256.50K)



File List Function
This is used to retrieved the list of filenames. The output is comma-delimited, which is similar to the following: filename1.jpg,filename2.doc,filename3.txt



Dialog Function
This is a helper function for displaying dialog boxes.



Clear Function
This clears the form of its contents.



Form
This is the form itself. Notice we've set the file input's opacity to zero to hide it and make it work under Safari and Opera (try removing the opacity and hide the file input via display:none to see an unwanted effect).



By setting the file input's opacity to 0, we have successfully hidden the input. But how do we access it now? Notice the "Add a file" link? We've attached a click trigger function on that link to fire up the file input. If we removed the opacity, here's what we will see:

Chrome 19.0.1084.56


Firefox 9.0.1


Internet Explorer 9.0.8112.16421


Browser Bugs

Unfortunately, even though the jQuery-File-Upload plugin has great cross-browser support, HTML5 and traditional, there are still bugs and unwanted behavior. Maybe it's a configuration issue or a browser issue. In other words, always tests before you deploy to production. Here's what I've discovered so far:

Internet Explorer 9.0.8112.16421
  • Does not upload file
  • Does not upload message

Opera 11.60
  • Attach link does not work if file input has display:none
  • To make it work, set the opacity instead

Safari 5.1.2
  • Attach link does not work if file input has display:none
  • To make it work, set the opacity instead

Next

In the next section, we will build and run the application using Maven, and show how to import the project in Eclipse. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: File Upload with Spring and jQuery (Part 4) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

File Upload with Spring and jQuery (Part 5)

Review

We have just completed our application! In the previous sections, we have discussed the functional specs, created the Java classes, declared the configuration files, and wrote the HTML files. In this section, we will build and run the application using Maven, and show how to import the project in Eclipse.


Running the Application

Access the source code

To download the source code, please visit the project's Github repository (click here)

Building with Maven

  1. Ensure Maven is installed
  2. Open a command window (Windows) or a terminal (Linux/Mac)
  3. Run the following command:
    mvn tomcat:run
  4. You should see the following output:
    [INFO] Scanning for projects...
    [INFO] Searching repository for plugin with prefix: 'tomcat'.
    [INFO] artifact org.codehaus.mojo:tomcat-maven-plugin: checking for updates from central
    [INFO] artifact org.codehaus.mojo:tomcat-maven-plugin: checking for updates from snapshots
    [INFO] ------------------------------------------
    [INFO] Building spring-fileupload-tutorial Maven Webapp
    [INFO]    task-segment: [tomcat:run]
    [INFO] ------------------------------------------
    [INFO] Preparing tomcat:run
    [INFO] [apt:process {execution: default}]
    [INFO] [resources:resources {execution: default-resources}]
    [INFO] [tomcat:run {execution: default-cli}]
    [INFO] Running war on http://localhost:8080/spring-fileupload-tutorial
    Jun 20, 2012 8:35:14 PM org.apache.catalina.startup.Embedded start
    INFO: Starting tomcat server
    Jun 20, 2012 8:35:14 PM org.apache.catalina.core.StandardEngine start
    INFO: Starting Servlet Engine: Apache Tomcat/6.0.29
    Jun 20, 2012 8:35:15 PM org.apache.catalina.core.ApplicationContext log
    INFO: Initializing Spring root WebApplicationContext
    Jun 20, 2012 8:35:17 PM org.apache.coyote.http11.Http11Protocol init
    INFO: Initializing Coyote HTTP/1.1 on http-8080
    Jun 20, 2012 8:35:17 PM org.apache.coyote.http11.Http11Protocol start
    INFO: Starting Coyote HTTP/1.1 on http-8080
    
  5. Note: If the project will not build due to missing repositories, please enable the repositories section in the pom.xml!

Access the Entry page

  1. Follow the steps with Building with Maven
  2. Open a browser
  3. Enter the following URL (8080 is the default port for Tomcat):
    http://localhost:8080/spring-fileupload-tutorial/upload

Attach a file

  1. Click on "Add a file"
  2. Browse for a file and add it. Check the logs and you should see something similar to the following:
    [DEBUG] [tomcat-http--24 02:15:20] (TraceInterceptor.java:writeToLog:21) Entering UploadController.upload(org.springframework.web.multipart.commons.CommonsMultipartFile@d1258b)
    [DEBUG] [tomcat-http--24 02:15:20] (UploadController.java:upload:43) Writing file to disk...done
    [DEBUG] [tomcat-http--24 02:15:20] (TraceInterceptor.java:writeToLog:21) Leaving UploadController.upload(): [UploadedFile [name=Tulips.jpg, size=620888, url=http://localhost:8080/spring-fileupload-tutorial/resources/Tulips.jpg, thumbnail_url=null, delete_url=null, delete_type=null]]
    

Attach multiple files

  1. Click on "Add another file"
  2. Browse for files and add them. Check the logs and you should see something similar to the following:
    [DEBUG] [tomcat-http--26 02:15:42] (TraceInterceptor.java:writeToLog:21) Entering UploadController.upload(org.springframework.web.multipart.commons.CommonsMultipartFile@7783ea)
    [DEBUG] [tomcat-http--26 02:15:42] (UploadController.java:upload:43) Writing file to disk...done
    [DEBUG] [tomcat-http--26 02:15:42] (TraceInterceptor.java:writeToLog:21) Leaving UploadController.upload(): [UploadedFile [name=Hydrangeas.jpg, size=595284, url=http://localhost:8080/spring-fileupload-tutorial/resources/Hydrangeas.jpg, thumbnail_url=null, delete_url=null, delete_type=null]]
    [DEBUG] [tomcat-http--27 02:15:42] (TraceInterceptor.java:writeToLog:21) Entering UploadController.upload(org.springframework.web.multipart.commons.CommonsMultipartFile@85ec1b)
    [DEBUG] [tomcat-http--27 02:15:42] (UploadController.java:upload:43) Writing file to disk...done
    [DEBUG] [tomcat-http--27 02:15:42] (TraceInterceptor.java:writeToLog:21) Leaving UploadController.upload(): [UploadedFile [name=Jellyfish.jpg, size=775702, url=http://localhost:8080/spring-fileupload-tutorial/resources/Jellyfish.jpg, thumbnail_url=null, delete_url=null, delete_type=null]]
    

Upload the files

  1. Click on "Upload". Check the logs and you should see something similar to the following:
    [DEBUG] [tomcat-http--30 02:16:20] (TraceInterceptor.java:writeToLog:21) Entering UploadController.message(Message [owner=John Smith, description=These are my files. I owned them., filename=Tulips.jpg,Hydrangeas.jpg,Jellyfish.jpg])
    [DEBUG] [tomcat-http--30 02:16:20] (UploadController.java:message:33) Service processing...done
    [DEBUG] [tomcat-http--30 02:16:20] (TraceInterceptor.java:writeToLog:21) Leaving UploadController.message(): StatusResponse [success=true, message=Message received, ]
    

Note:

When adding a file via the "Add a file" link, the file is automatically uploaded to the backend. The backend responds with an object containing the filename (and other file details). When you click on the "Upload" button, the form data is sent along with the filename. The file itself is never uploaded in this second step because it's already in the server!

Import the project in Eclipse

  1. Ensure Maven is installed
  2. Open a command window (Windows) or a terminal (Linux/Mac)
  3. Run the following command:
    mvn eclipse:eclipse -Dwtpversion=2.0
  4. You should see the following output:
    [INFO] Scanning for projects...
    [INFO] Searching repository for plugin with prefix: 'eclipse'.
    [INFO] org.apache.maven.plugins: checking for updates from central
    [INFO] org.apache.maven.plugins: checking for updates from snapshots
    [INFO] org.codehaus.mojo: checking for updates from central
    [INFO] org.codehaus.mojo: checking for updates from snapshots
    [INFO] artifact org.apache.maven.plugins:maven-eclipse-plugin: checking for updates from central
    [INFO] artifact org.apache.maven.plugins:maven-eclipse-plugin: checking for updates from snapshots
    [INFO] -----------------------------------------
    [INFO] Building spring-fileupload-tutorial Maven Webapp
    [INFO]    task-segment: [eclipse:eclipse]
    [INFO] -----------------------------------------
    [INFO] Preparing eclipse:eclipse
    [INFO] No goals needed for project - skipping
    [INFO] [eclipse:eclipse {execution: default-cli}]
    [INFO] Adding support for WTP version 2.0.
    [INFO] -----------------------------------------
    [INFO] BUILD SUCCESSFUL
    [INFO] -----------------------------------------
    
    This command will add the following files to your project:
    .classpath
    .project
    .settings
    target
    You may have to enable "show hidden files" in your file explorer to view them
  5. Open Eclipse and import the project

Conclusion

That's it! We've have successfully completed our file upload application with Spring and jQuery-File-Upload plugin. We've learned how to setup an HTML form for file uploads with AJAX-like experience.

I hope you've enjoyed this tutorial. Don't forget to check my other tutorials at the Tutorials section.

Revision History


Revision Date Description
1 June 20 2012 Uploaded tutorial
2 June 26 2012 Corrected wrong entry url
3 June 27 2012 Corrected wrong entry url again

StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: File Upload with Spring and jQuery (Part 5) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Saturday, January 28, 2012

Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 1)

In this tutorial, we will create a simple CRUD application using Spring MVC 3.1, jqGrid, and Spring Data JPA. We will use jqGrid, a jQuery plugin, to present tabular data as an interactive grid, and Spring Data JPA to simplify the creation of JPA repositories (where Hibernate and MySQL are our JPA vendor and database respectively).


Dependencies

  • Spring core 3.1.0.RELEASE
  • Spring Data JPA 1.1.0 RC1
  • jQuery 1.6.4
  • jqGrid 4.3.1
  • See pom.xml for details

Github

To access the source code, please visit the project's Github repository (click here)

Functional Specs

Before we start, let's define our application's specs as follows:
  • A CRUD page for managing users
  • Use AJAX to avoid page refresh
  • Display reports in an interactive table
  • Users have roles. They are either admin or regular (default)
  • Everyone can create new users and edit existing ones
  • When editing, users can only edit first name, last name, and role fields
  • A username is assumed to be unique

Here's our Use Case diagram:
[User]-(View)
[User]-(Add) 
[User]-(Edit) 
[User]-(Delete) 

Database

Our database contains two tables: user and role tables.


user and role table design

User table

The user table contains personal information of each user. Notice the password values are hashed using Md5.

user table

Role table

The role table contains role values of each user. We define a role value of 1 as an admin, while a role value of 2 as a regular user.

role table

Screenshots

Before we start with the actual development, let's preview how our application should look like by providing screenshots. This is also a good way to clarify further the application's specs.

Entry page
The entry page is the primary page that users will see. It contains an interactive table where users can view, add, edit, and delete records on the same page.
Entry page (page 1)

Entry page (page 2)

Entry page (showing all records at once)

Create new record form
This form is used for adding new records. It is displayed when the user clicks on the Add button.
Create new record

Edit existing record form
This form is used for editing existing records. It is displayed when the user clicks on the Edit button. When editing, the form is pre-populated with the selected record's data.
Edit existing record

Alerts
You must select a record first alert is displayed whenever a user tries to edit or delete an existing record without selecting first that record.
Failure alert

Entry has been edited successfully alert is displayed whenever a successful action has been done, for example editing of an existing record.
Success alert

Filtered records
Records can be filtered by typing keywords on the menu toolbar.
Filtered records

Next

In the next section, we will discuss the project's structure and write the Java classes. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 1) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 3)

Review

In the previous section, we have created the Java classes and discussed jqGrid's jsonReader format. In this section, we will focus on the presentation layer, in particular the HTML and JavaScript files.


Presentation Layer

To display our data without page-refresh and interactively, we will add AJAX and jqGrid, a jQuery plugin, to present tabular data.

What is jQuery?

jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development. jQuery is designed to change the way that you write JavaScript.

Source: http://jquery.com/

What is jqGrid?

jqGrid is an Ajax-enabled JavaScript control that provides solutions for representing and manipulating tabular data on the web. Since the grid is a client-side solution loading data dynamically through Ajax callbacks, it can be integrated with any server-side technology, including PHP, ASP, Java Servlets, JSP, ColdFusion, and Perl.

Source: http://www.trirand.com/jqgridwiki/doku.php

Preview

We only have a single HTML file (users.jsp, a JSP to be exact) to perform all actions. This page contains our jqGrid table and buttons for interacting with the data.

Entry page

Source

At first glance, when you look at the JavaScript code, it is somewhat intimidating, but once you've familiarized with the jqGrid syntax, you'll find that it's actually simple. If you aren't familiary with jqGrid, please visit the jqGrid Official Wiki


You might be asking: "What's that humongous lines of jibberish code?" If you'd been following my blog, you would notice that I have tackled jqGrid a couple of times from my previous tutorials. If my explanation in this tutorial isn't enough, please see the following tutorials for an alternative perspective:


An In-depth Look

If we partition this HTML page, you will notice the following sections:
  • URL imports
  • JavaScript and CSS imports
  • jqGrid initialization
  • JavaScript functions: addRow(), editRow(), deleteRow()
  • HTML table

Notice how we've separated the HTML markup from the JavaScript code. We could, of course, move that one huge JavaScript code in an external js file, and make the HTML look somewhat smaller. But I'll leave that exercise to my readers.

Next

In the next section, we will focus on the configuration files for enabling Spring MVC. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 3) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 2)

Review

In the previous section, we have laid down the functional specs of the application. In this section, we will discuss the project's structure, write the Java classes, and organize them in layers.


Project Structure

Our application is a Maven project and therefore follows Maven structure. As we create the classes, we've organized them in logical layers: domain, repository, service, and controller.

Here's a preview of our project's structure:

The Layers

Domain

This layer contains two domain classes, User and Role. They represent our database tables, user and role respectively. Because we're developing a JPA-based repository, both classes must be annotated with JPA annotations.




Data Transfer Object (DTO)

This layer contains three DTO classes:
  • UserDto is a POJO for mapping User objects to and from the presentation layer
  • StatusResponse is a POJO for sending boolean responses to the presentation layer
  • JqgridResponse is a container for UserDto objects for sending records to the jqGrid table. It contains information regarding the number of rows, current page, and total pages.




What is the principle behind JqgridResponse's structure?

By default, the jqGrid plugin can process data in various formats: XML, JSON, Arrays, and etc. For this tutorial, we will use JSON because it's lightweight and simple. If we're going to use JSON, our JSON format must match our jqGrid's jsonReader property. Consequently, our DTO object must match as well.

Below is a sample jqGrid jsonReader property declaration:

Below is a sample JSON string that's acceptable to jqGrid (Notice the fields match the jsonReader fields and JqgridResponse's fields):
{"page":"1","total":"2","records":"2","rows":[{"id":1,"firstName":"John","lastName":"Smith","username":"john","role":1},{"id":2,"firstName":"Jane","lastName":"Adams","username":"jane","role":2}]}

Controller

This layer contains two controllers, MediatorController and UserController.
  • MediatorController is responsible for redirecting requests from the root path to the Users page
  • UserController is responsible for handling user related requests




The UserController in all cases, except for the getUsersPage() method, returns a JSON string as indicated in the @RequestMapping annotation:
produces="application/json"


The methods create(), update(), delete(), and get() are pretty much straightforward. However, the records() and getFilteredRecords() methods are somewhat more involved.

The records() method basically returns a list of UserDto objects as JSON strings. If the search prooperty is true, it will call the getFilteredRecords() method. Otherwise, it will retrieve all records.

The getFilteredRecords() is quite interesting. The basic algorithm is as follows:
  1. Convert a JSON String filter to a JqgridFilter object
  2. Use JqgridObjectMapper.map() method to do the conversion
    (After the conversion, a list of Rule objects are produced)
  3. Loop these list.
  4. If any of the fields match "username", "firstName", "lastName", and "role", store its value
    (This means we can only search within these fields.)
  5. Do a repository search based on non-empty field parameters
  6. Return the results to the presentation layer

Introducing Jsonquery

Question: What if I want to have a dynamic search on all fields? For example, instead of doing a "like" comparison, I want to do a "greater than" or "less than" and combine various operators, i.e. "and", "or".

Answer: This is not possible with the way I coded that here. And even if I could, it would be a big mess of if-else conditions. Luckily, there's a library that would simplify that for us: jsonquery

Jsonquery is a framework that translates SQL-like JSON queries to type-safe JPQL queries through Querydsl which means each query is type-safe, fluent, and SQL-like. Currently, the framework is designed for JPA-based backends.

To see the actual project, please visit https://github.com/markdevcode/jsonquery
To see the samples, please visit https://github.com/markdevcode/jsonquery-samples

However there are caveats:
  • It's not yet available from the Maven repository (it's on its way)
  • You must build and deploy the project from Github
  • You must use JPA and QueryDSL

Repository

This layer contains a single interface, UserRepository. This is our data access object (DAO). With the help of Spring Data JPA, Spring will automatically provide the actual implementation.

What is Spring Data JPA?

Spring JPA is part of the umbrella Spring Data project that makes it easy to easily implement JPA based repositories.

Implementing a data access layer of an application has been cumbersome for quite a while. Too much boilerplate code has to be written to execute simple queries as well as perform pagination, and auditing. Spring JPA aims to significantly improve the implementation of data access layers by reducing the effort to the amount that's actually needed. As a developer you write your repository interfaces, including custom finder methods, and Spring will provide the implementation automatically.

Source: http://www.springsource.org/spring-data/jpa

Service

This layer contains a single service, UserService. Its main purpose is to handle the CRUD operations for the User object. Notice all operations are eventually delegated to the UserRepository.

Utilities

  • JqgridFilter is a Java representation of a jqGrid filter
  • JqgridObjectMapper is used to convert a jqGrid filter to a JqgridFilter object
  • UserMapper is used to map User objects to UserDto objects
  • TraceInterceptor is an AOP-based utility class to help us debug our application. This is a subclass of CustomizableTraceInterceptor (see Spring Data JPA FAQ)

Next

In the next section, we will discuss the presentation layer and write the HTML and JavaScript files. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 2) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 4)

Review

In the previous section, we have focused on the presentation layer and discussed jqGrid. In this section, we will focus on the configuration files, in particular XML files.


Configuration

Database properties

Remember we'll use MySQL as our application's database. However, it's also possible to use a different database provider. Therefore, to make switching database simpler, we've externalized our database configuration within a properties file.


Application Context

Below is a typical application context file for enabling Spring MVC support.


Spring Data

In conjuction with the spring.properties file, we have to declare the actual datasource. Notice we're using JPA and Spring Data JPA support.


Next

In the next section, we will build and run the application using Maven, and show how to import the project in Eclipse. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 4) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 5)

Review

We have just completed our application! In the previous sections, we have discussed the functional specs, created the Java classes, declared the configuration files, and wrote the HTML files. In this section, we will build and run the application using Maven, and show how to import the project in Eclipse.


Running the Application

Access the source code

To download the source code, please visit the project's Github repository (click here)

Preparing the data source

  1. Run MySQL (install one if you don't have one yet)
  2. Create a new database:
    spring_jqgrid_tutorial
  3. Import the following file which is included in the source code under the src/main/resources folder:
    spring_jqgrid_tutorial.sql

Building with Maven

  1. Ensure Maven is installed
  2. Open a command window (Windows) or a terminal (Linux/Mac)
  3. Run the following command:
    mvn tomcat:run
  4. You should see the following output:
    [INFO] Scanning for projects...
    [INFO] Searching repository for plugin with prefix: 'tomcat'.
    [INFO] artifact org.codehaus.mojo:tomcat-maven-plugin: checking for updates from central
    [INFO] artifact org.codehaus.mojo:tomcat-maven-plugin: checking for updates from snapshots
    [INFO] ------------------------------------------
    [INFO] Building spring-jqgrid-tutorial Maven Webapp
    [INFO]    task-segment: [tomcat:run]
    [INFO] ------------------------------------------
    [INFO] Preparing tomcat:run
    [INFO] [apt:process {execution: default}]
    [INFO] [resources:resources {execution: default-resources}]
    [INFO] [tomcat:run {execution: default-cli}]
    [INFO] Running war on http://localhost:8080/spring-jqgrid-tutorial
    Jan 28, 2012 11:15:25 AM org.apache.catalina.startup.Embedded start
    INFO: Starting tomcat server
    Jan 28, 2012 11:15:25 AM org.apache.catalina.core.StandardEngine start
    INFO: Starting Servlet Engine: Apache Tomcat/6.0.29
    Jan 28, 2012 11:15:26 AM org.apache.catalina.core.ApplicationContext log
    INFO: Initializing Spring root WebApplicationContext
    Jan 28, 2012 11:15:32 AM org.apache.coyote.http11.Http11Protocol init
    INFO: Initializing Coyote HTTP/1.1 on http-8080
    Jan 28, 2012 11:15:32 AM org.apache.coyote.http11.Http11Protocol start
    INFO: Starting Coyote HTTP/1.1 on http-8080
    
  5. Note: If the project will not build due to missing repositories, please enable the repositories section in the pom.xml!

Access the Entry page

  1. Follow the steps with Building with Maven
  2. Open a browser
  3. Enter the following URL (8080 is the default port for Tomcat):
    http://localhost:8080/spring-jqgrid-tutorial/

Import the project in Eclipse

  1. Ensure Maven is installed
  2. Open a command window (Windows) or a terminal (Linux/Mac)
  3. Run the following command:
    mvn eclipse:eclipse -Dwtpversion=2.0
  4. You should see the following output:
    [INFO] Scanning for projects...
    [INFO] Searching repository for plugin with prefix: 'eclipse'.
    [INFO] org.apache.maven.plugins: checking for updates from central
    [INFO] org.apache.maven.plugins: checking for updates from snapshots
    [INFO] org.codehaus.mojo: checking for updates from central
    [INFO] org.codehaus.mojo: checking for updates from snapshots
    [INFO] artifact org.apache.maven.plugins:maven-eclipse-plugin: checking for updates from central
    [INFO] artifact org.apache.maven.plugins:maven-eclipse-plugin: checking for updates from snapshots
    [INFO] -----------------------------------------
    [INFO] Building spring-jqgrid-tutorial Maven Webapp
    [INFO]    task-segment: [eclipse:eclipse]
    [INFO] -----------------------------------------
    [INFO] Preparing eclipse:eclipse
    [INFO] No goals needed for project - skipping
    [INFO] [eclipse:eclipse {execution: default-cli}]
    [INFO] Adding support for WTP version 2.0.
    [INFO] -----------------------------------------
    [INFO] BUILD SUCCESSFUL
    [INFO] -----------------------------------------
    
    This command will add the following files to your project:
    .classpath
    .project
    .settings
    target
    You may have to enable "show hidden files" in your file explorer to view them
  5. Open Eclipse and import the project

Conclusion

That's it! We've have successfully completed our Spring MVC 3.1 web application. We've learned how to integrate with jqGrid and add AJAX functionality to make the application responsive.

I hope you've enjoyed this tutorial. Don't forget to check my other tutorials at the Tutorials section.

Revision History


Revision Date Description
1 Jan 28 2012 Uploaded tutorial and Github repository
2 Jan 30 2012 Update Functional Specs
3 Feb 11 2012 Update to Spring Data JPA 1.1.0 RC1

StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 5) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Friday, September 16, 2011

Spring MVC: Integrating MySQL, MongoDB, RabbitMQ, and AJAX - Part 1

Introduction

In this article we will explore how to integrate MySQL, MongoDB, and RabbitMQ in a Spring MVC application using Spring Data JPA, Spring Data MongoDB, and Spring AMQP projects respectively. Then we'll add AJAX in the presentation layer using jQuery. For presenting tabular data, we will explore two jQuery plugins: DataTables and jQgrid. The jQgrid version will use Spring Cache support to boost performance. The ultimate purpose of this article is to demonstrate how to integrate these different projects in a single Spring MVC application.

Our application is a simple event management system for performing CRUD operations. When we talk of events, we're referring to the colloquial definition, i.e wedding event. The application's main data will be stored in a MySQL database using Hibernate as our ORM. We will use Spring Data JPA to simplify the data access layer. This means we don't need to implement our own data access objects.

Our application is also capable of broadcasting these events as simple text messages. To broadcast these events, we will use RabbitMQ as our messaging broker, and Spring AMQP for sending and receiving of messages.

No application is free from errors. Therefore, we've added error persistence capability using MongoDB. Our application has logging capabilities already, but we want the ability to analyze these errors later. Therefore, this is where MongoDB plays in. To simplify the data access layer, we will use Spring Data MongoDB, similar with Spring Data JPA.

Table of Contents

  1. Event Management
  2. Messaging support
  3. Error persistence
  4. Build and deploy

Frequently Asked Questions (FAQs)

  1. Q: What is JPA?
    A: See http://en.wikipedia.org/wiki/Java_Persistence_API
  2. Q: What is MongoDB?
    A: See http://www.mongodb.org
  3. Q: What is RabbitMQ?
    A: See http://www.rabbitmq.com
  4. Q: What is Spring Data?
    A: See http://www.springsource.org/spring-data
  5. Q: What is Spring Data - JPA?
    A: See http://www.springsource.org/spring-data/jpa
  6. Q: What is Spring Data - MongoDB?
    A: See http://static.springsource.org/spring-data/data-document/docs/current/reference/html
  7. Q: What is Spring AMQP?
    A: See http://www.springsource.org/spring-amqp
  8. Q: What is jQuery?
    A: http://jquery.com/
  9. Q: What is AJAX?
    A: http://en.wikipedia.org/wiki/Ajax_(programming)
  10. Q: What is Ehcache?
    A: http://ehcache.org/

Required Tools and Services

The following tools and services are essential in building and running our project:
  1. MySQL
  2. The application's main data will be stored in MySQL. If you don't have one yet, download and install one by visiting the MySQL home page, or use a pre-packaged setup via XAMPP or Wamp.
    • MySQL: http://www.mysql.com/downloads/
    • Wamp: http://www.wampserver.com
    • XAMPP: http://www.apachefriends.org
  3. RabbitMQ
  4. We will publish and listen for messages using RabbitMQ. If you don't have one yet, download and install one by visiting the RabbitMQ home page.
    • http://www.rabbitmq.com/download.html
  5. MongoDB
  6. We will persist errors using MongoDB. If you don't have one yet, download and install one by visiting the MongoDB home page.
    • http://www.mongodb.org/downloads
  7. Maven
  8. We will use Maven to build our project. If you don't have one yet, download and install one by visiting the Maven home page. You can also use SpringSource Tool Suite (STS), an Eclipse-powered IDE, which has Maven pre-installed.
    • Maven: http://maven.apache.org/download.html
    • STS: http://www.springsource.com/developer/sts

Screenshots

Before we dive into development, it's better if we first visualize what we will be developing.






Live Deployment in the Cloud

The best way to interact with the application is with a live deployment. Therefore, I have taken extra steps to deploy the project in the cloud via the excellent open platform Cloud Foundry. To access the project, visit http://spring-mysql-mongo-rabbit.cloudfoundry.com/

Project Structure

To see how we're going to structure the project, take a look at the following screenshot:


The project's source code is available at GitHub. You can access the project's repository at spring-mysql-mongo-rabbit-integration

Project Dependencies (pom.xml)

The pom.xml contains the project's dependencies. It's a long list but I will only show the relevant entries. As of Sept 17 2011, we're using the latest versions.

What is POM?
POM stands for "Project Object Model". It is an XML representation of a Maven project held in a file named pom.xml. See http://maven.apache.org/pom.html

To see the pom's entire contents, please check the attached Maven project at the end of this tutorial.

Development

The project will be divided into four parts:
  1. Event Management
  2. Messaging support
  3. Error persistence
  4. Build and deploy

A. Event Management

The Event Management is the core function of the system. And we're specifically referring to the CRUD operations. We will divide this stage in four sub-parts:
  1. Event Management
    • A1. Domain
    • A2. Service
    • A3. Controller
    • A4. View
      1. DataTables view
      2. jQgrid view
    • A5. Crosscutting Concerns

A1. Domain

The domain contains a simple Event class. By marking it with @Entity the class will be persisted in a relational database. Notice the class has validation constraints added. For example, the name field cannot be null.

Special attention is given to the date field. We've annotated it with @DateTimeFormat, a Spring conversion annotation (see Spring Reference 5.6.2.1 Format Annotation API) to help us serialize and deserialize JSON dates in the presentation layer.

Event.java


A2. Service

Before we start developing the service layer we need to create first the data access objects (DAOs) manually. We do this for every new project. Through time it becomes repetitive and tedious. Gladly, Spring has a solution: the Spring Data project.

Spring Data's purpose is to provide us ready-made data access objects for various database sources. All we need to do is extend an interface and we're good to go. This means we can start writing the service immediately (if needed).

Spring Data is not a single project, but rather it's composed of many different projects specifically catering to different types of databases (see http://www.springsource.org/spring-data). Since we're using MySQL and Hibernate we will use the Spring Data JPA project.

IEventRepository.java


IEventService.java


EventService.java


A3. Controller

We have a single controller, EventController, whose main purpose is to display the Event page. It also has methods for handling CRUD operations that are ultimately delegated to the EventService.

EventController.java


A4. View

I've provided two views for displaying Event records: a DataTables version and a jQgrid version. The purpose of having two views is to demonstrate Spring's flexibility and teach various ways of presenting tabular data.

To proceed, please choose your preferred view (a specific guide will be presented):
  1. DataTables view
  2. jQgrid view

JMeter Test

The main difference between these two views are the addition of cache to the jQgrid controller. To appreciate the difference, I've provided JMeter tests to gauge each controller's performance. Take note that this tests have nothing to do with the DataTables or jQgrid plugin. The tests are written so that it will only query the controllers without generating the presentation layer.

Small dataset (9 records):

Large dataset (4300+ records):

Notice in small datasets the difference in performance is almost trivial. However, in large datasets the difference is phenomenal. Adding a cache greatly improves the application's performance (of course this assumes that the same request will be called multiple times).

Click here to download the JMeter Test. To run this test, make sure to run only one test, i.e do the DataTables first, then the jQgrid, or vice versa.

What is JMeter?
Apache JMeter is open source software, a 100% pure Java desktop application designed to load test functional behavior and measure performance. Source: http://jakarta.apache.org/jmeter/

A5. Crosscutting Concerns

As mentioned earlier, no application is free from errors. To facilitate troubleshooting, a logging mechanism needs to be added. Typically we would place the logging mechanism across our existing classes. This is a crosscutting concern.

What is a crosscutting concern?
In computer science, cross-cutting concerns are aspects of a program which affect other concerns. These concerns often cannot be cleanly decomposed from the rest of the system in both the design and implementation, and can result in either scattering (code duplication), tangling (significant dependencies between systems), or both.

For instance, if writing an application for handling medical records, the bookkeeping and indexing of such records is a core concern, while logging a history of changes to the record database or user database, or an authentication system, would be cross-cutting concerns since they touch more parts of the program. See http://en.wikipedia.org/wiki/Cross-cutting_concern

To implement a clean way of logging our application, we will take advantage of Spring's CustomizableTraceInterceptor support as seen in the Spring Data JPA reference (Appendix B. Frequently asked questions).

By default CustomizableTraceInterceptor uses trace level for logging. If we want to change the logging level, we need to extend this class and override the writeToLog() method. We have created a sub-class TraceInterceptor and change the logging level to debug

TraceInterceptor.java


After creating the class, we declare it as a bean in the XML configuration. Notice we've configured the entry and exit signature patterns and the pointcut expressions to match. In other words, this will log all services and specific controllers.

trace-context.xml


Next Section

In the next section, we will add messaging support using RabbitMQ and Spring AMQP. To proceed to the next section, click here.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring MVC: Integrating MySQL, MongoDB, RabbitMQ, and AJAX - Part 1 ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring MVC: Integrating MySQL, MongoDB, RabbitMQ, and AJAX - Part 3

Review

In the previous two sections, we've managed to create the core Event management system and integrated RabbitMQ messaging using Spring AMQP. For performing CRUD operations, we've utilized the Spring Data JPA project. In this section, we will integrate MongoDB and add error persistence.

Where am I?

Table of Contents

  1. Event Management
  2. Messaging support
  3. Error persistence
  4. Build and deploy

Error Persistence

It might be odd why we need to record errors in the application. Isn't the default logging feature enough? That depends. But for the purpose of this tutorial, we are doing it to explore MongoDB integration. There are also advantages with this approach. We can easily query and analyze our application's errors and provide a statistical view.

It's interesting that logging is the first use case listed in the MongoDB site and statistical analysis as the last well-suited use case (see MongoDB Use Cases).

We'll divide this page into five sections:
  1. C. Error Persistence
    • C1. Domain
    • C2. Service
    • C3. Aspect
    • C4. Controller
    • C5. View

C1. Domain

The domain contains a simple ErrorLog class. At the class head we've added @Document, a Spring Data MongoDB annotation, for efficiency reasons, and @Id to mark the field id as the class's identifier. If you scrutinize the application's domain classes, notice the @Id annotation in the Event.java (earlier) is from the javax.persistence package; whereas the @Id in ErrorLog.java is from the org.springframework.data.annotation package.

ErrorLog.java


C2. Service

Normally before we start developing the service layer we have to create first the data access objects (DAOs) manually. It becomes tedious as you keep repeating the same implementation. Gladly, Spring is here to rescue us from this repetitive task with Spring Data project.

Spring Data's main purpose is to provide us ready-made data access objects for various database sources. This means all we need to do is write our service to contain the business logic. And since we're using a MongoDB, we will use the corresponding Spring Data project: Spring Data MongoDB. (To see a list of other Spring Data projects, visit http://www.springsource.org/spring-data).

IErrorLogRepository.java


That's it. We're done with the service. Wait, where's the service? We don't create one since we don't have custom business logic that needs to be wrapped in a service. All we're doing is retrieval of records.

C3. Aspect

Error persistence, at its core, is no different with logging. It's a crosscutting concern. And similar with how we implemented AMQP messaging, we will use an Aspect to add error persistence.

We have declared EventMongoAspect with two pointcut expressions: one for the service and another for the controller. The interceptService() method handles and persists service errors, while the interceptController() method handles controller errors. We don't persist controller errors; instead we provide a default value so that when returning JSP pages we're not propagating stack traces to the browser.

EventMongoAspect.java


C4. Controller

The error controller is a simple controller with the single purpose of serving the error page.

ErrorController.java


C5. View

Our view is a single JSP page containing a table and an AJAX request for retrieving records. The setup is similar with the event-page.jsp (see A4. View), except we don't have dialogs for adding, editing, or deleting records.

The getRecords() function is the AJAX request responsible for retrieval and filling-in of records to the table. Then it will convert the table to a DataTables. The addition of DataTables is mainly for aesthetic purposes (and some nifty features like sorting and searching).

error-page.jsp


Result

You can preview the final output by visiting a live deployment at http://spring-mysql-mongo-rabbit.cloudfoundry.com/error


Next Section

In the next section, we will build and deploy our project using Tomcat and Jetty. To proceed, click here.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring MVC: Integrating MySQL, MongoDB, RabbitMQ, and AJAX - Part 3 ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring MVC: Integrating MySQL, MongoDB, RabbitMQ, and AJAX - Part 2

Review

In the previous section, we created the core Event management system and utilized the Spring Data JPA project to simplify data access. We've also added AJAX functionality to make the application responsive. In this section, we will integrate RabbitMQ and messaging in general.

Where am I?

Table of Contents

  1. Event Management
  2. Messaging support
  3. Error persistence
  4. Build and deploy

Messaging Support

Our application is capable of broadcasting events as simple text messages. These messages are CRUD actions and exceptions that arise during the lifetime of the application. This means if a user performs an add, edit, delete, or get these actions will be published to a message broker. If there are any exceptions, we will also publish them.

Why do we need to publish these events? First, it helps us study and explore RabbitMQ messaging. Second, we can have a third-party application whose sole purpose is to handle these messages for intensive statistical analysis. Third, it allows us to monitor in real-time and check the status of our application instantaneously.

If you're unfamiliar with messaging and its benefits, I suggest visiting the following links:

We'll divide this page into four sections:
  1. B. Messaging Support
    • B1. Aspect
    • B2. Configuration
    • B3. Controller
    • B4. View

B1. Aspect

We will publish CRUD operations as simple messages. It's like logging except we send the logs to a message broker. Usually we would add this feature across existing classes. Unfortunately, this leads to "scattering" and " tangling" of code. No doubt--it's a crosscutting concern. We have the same scenario when added the logging feature earlier (See A5. Crosscutting Concerns section earlier).

We have created an Aspect, EventRabbitAspect.java, to solve this concern. To send messages, we use the AmqpTemplate where we pass the exchange, routing key, and the message. Since we want to publish messages as they are called and also errors as they happened, we use @Around to capture these events. The proceeding code is a variation of the original tutorial Chatting in the Cloud: Part 1 by Mark Fisher (http://blog.springsource.com/2011/08/16/chatting-in-the-cloud-part-1/)

EventRabbitAspect.java


In order for Spring to recognize this aspect, make sure to declare the following element in your XML configuration (we've done this in the trace-context.xml):



B2. Configuration

After declaring the Aspect, we now declare and configure the RabbitMQ and Spring AMQP specific settings. In fact, you will soon discover that most of the work with Spring AMQP is configuration-related: declaration of queues, bindings, exchanges, and connection settings.

We've declared two queues: eventQueue for normal events, and errorQueue for errors. We have a single exchange, eventExchange where we declare the bindings for the two queues.

In order to send messages to the eventQueue, we set the routing key to event.general.*. Likewise, to send messages to the errorQueue, we set the routing key to event.error.*. For a tutorial on these concepts, please visit the official examples at http://www.rabbitmq.com/getstarted.html

spring-rabbit.xml


B3. Controller

After configuring RabbitMQ and Spring AMQP, we declare a controller, aptly named MonitorController. It's main purpose is to handle monitoring requests. This controller is based on Chatting in the Cloud: Part 1 blog by Mark Fisher (http://blog.springsource.com/2011/08/16/chatting-in-the-cloud-part-1/).

MonitorController.java


B4. View

We have two JSP pages event-monitor-page.jsp and error-monitor-page.jsp for event and error views respectively. We've utilized AJAX to pull information from the application. Again, this is based on Chatting in the Cloud: Part 1 blog by Mark Fisher (http://blog.springsource.com/2011/08/16/chatting-in-the-cloud-part-1/).

event-monitor-page.jsp


error-monitor-page.jsp


Result

You can preview the final output by visiting our live app at http://spring-mysql-mongo-rabbit.cloudfoundry.com/monitor/event


Next Section

In the next section, we will integrate MongoDB and add error persistence to the current application. To proceed to the next section, click here.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring MVC: Integrating MySQL, MongoDB, RabbitMQ, and AJAX - Part 2 ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share