Skip navigation

Tag Archives: File Download

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.