BEING JAVA GUYS


Thursday, 8 August 2013

In this particular blog we will learn 'How to upload a file in Spring MVC and save it to a directory' .Spring supports MultipartResolver to handle file upload capabilities in a web application. We will add a 'MultipartResolver' bean to our spring configuration file to take advantage of Apache Commons upload library to handle upload in application.


Project Structure

Create a simple Maven Web application and import it to eclipse, now add required dependencies and controller file as shown in the later part of this tutorial.


Adding File Upload dependencies in Spring MVC

Add the following dependencies to your maven application to make it a spring web app and capable of file uploading.

\SpringFileUpload\pom.xml

Here is a list of required dependencies to use in a spring file upload example.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.beingjavaguys.fileupload</groupId>
 <artifactId>SpringFileUpload</artifactId>
 <packaging>war</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>SpringFileUpload Maven Webapp</name>
 <url>http://maven.apache.org</url>

 <properties>
  <spring.version>3.2.3.RELEASE</spring.version>
  <jdk.version>1.6</jdk.version>
 </properties>

 <dependencies>
  <!-- Spring framework -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring.version}</version>
  </dependency>

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${spring.version}</version>
  </dependency>

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-beans</artifactId>
   <version>${spring.version}</version>
  </dependency>

  <!-- Spring MVC framework -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${spring.version}</version>
  </dependency>

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>${spring.version}</version>
  </dependency>

  <!-- Apache Commons Upload -->
  <dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.2.2</version>
  </dependency>

  <!-- Apache Commons Upload -->
  <dependency>
   <groupId>commons-io</groupId>
   <artifactId>commons-io</artifactId>
   <version>1.3.2</version>
  </dependency>

  <!-- JSTL -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.1.2</version>
  </dependency>

  <dependency>
   <groupId>taglibs</groupId>
   <artifactId>standard</artifactId>
   <version>1.1.2</version>
  </dependency>
 </dependencies>
 <build>
  <finalName>SpringFileUpload</finalName>
  <plugins>
   <plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.1</version>
    <configuration>
     <url>http://localhost:8080/manager/text</url>
     <server>my-tomcat</server>
     <path>/SpringFileUpload</path>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.0</version>
    <configuration>
     <source>${jdk.version}</source>
     <target>${jdk.version}</target>
    </configuration>
   </plugin>
  </plugins>
 </build>
</project>



Adding Controller class

\src\main\java\com\beingjavaguys\controller\UploadController.java

This is a simple spring controller class having two mappings, the firsts one returns a jsp to show the uploading form. We have attached a 'UploadedFile' object with @ModelAttribute to make the uploading file a Multipart file object. In second method all code is written to how to get a multipart file object from uploading form and how to write it to a directory.
package com.beingjavaguys.controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.beingjavaguys.model.UploadedFile;
import com.beingjavaguys.validator.FileValidator;

@Controller
public class UploadController {

 @Autowired
 FileValidator fileValidator;

 @RequestMapping("/fileUploadForm")
 public ModelAndView getUploadForm(
   @ModelAttribute("uploadedFile") UploadedFile uploadedFile,
   BindingResult result) {
  return new ModelAndView("uploadForm");
 }

 @RequestMapping("/fileUpload")
 public ModelAndView fileUploaded(
   @ModelAttribute("uploadedFile") UploadedFile uploadedFile,
   BindingResult result) {
  InputStream inputStream = null;
  OutputStream outputStream = null;

  MultipartFile file = uploadedFile.getFile();
  fileValidator.validate(uploadedFile, result);

  String fileName = file.getOriginalFilename();

  if (result.hasErrors()) {
   return new ModelAndView("uploadForm");
  }

  try {
   inputStream = file.getInputStream();

   File newFile = new File("C:/Users/nagesh.chauhan/files/" + fileName);
   if (!newFile.exists()) {
    newFile.createNewFile();
   }
   outputStream = new FileOutputStream(newFile);
   int read = 0;
   byte[] bytes = new byte[1024];

   while ((read = inputStream.read(bytes)) != -1) {
    outputStream.write(bytes, 0, read);
   }
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

  return new ModelAndView("showFile", "message", fileName);
 }

}



Add a domain class to make the uploaded file a Multipart file

\src\main\java\com\beingjavaguys\model\UploadedFile.java

This is a simple java domain class having a single attribute of type MultipartFile, this is where our uploading file is being stored as an object.
package com.beingjavaguys.model;

import org.springframework.web.multipart.MultipartFile;

public class UploadedFile {

 private MultipartFile file;

 public MultipartFile getFile() {
  return file;
 }

 public void setFile(MultipartFile file) {
  this.file = file;
 }
}



Adding validation class to validate the uploading file

\src\main\java\com\beingjavaguys\validator\FileValidator.java

This is another simple java class having code to validate if the user uploaded a file before submitting the form or not.
package com.beingjavaguys.validator;

import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.beingjavaguys.model.UploadedFile;

public class FileValidator implements Validator {

 @Override
 public boolean supports(Class arg0) {
  // TODO Auto-generated method stub
  return false;
 }

 @Override
 public void validate(Object uploadedFile, Errors errors) {

  UploadedFile file = (UploadedFile) uploadedFile;

  if (file.getFile().getSize() == 0) {
   errors.rejectValue("file", "uploadForm.salectFile",
     "Please select a file!");
  }

 }

}



Adding a simple 'web.xml' file

src\main\webapp\WEB-INF\web.xml

This is a simple web.xml file having an entry for spring 'DispatcherServlet', this tells the container that all other upcoming requests are going to be served by spring itself.
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
       http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 version="2.5">

 <display-name>Sample Spring Maven Project</display-name>

 <servlet>
  <servlet-name>mvc-dispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
  <servlet-name>mvc-dispatcher</servlet-name>
  <url-pattern>*.htm</url-pattern>
 </servlet-mapping>

 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
 </context-param>

 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
</web-app>


Adding spring configuration file

\src\main\webapp\WEB-INF\mvc-dispatcher-servlet.xml

This is a simple spring configuration file containing a view resolver entry to map jsp names specified in controllers to the jsp files stored in project. We have also added a fileValidator bean here to validate user input and a 'multipartResolver' bean to take advantage of apache commons uploading capabilities.
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

 <context:component-scan base-package="com.beingjavaguys.controller" />

 <bean
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix">
   <value>/WEB-INF/pages/</value>
  </property>
  <property name="suffix">
   <value>.jsp</value>
  </property>
 </bean>

 <bean id="fileValidator" class="com.beingjavaguys.validator.FileValidator" />

 <bean id="multipartResolver"
  class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

</beans>


Adding a simple form to upload file

\src\main\webapp\WEB-INF\pages\uploadForm.jsp

This is a simple jsp file containing a form, the form is having a file input field to make user select and upload a file. Do not forget to set enctype="multipart/form-data", this w'll make the file object to be returned as a multipart object.
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
<script type="text/javascript" src="jquery-1.2.6.min.js"></script>
<title>Being Java Guys | Hello World</title>
</head>
<body>

 <center>
  <h2>Being Java Guys | Hello World</h2>
  <h3>Please select a file to upload !</h3>
  <br />
  <form:form method="post" enctype="multipart/form-data"
   modelAttribute="uploadedFile" action="fileUpload.htm">
   <table>
    <tr>
     <td>Upload File: </td>
     <td><input type="file" name="file" />
     </td>
     <td style="color: red; font-style: italic;"><form:errors
       path="file" />
     </td>
    </tr>
    <tr>
     <td> </td>
     <td><input type="submit" value="Upload" />
     </td>
     <td> </td>
    </tr>
   </table>
  </form:form>
 </center>
</body>
</html>



Adding a simple jsp file showing uploaded file details

\src\main\webapp\WEB-INF\pages\showFile.jsp

Another simple jsp file to show uploaded file details, when a file is successfully uploaded and stored to the targeted directory.
<html>
<head>
<title>Being Java Guys | Hello World</title>
</head>
<body>
 <center>

  <h2>Being Java Guys | Hello World</h2>
  <h3>
   File name : "<strong> ${message}</strong>" uploaded successfully !
  </h3>

 </center>
</body>
</html>



Here we are done with adding all required files and code to upload a file in spring, just run your project on server and hit the url 'localhost:8080/SpringFileUpload'. Or you can make a war from application to deploy it on server. If everything goes fine you will see following output screens:





In this particular blog we came across ‘How to upload a file in Spring MVC application', 'Validate a file upload in spring' and 'How to save uploaded file to a directory in spring'. In upcoming blogs we will see more about 'Spring MVC', Java and other opensource technologies.






Thanks for reading !
Being Java Guys Team

Download "Spring file upload Example Hello World project" from "SkyDrive"



2 comments:

  1. Thanks for the code...

    ReplyDelete
  2. Nice work!

    Only had one problem - I could not open the file after uploading because it was held by the server.

    In UploadController.java, I closed the output stream. Working great!

    try {
    outputStream.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    Thank you Zoe

    I closed the outputSteam

    ReplyDelete