Skip navigation

This article will show how to upload and download in web application using Spring-MVC. The application will upload any file format and save it to database, likewise when downloading it will read from database and open save download dialog.

Consider a form like this:

Here is html code:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
  <head><title>Upload and Download files using Spring</title></head>
  <body>
    <table width="80%" border="1" cellspacing="0" cellpadding="5">
        <tr>
            <th width="4%">No</th>
            <th width="30%">Filename</th>
            <th width="30%">Notes</th>
            <th width="16%">Type</th>
            <th width="20%">&nbsp;</th>
        </tr>
        <c:choose>
            <c:when test="${files != null}">
                <c:forEach var="file" items="${files}" varStatus="counter">
                    <tr>
                        <td>${counter.index + 1}</td>
                        <td>${file.filename}</td>
                        <td>${file.notes}</td>
                        <td>${file.type}</td>
                        <td><div align="center"><a href="download.htm?id=${file.id}">Download</a> /
                            <a href="delete.htm?id=${file.id}">Delete</a></div>
                        </td>
                    </tr>
                </c:forEach>
            </c:when>
        </c:choose>
    </table>

    <h2>Add New File</h2>
    <form action="upload.htm" method="post" enctype="multipart/form-data">
        <table width="60%" border="1" cellspacing="0">
            <tr>
                <td width="35%"><strong>File to upload</strong></td>
                <td width="65%"><input type="file" name="file" /></td>
            </tr>
            <tr>
                <td><strong>Notes</strong></td>
                <td><input type="text" name="notes" width="60" /></td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td><input type="submit" name="submit" value="Add"/></td>
            </tr>
        </table>
    </form>
  </body>
</html>

To upload a file from web page we need to set a form with property enctype="multipart/form-data" . This will use by action/controller how to handle the data.

To save a binary file to database we use column with type Blob. I’m using Mysql database, i’m choose column with type longblob. There’s three type of blob in Mysql (other is blob and mediumblob), i’m using longblob so it can store more bigger file. This is create table script:

 

CREATE TABLE `files` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `filename` varchar(100) NOT NULL,
  `notes` varchar(100) default NULL,
  `type` varchar(40) default NULL,
  `file` longblob default NULL,
  PRIMARY KEY  (`id`)
);

 

As we can see column ‘file’ type longblob, we wil use to store the binary of a file. Column ‘filename’ to store original file name, column ‘type’ to save the type of the file, and column ‘notes’ is optional.

And here is the java bean to represent the table:

package com.spring.example.bean;
public class Files {
    private int id;
    private String filename;
    private String notes;
    private String type;
    private byte[] file;

    // please make setter and getter
}

For the blob type column, i use bytes array rather that Java Blob type. It will suit accross different databases blob type.

Service/manager/DAO
For database layer we’re using Spring JDBC, so we create service class that extends JdbcDaoSupport class.

package com.spring.example.web;
import org.springframework.web.servlet.mvc.AbstractController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.spring.example.service.FilesService;
import com.spring.example.bean.Files;
import java.util.List;

public class FilesService extends JdbcDaoSupport {
    String query = null;

    /**
     * find
     */
    public Files find(int id) {
        query = "select * from files where id = ?";

        try {
            Files file = (Files) getJdbcTemplate().queryForObject(query, new Object[] {id},
                new RowMapper() {
                    Files fl;
                    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                        fl = new Files();
                        fl.setId(rs.getInt(1));
                        fl.setFilename(rs.getString(2));
                        fl.setNotes(rs.getString(3));
                        fl.setType(rs.getString(4));
                        fl.setFile(rs.getBytes(5));

                        return fl;
                    }
            });

            return file;
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    /**
     * listAll
     */
    public List<Files> listAll() {
        query = "select id, filename, notes, type from files";

        try{
            List<Files> files = getJdbcTemplate().query(query, new BeanPropertyRowMapper(Files.class));

            return files;
        } catch(Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * save
     */
    public void save(final Files file) {
        query = "insert into files (filename, notes, type, file) values (?, ?, ?, ?)";

        try {
            synchronized(this) {
                getJdbcTemplate().update(new PreparedStatementCreator() {

                    public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
                        PreparedStatement statement = con.prepareStatement(query);
                        statement.setString(1, file.getFilename());
                        statement.setString(2, file.getNotes());
                        statement.setString(3, file.getType());
                        statement.setBytes(4, file.getFile());
                        return statement;
                    }
                });
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * delete
     */
    public void delete(int id) {
        query = "delete from files where id = ?";

        try {
            getJdbcTemplate().update(query, new Object[] {id});
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

File List Form
Here is the controller that will query all the files that we had upload, send it to page so it will display all uploaded files, then we can download or delete it. And we can upload a new file.

package com.spring.example.web;
import org.springframework.web.servlet.mvc.AbstractController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.spring.example.service.FilesService;
import com.spring.example.bean.Files;
import java.util.List;

public class FilesForm extends AbstractController {
    private FilesService filesService;

    public void setFilesService(FilesService filesService) {
        this.filesService = filesService;
    }

    protected ModelAndView handleRequestInternal(HttpServletRequest request,
        HttpServletResponse response) throws Exception {

        List<Files> files = this.filesService.listAll();

        return new ModelAndView("files", "files", files);
    }
}

Files Controller
This is a Spring MultiActionController so i dont need separate controller class file to upload, download, and delete a file.

package com.spring.example.web;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.util.FileCopyUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.spring.example.bean.Files;
import com.spring.example.service.FilesService;

public class FilesController extends MultiActionController {
    private FilesService filesService;

    public void setFilesService(FilesService filesService) {
        this.filesService = filesService;
    }

    /**
     * upload
     */
    public ModelAndView upload(HttpServletRequest request,
        HttpServletResponse response) throws Exception {

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        MultipartFile multipartFile = multipartRequest.getFile("file");

        Files file = new Files();
        file.setFilename(multipartFile.getOriginalFilename());
        file.setNotes(ServletRequestUtils.getStringParameter(request, "notes"));
        file.setType(multipartFile.getContentType());
        file.setFile(multipartFile.getBytes());

        this.filesService.save(file);

        return new ModelAndView("redirect:files.htm");
    }

    /**
     * download
     */
    public ModelAndView download(HttpServletRequest request,
        HttpServletResponse response) throws Exception {
        int id = ServletRequestUtils.getRequiredIntParameter(request, "id");

        Files file = this.filesService.find(id);

        response.setContentType(file.getType());
        response.setContentLength(file.getFile().length);
        response.setHeader("Content-Disposition","attachment; filename=\"" + file.getFilename() +"\"");

        FileCopyUtils.copy(file.getFile(), response.getOutputStream());

        return null;

    }

    /**
     * delete
     */
    public ModelAndView delete(HttpServletRequest request,
        HttpServletResponse response) throws Exception {
        int id = ServletRequestUtils.getRequiredIntParameter(request, "id");

        this.filesService.delete(id);

        return new ModelAndView("redirect:files.htm");
    }
}

applicationContext.xml
Here is the applicationContext.xml, please change proper value to match your environtment:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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.xsd">

    <!-- datasource -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/test">
        </property>
    </bean>

    <!-- template -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- services -->
    <bean id="filesService" class="com.spring.example.service.FilesService">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
</beans>

dispatcher-servlet.xml
The dispatcher-servlet.xml contains list of mapping url address to controller class, i use SimpleUrlHandlerMapping class for url handler mapping. And there’s two view resolver, the basic InternalResourceViewResolver and CommonsMultipartResolver to handle file upload, i set the ‘maxUploadSize’ property to 5Mb.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- mapping -->
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="files.htm">filesForm</prop>
                <prop key="upload.htm">filesController</prop>
                <prop key="download.htm">filesController</prop>
                <prop key="delete.htm">filesController</prop>
            </props>
        </property>
    </bean>

    <!-- The view resolver -->
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="5242880" />
    </bean>

    <!-- controller -->
    <bean id="filesForm" class="com.spring.example.web.FilesForm">
        <property name="filesService" ref="filesService"/>
    </bean>

    <bean id="filesController" class="com.spring.example.web.FilesController">
        <property name="filesService" ref="filesService"/>
        <property name="methodNameResolver">
            <bean class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
                <property name="mappings">
                    <props>
                        <prop key="/upload.htm">upload</prop>
                        <prop key="/download.htm">download</prop>
                        <prop key="/delete.htm">delete</prop>
                    </props>
                </property>
            </bean>
        </property>
    </bean>
</beans>

Common Errors/Exception when upload a file (in Mysql)
Commons error during file upload process is how big size of file can be transferred to a server or save to a databases.
If you experienced similiar error like this, when using mysql database:

 

Packet for query is too large (1217245 > 1047552). You can change this value
on the server by setting the max_allowed_packet' variable.; nested exception is
com.mysql.jdbc.PacketTooBigException: Packet for query is too large (1217245 > 1047552).
You can change this value on the server by setting the max_allowed_packet' variable.

 

or

 

Caused by: com.mysql.jdbc.PacketTooBigException: Packet for query is too
large (1217245 > 1047552). You can change this value on the server by setting
the max_allowed_packet' variable.

 

In Unix/Linux system open file “/etc/my.cnf“, look for the max_allowed_packet string and set the max value you want to.

Here, here and here is the code.

33 Comments

  1. very informative..thanks a lot.
    james smith
    javajobs.net

  2. Agree with James, but it is absolutely ridiculous that it takes so much code to up/download an image to the database.

    This must have been done a thousand times before? Is there no reusable component to handle this for you?

    • Well i dont think it’s that much. The code i’m showing here is almost 90% of the demo application, so it can be run on application server. I’m not just showing the upload/download part.
      Off course to make it completely run, especially using spring, we need to do few configuration.

      This code is base on my experience on finding how to download/upload files using spring. Everybody has their on way. Bassicaly i will use this technique everytime i need this, until i find more simple way or reusable component to do this.

      Thanks,

  3. Ur effort is appreciated…

    sorry, ur code is not working.. Can u please mail me ur entire code with dispatcher servlet & application context with web.xml… And with needy jars… mail it soon…. Asap…

  4. opooo ikii….
    chip please…

  5. superb post. this was a real lifesaver. relevant, actionable and precise. Many thanks Gardiary.

    regards,
    cyril

  6. ${counter.index + 1}
    unnecessary

    if you have varStatus=”counter” in forEach, you have:

    ${counter.index} // from 0…
    or
    ${counter.count} // from 1…

  7. Thanks a lot Gardiary. Wonderfully clear and precise.

  8. This code is nice but…. i added this code but i am getting in FilesService in the FilesForm class… is i need to add any jar files

    • I dont get what you mean. Is there any error or something?

      This demo is made using IntelliJ IDEA.

  9. Hello Gardiary,
    I am using eclipse helios and mysql 5.5
    I have loaded all the jar files

    I get the following error in this line of FileService.java

    CODE:
    List files = getJdbcTemplate().query(query, new BeanPropertyRowMapper(Files.class));

    Error:
    Type safety: The expression of type List needs unchecked conversion to conform to List

    Also, I have included the jstl api in the lib, i am still getting unknown tag at

    in the files.jsp

    Please guide me regarding these errors.

    Thank you.

  10. This example is really helpful to me, thanks a lot!

  11. can i get the full project??

  12. Thank you very much …..i found this post very useful.
    I tried a lot for this but i found from here …Thanks again……..

  13. thank you very much. this is very very useful. but in addition to this I need to refresh the table with currently uploaded file after successfully uploading with success message. please help me to do this yar. thanks a lot in advance .

  14. Thank you very much. this is very useful. but in addition to this I need to refresh the table with currently uploaded file after successfully uploading with success message. please help me to do this yar.

  15. Thnaks …very useful stuff….!!!

  16. Really very helpful…Thanks for posting…🙂

  17. Helpful Post

  18. Thanks, very helpful

  19. This is Really Helpfull Thanks

    But now i want to display the same file using spring what can i do..???

    http://www.visionsdeveloper.com

    Thanks & Regards.
    Visions Developer.

    • What it’s mean with display, display on page? If it’s files like PDF, ZIP, DOC, etc, it cannot display right? Except for images.

  20. MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
    cast exception =(

    • You download the code and got that exception? That is impossible :p

  21. Everything is very open with a verty clear explanation of the issues.
    It was definitely informative. Your website is extremely
    helpful. Many thanks for sharing!

  22. Very good tutorial ,when i am run this code Iam getting this is Error:
    for servlet [document] in context with path [/Document] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
    java.lang.NullPointerException
    at org.project.upload.web.DocumentController.upload(DocumentController.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

    in my java 30th line is
    document.setFilename(multipartFile.getOriginalFilename());
    document.setNotes(ServletRequestUtils.getStringParameter(request, “notes”));
    document.setType(multipartFile.getContentType());
    document.setFile(multipartFile.getBytes());
    (i replacced files with documents)

    could you solve this problem

    thanks

  23. Your website is extremely helpful. But I got some problem, when I did upload it run well but when I wanted to download it the file is corrupt, why this is happen? and how to solve it? Many thanks for sharing!


2 Trackbacks/Pingbacks

  1. […] Upload and Download spring mvc […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: