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.
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:
User fills-in the form's text inputs, i.e owner and description
User clicks on "Add a file" link. Browsers for a file and attaches it
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
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.
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.
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
StatusResponse is used to determine the status of a request, and includes an error message if any.
StatusResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Endpoint Urls
We've declared two global urls: messageUploadUrl and fileUploadUrl. These are the endpoints for uploading messages and files respectively.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Import Scripts
Based on the jQuery-File-Uploadbasic 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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Initialization Function
This function contains the following initialization steps:
Beautify buttons
Attach submit function
Attach clear function
Attach file upload function
Initialize filelist data
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File Display Function
This is used for formatting filenames. The output is similar to the following: filename (256.50K)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Dialog Function
This is a helper function for displaying dialog boxes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Clear Function
This clears the form of its contents.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
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.
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
Ensure Maven is installed
Open a command window (Windows) or a terminal (Linux/Mac)
Run the following command:
mvn eclipse:eclipse -Dwtpversion=2.0
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
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.
In this article we will study how to send email with Spring by integrating with SendGrid's email service. Instead of the usual SMTP, we will use HTTP to communicate with SendGrid.
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 compose and send emails
Emails do not need to be persisted in a database
Send email via HTTP instead of SMTP to avoid firewall issues
Here's our Use Case diagram:
[User]-(Compose)
[User]-(Send)
In MVC terms, we decompose the application as follows:
Model: A simple Map object that conforms with SendGrid's message format
View: An HTML-based form where users can compose and send emails
Controller: Spring controller that receives the request. The controller delegates actual work to the service layer which eventually executes an HTTP call to send email to SendGrid.
What is SendGrid?
SendGrid's cloud-based email infrastructure relieves businesses of the cost and complexity of maintaining custom email systems. SendGrid provides reliable delivery, scalability and real-time analytics along with flexible API's that make custom integration a breeze.
Source: http://www.sendgrid.com
Why SendGrid?
It's easy to integrate with.
It has a free plan that allows 200 email messages per day.
SendGrid has an HTTP API for sending emails which is very simple to use.
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 compose and send emails.
Compose Email Form
After clicking "Send", the email message is sent. An alert is shown to confirm the action.
Sent alert
When user clicks on "Reset", the contents of the fields are cleared. An alert is shown to confirm the action.
Fields cleared alert
Email Messages
This is the sample email received from Gmail. Notice Gmail is able to show that this email was sent via SendGrid.
Gmail email
email details
This is the sample email received from Yahoo.
Yahoo email
Next
In the next section, we will show how to sign-up with SendGrid's email service. This is required before we can start sending emails. Click here to proceed.
In the previous section, we have laid down the functional specs of the application . In this section, we will demonstrate how to sign-up with SendGrid's email service. This is required so that we can integrate with their service.
Disclaimer
SendGrid manually approves each account. It takes almost a day before they can approve your account. If it takes longer, I suggest sending an email to their tech support.
1. Go to SendGrid's page at http://www.sendgrid.com
2. Click on "Pricing" and scroll-down.
3. At the bottom portion of the page, there's a link to the "Free Plan". Click it.
4. The account creation page is displayed. Fill-in the details. Then submit your application. Remember your username and password here. These will be your API username and key.
5. You will be redirected to the "Get Started" page. Complete all the required actions. Notice your account is on provision. It might take a day for it to be approved.
Account Completion
Once your account has been provisioned, visit your SendGrid account page
SendGrid API
SendGrid offers numerous APIs to allow developers to fully integrate with their service. They have the following APIs:
Customer Subuser API
Event API
Parse API
Web API
SMTP API
Reseller API
Newsletter API
We will focus on the Mail module, which is under the Web API. Please see http://docs.sendgrid.com/documentation/api/web-api/mail/#send for the complete documentation.
To test the Mail module, you can either use your browser or CURL (if you're familiar with it).
But how do we use the Web API via Java and Spring? We will discuss that on the next section. But to satisfy your inquisitive minds, here's a preview:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
In the previous section, we have learned how to sign-up with SendGrid's free plan. In this section, we will start writing the Java classes and discuss the project's 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 represents an email message.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The controller layer contains a simple controller that serves a form for composing and sending emails. It also contains a send method that accepts a Message object. The controller delegates the sending part to an email service.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The service layer contains the email service. We have a simple interface EmailService for sending messages.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The actual implementation SendGridEmailService relies on RestTemplate to send the email message via HTTP as a POST method.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This layer contains helper classes and interfaces. Here we've extracted the required SendGrid parameters for sending emails via HTTP. Please refer to Part 2 of this guide if you need to review the SendGrid Web API.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The view layer contains a simple html form for composing and sending email messages. One important section here that needs to be discussed is the usage of the postJSON plugin.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
postJSON is a jQuery plugin that allows sending of JSON objects via POST. This plugin is based a plugin I found at the jQuery plugin repository. Unfortunately, the location doesn't seem to exist anymore. Also, I've made some modifications with the plugin (see the comments).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* success: The success handler to invoke on successful submission
* options: Additional options to provide to the AJAX call. This is the exact same object you would use when calling $.ajax directly.
*
* Description:
* $.postJSON simplifies posting JSON objects to any url by invoking $.ajax with the required options. The specified JSON object will be stringified and posted to the url.
* It's up to the server to deserialize the stringified JSON object. ASP.NET MVC 3 will do this automatically
In the previous section, we have implemented the Java classes. In this section, we will start writing the configuration files to complete our Spring application.
To complete our application, here are the important configuration files that needs to be declared:
spring.properties
applicationContext.xml
spring-servlet.xml
web.xml
The spring.properties file contains the SendGrid user and key values to access the Web API. This is equivalent to your SendGrid's username and password.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
Open a command window (Windows) or a terminal (Linux/Mac)
Run the following command:
mvn eclipse:eclipse -Dwtpversion=2.0
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-sendgrid-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
Open Eclipse and import the project
Conclusion
That's it! We've have successfully completed our email application with Spring and SendGrid integration. We've learned how to setup a SendGrid account and how to utilize its Web API via Spring's RestTemplate.
I hope you've enjoyed this tutorial. Don't forget to check my other tutorials at the Tutorials section.