Showing posts with label AJAX. Show all posts
Showing posts with label AJAX. 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

Thursday, February 16, 2012

Spring Batch Tutorial (Part 1)

In this tutorial, we will create a simple Spring Batch application to demonstrate how to process a series of jobs where the primary purpose is to import a lists of comma-delimited and fixed-length records. In addition, we will add a web interface using Spring MVC to teach how to trigger jobs manually, and so that we can visually inspect the imported records. In the data layer, we will use JPA, Hibernate, and MySQL.


Dependencies

  • Spring core 3.1.0.RELEASE
  • Spring Batch 2.1.8.RELEASE
  • 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 the application's specs as follows:
  • Import a list of comma-delimited records
  • Import a list of fixed-length records
  • Import a list of mixed-type records
  • Jobs must be triggered using a web interface
  • Display the imported records in a web interface
  • Each record represents a user and its associated access levels

Here's our Use Case diagram:
[User]-(Import job1)
[User]-(Import job2) 
[User]-(Import job3) 
[User]-(View records)

The CSV Files

To visualize what we want to do, let's examine first the files that we plan to import:

User Files

user1.csv
This file contains comma-separated value (CSV) records representing User records. Each line has the following tokens: username, first name, last name, password.

user2.csv
This file contains fixed-length records representing User records. Each line has the following tokens: username(positions 1-5), first name(6-9), last name(10-16), password(17-25).

user2.csv
This file contains comma-separated value and fixed-length records representing User records. Each line has the following tokens: username, first name, last name, password.

This file contains two types of CSV-records:
  • DELIMITED-RECORD-A: uses the standard comma delimiter
  • DELIMITED-RECORD-B: uses | delimiter

It also contains two types of fixed-length records:
  • FIXED-RECORD-A: username(16-20), first name(21-25), last name(26-31), password(32-40)
  • FIXED-RECORD-B: username(16-21), first name(22-27), last name(28-33), password(35-42)

Role Files

role1.csv
This file contains comma-separated value (CSV) records representing Role records. Each line has the following tokens: username and access level.

role2.csv
This file contains fixed-length records representing Role records. Each line has the following tokens: username and access level.

role3.csv
This file contains comma-separated value (CSV) records representing Role records. Each line has the following tokens: username and access level.

By now you should have a basic idea of the file formats that we will be importing. You must realize that all we want to do is import these files and display them on a web interface.

Diagrams

Here's the Class diagram:
# Cool UML Diagram
[User|id;firstName;lastName;username;password;role{bg:orange}]1--1> [Role|id;role{bg:green}]

Here's the Activity Diagram:

(start)->import->success->(Show Success Alert)->|a|->(end),
fail->(Show Fail Alert)->|a|,
view->(Show Records)->|a|->(end)

Screenshots

Let's preview how the application will look like after it's finished. 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 a table showing user records and four buttons for adding, editing, deleting, and reloading data. All interactions will happen in this page.

Entry page






Next

In the next section, we will 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 Batch Tutorial (Part 1) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring Batch Tutorial (Part 4)

Review

We have just completed our application! In the previous sections, we have discussed how to perform batch processing with Spring Batch. We have also created a Spring MVC application to act as a web interface. In this section, we will build and run the application using Maven, and demonstrate 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_batch_tutorial
  3. Import the following file which is included in the source code under the src/main/resources folder:
    schema-mysql.sql
    This script contains Spring Batch infrastructure tables which can be found in the Spring Batch core library. I have copied it here separately for easy access.

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-batch-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-batch-tutorial
    Feb 13, 2012 9:36:54 PM org.apache.catalina.startup.Embedded start
    INFO: Starting tomcat server
    Feb 13, 2012 9:36:55 PM org.apache.catalina.core.StandardEngine start
    INFO: Starting Servlet Engine: Apache Tomcat/6.0.29
    Feb 13, 2012 9:36:55 PM org.apache.catalina.core.ApplicationContext log
    INFO: Initializing Spring root WebApplicationContext
    Feb 13, 2012 9:37:01 PM org.apache.coyote.http11.Http11Protocol init
    INFO: Initializing Coyote HTTP/1.1 on http-8080
    Feb 13, 2012 9:37:01 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-batch-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-batch-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 Batch application and learned how to process of jobs in batches. We've also added Spring MVC support to allow jobs to be controlled online.

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 Feb 16 2012 Uploaded tutorial and Github repository

StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring Batch Tutorial (Part 4) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring Batch Tutorial (Part 2)

Review

In the previous section, we have laid down the functional specs of the application and examined the raw files that are to be imported. In this section, we will discuss the project's structure and write the Java classes.


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

Disclaimer

I will only discuss the Spring Batch-related classes here. And I've purposely left out the unrelated classes because I have described them in detail already from my previous tutorials. See the following guides:

Controller Layer

The BatchJobController handles batch requests. There are three job mappings:
  • /job1
  • /job2
  • /job3
Everytime a job is run, a new JobParameter is initialized as the job's parameter. We use the current date to be the distinguishing parameter. This means every job trigger is considered a new job.

What is a JobParameter?

"how is one JobInstance distinguished from another?" The answer is: JobParameters. JobParameters is a set of parameters used to start a batch job. They can be used for identification or even as reference data during the run:

Source: Spring Batch - Chapter 3. The Domain Language of Batch

Notice we have injected a JobLauncher. It's primary job is to start our jobs. Each job will run asynchronously (this is declared in the XML configuration).

What is a JobLauncher?

JobLauncher represents a simple interface for launching a Job with a given set of JobParameters:

Source: Spring Batch - Chapter 3. The Domain Language of Batch



Batch Layer

This layer contains various helper classes to aid us in processing batch files.
  • UserFieldSetMapper - maps FieldSet result to a User object
  • RoleFieldSetMapper - maps FieldSet result to a Role object. To assign the user, an extra JDBC query is performed
  • MultiUserFieldSetMapper - maps FieldSet result to a User object; it removes semi-colon from the first token.
  • UserItemWriter - writes a User object to the database
  • RoleItemWriter - writes a Role object to the database. To assign the user, an extra JDBC query is performed







Next

In the next section, we will focus on the configuration files. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring Batch Tutorial (Part 2) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring Batch Tutorial (Part 3)

Review

In the previous section, we have written and discussed the Spring Batch-related classes. In this section, we will write and declare the Spring Batch-related configuration files.


Configuration

Properties File

The spring.properties file contains the database name and CSV files that we will import. A job.commit.interval property is also specified which denotes how many records to commit per interval.



Spring Batch

To configure a Spring Batch job, we have to declare the infrastructure-related beans first. Here are the beans that needs to be declared:

  • Declare a job launcher
  • Declare a task executor to run jobs asynchronously
  • Declare a job repository for persisting job status

What is Spring Batch?

Spring Batch is a lightweight, comprehensive batch framework designed to enable the development of robust batch applications vital for the daily operations of enterprise systems. Spring Batch builds upon the productivity, POJO-based development approach, and general ease of use capabilities people have come to know from the Spring Framework, while making it easy for developers to access and leverage more advance enterprise services when necessary. Spring Batch is not a scheduling framework.

Source: Spring Batch Reference Documentation

What is a JobRepository?

JobRepository is the persistence mechanism for all of the Stereotypes mentioned above. It provides CRUD operations for JobLauncher, Job, and Step implementations.

Source: Spring Batch - Chapter 3. The Domain Language of Batch

What is a JobLauncher?

JobLauncher represents a simple interface for launching a Job with a given set of JobParameters

Source: Spring Batch - Chapter 3. The Domain Language of Batch

Here's our main configuration file:



Notice we've also declared the following beans:
  • Declare a JDBC template
  • User and Role ItemWriters

Job Anatomy

Before we start writing our jobs, let's examine first what constitutes a job.

What is a Job?

A Job is an entity that encapsulates an entire batch process. As is common with other Spring projects, a Job will be wired together via an XML configuration file

Source: Spring Batch: The Domain Language of Batch: Job

Each job contains a series of steps. For each of step, a reference to an ItemReader and an ItemWriter is also included. The reader's purpose is to read records for further processing, while the writer's purpose is to write the records (possibly in a different format).

What is a Step?

A Step is a domain object that encapsulates an independent, sequential phase of a batch job. Therefore, every Job is composed entirely of one or more steps. A Step contains all of the information necessary to define and control the actual batch processing.

Source: Spring Batch: The Domain Language of Batch: Step

Each reader typically contains the following properties
  • resource - the location of the file to be imported
  • lineMapper - the mapper to be used for mapping each line of record
  • lineTokenizer - the type of tokenizer
  • fieldSetMapper - the mapper to be used for mapping each resulting token

What is an ItemReader?

Although a simple concept, an ItemReader is the means for providing data from many different types of input. The most general examples include: Flat File, XML, Database

Source: Spring Batch: ItemReaders and ItemWriters

What is an ItemWriter?

ItemWriter is similar in functionality to an ItemReader, but with inverse operations. Resources still need to be located, opened and closed but they differ in that an ItemWriter writes out, rather than reading in.

Source: Spring Batch: ItemReaders and ItemWriters

The Jobs

As discussed in part 1, we have three jobs.

Job 1: Comma-delimited records

This job contains two steps:
  1. userLoad1 - reads user1.csv and writes the records to the database
  2. roleLoad1 - reads role1.csv and writes the records to the database
Notice userLoad1 is using DelimitedLineTokenizer and the properties to be matched are the following: username, firstName, lastName, password. Whereas, roleLoad1 is using the same tokenizer but the properties to be matched are the following: username and role.

Both steps are using their own respective FieldSetMapper: UserFieldSetMapper and RoleFieldSetMapper.

What is DelimitedLineTokenizer?

Used for files where fields in a record are separated by a delimiter. The most common delimiter is a comma, but pipes or semicolons are often used as well.

Source: Spring Batch: ItemReaders and ItemWriters


Job 2: Fixed-length records

This job contains two steps:
  1. userLoad2 - reads user2.csv and writes the records to the database
  2. roleLoad2 - reads role2.csv and writes the records to the database

Notice userLoad2 is using FixedLengthTokenizer and the properties to be matched are the following: username, firstName, lastName, password. However, instead of matching them based on a delimiter, each token is matched based on a specified length: 1-5, 6-9, 10-16, 17-25 where 1-5 represents the username and so forth. The same idea applies to roleLoad2.

What is FixedLengthTokenizer?

Used for files where fields in a record are each a 'fixed width'. The width of each field must be defined for each record type.

Source: Spring Batch: ItemReaders and ItemWriters


Job 3: Mixed records

This job contains two steps:
  1. userLoad3 - reads user3.csv and writes the records to the database
  2. roleLoad3 - reads role3.csv and writes the records to the database

Job 3 is a mixed of Job 1 and Job 2. In order to mix both, we have to set our lineMapper to PatternMatchingCompositeLineMapper.

What is PatternMatchingCompositeLineMapper?

Determines which among a list of LineTokenizers should be used on a particular line by checking against a pattern.

Source: Spring Batch: ItemReaders and ItemWriters

For the FieldSetMapper, we are using a custom implementation MultiUserFieldSetMapper which removes a semicolon from the String. See Part 2 for the class declaration.



Next

In the next section, we will run the application using Maven. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring Batch Tutorial (Part 3) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Tuesday, January 31, 2012

Spring MVC 3.1 and JasperReports: Using iReport and AJAX (Part 1)

In this tutorial, we will study how to generate reports from a Spring MVC 3.1 application using JasperReports. We will use jQuery and jqGrid to provide AJAX support and an interactive table. To design the report, we will use iReport, an open source report designer for JasperReports. On the data layer, we'll utilize MySQL, Hibernate, and Spring Data JPA.


Dependencies

  • Spring core 3.1.0.RELEASE
  • Spring Data JPA 1.1.0.M1
  • jQuery 1.6.4
  • jqGrid 4.3.1
  • Jasper Reports 4.5.0
  • 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:
  • Display reports in an interactive table
  • Downloadable reports in PDF and Excel formats
  • Use AJAX to avoid page refresh
  • Users have roles. They are either admin or regular (default)
  • A username is assumed to be unique

Here's our Use Case diagram:
[User]-(View)
[User]-(Download Pdf) 
[User]-(Download Excel)

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 will look like. 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 and download records.
Entry page

Pdf document
This is the downloadable Pdf document whenever the user clicks on the Pdf button.
Report in Pdf format as previewed from Chrome

Excel document
This is the downloadable Excel document whenever the user clicks on the Excel button. When using Excel format, the document's appearance varies depending on the application, i.e Microsoft Excel, Google Docs, Open Office.
Report in Excel format as previewed from Google Docs

Progress dialog
When a user clicks on any of the download buttons (Pdf or Excel), a progress dialog will appear and disappears once the download starts.
Progress alert


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 and JasperReports: Using iReport and AJAX (Part 1) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring MVC 3.1 and JasperReports: Using iReport and AJAX (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 and write the Java classes 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 four 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.
  • JasperDto is a POJO for mapping User objects into something that Jasper can process easily (This is used for reporting purposes only.)

Note: We won't display the contents of UserDto, StatusReponse, and JqgridResponse here since we've already discussed that on a different tutorial (see Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 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, including download requests




Let's describe the methods available from UserController:
  • The records() method returns a list of UserDto objects as JSON strings. This will be displayed on the presentation layer as an interactive grid of data with the help of jqGrid plugin.
  • checkDownloadProgress() method is used to check if a download token is present or not. See Download Token Algorithm below
  • getDownloadToken() method is used to retrieve a download token. See Download Token Algorithm below
  • download() method performs the actual report download by delegating it to the DownloadService.

Download Token Algorithm
(Inspired by Detect when browser receives file download)

This is basically a fancy way of adding a progress box in an AJAX environment, so that we can display the status of a download requests. In a typical AJAX requests, the call is perform asynchronously, and the user does not know if the requests is being processed unless we provide a progress report. Unfortunately, you can't use AJAX directly for file downloads.

However, you can provide an illusion of a progress report through the Download Token Algorithm:
  1. User clicks on download button. A progress box appears.
  2. Download button performs an AJAX requests to retrieve a download token
  3. Once a download token has been received, a call to the actual download URL is performed. (This is not an AJAX requests)
  4. Periodically perform an AJAX requests to check if the download token retrieved earlier still exists. If not, the download has started.
  5. If the download token does not exists anymore, close the progress box.

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 the following services:
  • TokenService: This is responsible for providing and managing download tokens. See the Download Token Algorithm above.
  • JasperDatasourceService: Wraps a list of objects into a JRBeanCollectionDataSource. This is the datasource for our Jasper reports.
  • ExporterService: This is responsible for exporting a Jasper report into different formats, such as Pdf and Excel.
  • DownloadService: This is responsible for the actual download requests and writing of reports to the output stream






The DownloadService is the heart of the download process. The algorithm is as follows:
  1. Add report parameters
  2. Retrieve template
  3. Convert template to JasperDesign
  4. Compile design to JasperReport
  5. Create the JasperPrint object
  6. Create an output byte stream where data will be written
  7. Export report
  8. Write to reponse stream

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

Note: We won't display the contents of JqgridFilter, JqgridObjectMapper, UserMapper, and TraceInterceptor here since we've already discussed them on a different tutorial. See Spring Data JPA FAQ

Next

In the next section, we will create the Jasper report layout and design it using iReport. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring MVC 3.1 and JasperReports: Using iReport and AJAX (Part 2) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring MVC 3.1 and JasperReports: Using iReport and AJAX (Part 3)

Review

In the previous section, we have created the Java classes and discussed the download process. In this section, we will focus on the Jasper layout and study how to design one using iReport.


Jasper Layout

The Jasper report layout is basically an XML document. You can create it through any text editor (if you know the syntax) or you can use a WYSWYG-editor. We choose the latter because it's easier.

What is iReport?

iReport is the free, open source report designer for JasperReports. Create very sophisticated layouts containing charts, images, subreports, crosstabs and much more. Access your data through JDBC, TableModels, JavaBeans, XML, Hibernate, CSV, and custom sources. Then publish your reports as PDF, RTF, XML, XLS, CSV, HTML, XHTML, text, DOCX, or OpenOffice.

Source: iReport

Final Design

Before we proceed, let's preview the final design:

Admittedly, this isn't the best looking design, but it's good enough for our purpose.


Project Structure

Below is a screenshot of the project's structure:

Installation

To start using iReport, we must first download and install one. Below are the instructions for installing and running iReport in Windows (Ubuntu will follow later):

Windows
1. Open a browser and visit the iReport site at http://jasperforge.org/projects/ireport

2. Click on the download button. It will ask you to register first, but you can skip it.
You should see the following options:

3. Choose the Windows installer.

4. Once the download is finished, install it.

Designing

We'll now start designing our report

1. Run iReport

2. Go to File and click New. You should see the following window

3. Select Report and click on the Coffee Landscape template. You will be asked to save the project.

4. Click Finish when done. You should see the following window:

Now, it's time to design the report.

5. On the left side, under the Report Inspector, you should see a list of items. Expand the Fields section. You should see the following items: id, username, firstName, lastName, role.

Click on any of the fields and change their properties as indicated below (the Properties panel is located on the right-side):






6. On the left side, under the Report Inspector, expand the Detail section. You should see the following items: $F{id}, $F{username}, $F{firstName}, $F{lastName}, $F{role}. These are value placeholders.

Click on any of the fields and change their properties as indicated below. Make sure to edit the Detail section itself and the bounding box as well.









7. On the left side, under the Report Inspector, expand the Column Header section. You should see the following items: ID, Username, First Name, LastName, Role. These are the labels for each fields accordingly.

Click on any of the fields and change their properties as indicated below. Make sure to edit the Detail section itself and the bounding box as well.






8. Now, let's update the title. Change it from Coffee Title to User Records


9. Update the subtitle as well. Change it from Coffee SubTitle to A Summary:

10. We're done with the design. Now, let's update the report's programming language (This is critical!). Click outside the report layout. Then on the Properties panel, scroll down and look for the Language property. Change it from Groovy to Java!

Before
After
11. Save the file, and we're done.

Transferring the Layout

After creating the design, we should now copy and save it to the classpath directory of our Spring project.

Here are the steps:

1. Open the folder or directory where you saved your report. Notice that the images are saved along with the report.
  • coffee.jpg: an image
  • coffee_stain.jpg: an image
  • users.jasper: compiled report (we don't need this one)
  • users.jrxml: the report layout (this is important)

2. Copy all the files except the users.jasper and paste it under the src/main/resources folder of your Spring project.

That's it! We've completed the transfer.

Next

In the next section, we will focus on the presentation layer, in particular the tabular display of our records using jqGrid and HTML. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring MVC 3.1 and JasperReports: Using iReport and AJAX (Part 3) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share