springmvc文件上传下载

在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下Spring中的文件上传和下载功能的实现,文件上传必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器。 一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。 
Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。而Spring MVC则提供了更简单的封装。 
Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件,common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。 

一、pom.xml

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

二、springmvc.xml中配置MultipartFile解析器

SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。在springmvc-config.xml进行配置文件如下

<!-- 配置文件上传 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="UTF-8"></property>
    <!-- 设置最大上传文件为5M -->
    <property name="maxUploadSize">
        <value>10510925824  </value>
    </property>
</bean>

三、创建一个FileUploadController类

Spring MVC会将上传的文件绑定到MultipartFile对象中。MultipartFile提供了获取上传文件内容、文件名等方法。通过transferTo()方法还可以将文件存储到硬件中,MultipartFile对象中的常用方法如下:

byte[] getBytes():获取文件数据
String getContentType[]:获取文件MIME类型,如image/jpeg等
InputStream getInputStream():获取文件流
String getName():获取表单中文件组件的名字
String getOriginalFilename():获取上传文件的原名
Long getSize():获取文件的字节大小,单位为byte
boolean isEmpty():是否有上传文件
void transferTo(File dest):将上传文件保存到一个目录文件中

 

文件上传的细节

       1、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。

  2、为提高io性能,上传文件夹以年月日创建

    3、要限制上传文件的最大值。

    4、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。

      5、页面必须设置enctype="multipart/form-data"  提交方式为POST

 

package com.htf.controller;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;


@Controller
public class FileUploadController {

    private final static Logger logger = LoggerFactory.getLogger(FileUploadController.class);
    private Map resultMap = new HashMap<>();


    @RequestMapping("/Upload.do")
    public String uploadFiles(@RequestParam("file") MultipartFile[] files, HttpServletRequest request,
                              HttpServletResponse response, Model mv) throws IOException {
        Long startTime = System.currentTimeMillis();
        String rootPath = "D:\\Software\\upload";
        if (files != null && files.length > 0) {

            try {
                for (MultipartFile mu : files) {
                    if (!mu.isEmpty()) {
                        // String rootPath=request.getSession().getServletContext().getRealPath("/upload");
                        // 原始名称
                        String originalFileName = mu.getOriginalFilename();
                        // 新文件名
                        String qb = UUID.randomUUID() + "";
                        qb = qb.substring(0, 5);
                        String newFileName = originalFileName.substring(0, originalFileName.lastIndexOf(".")) + "_" + qb
                                + originalFileName.substring(originalFileName.lastIndexOf("."));
                        // list.add(newFileName);
                        // 创建年月文件夹
                        Calendar date = Calendar.getInstance();
                        File dateDirs = new File(date.get(Calendar.YEAR) + File.separator
                                + (date.get(Calendar.MONTH) + 1) + File.separator + date.get(Calendar.DAY_OF_MONTH));
                        // 新文件
                        File newFile = new File(rootPath + File.separator + dateDirs + File.separator + newFileName);

                        // 判断目标文件所在目录是否存在
                        if (!newFile.getParentFile().exists()) {
                        // 如果目标文件所在的目录不存在,则创建父目录
                            newFile.getParentFile().mkdirs();
                        }

                        // MultipartFile自带的解析方法
                        mu.transferTo(newFile);
                    }
                }
            } catch (IllegalStateException e) {

                e.printStackTrace();
            }
        }
        Map mapTmp = new HashMap();
        mapTmp = readFile(rootPath);
        // List list = new ArrayList<>();
        // for (Object key : mapTmp.keySet()) {
        // list.add(key);
        // }
        mv.addAttribute("message", mapTmp);
        Long endTime = System.currentTimeMillis();
        System.out.println("程序运行时间:" + (endTime - startTime) + "ms");
        return "message";

    }


    @RequestMapping("/down.do")
    public String down(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
        try {
          // String path =request.getSession().getServletContext().getRealPath("/upload");

            String path = "D:\\Software\\upload";
            Map fileMap = readFile(path);
            String name = request.getParameter("name");
            File fileEnd = (File) fileMap.get(name);
            response.addHeader("content-disposition", "attachment;filename=" + name);

            ServletOutputStream out = response.getOutputStream();
            FileUtils.copyFile(fileEnd, out);
            out.flush();
            out.close();
            // return null: 解决getOutputStream() has already been called for this response,
            return null;

        } catch (Exception e) {
            e.printStackTrace();
        }
        model.addAttribute("msg", "下载成功!!!");
        return "message";
    }

    private Map readFile(String path) {
        File file = new File(path);
        if (file.exists()) {
            File[] files = file.listFiles();
            if (null == files || files.length == 0) {
                System.out.println("文件夹是空的!");
            } else {
                for (File file2 : files) {
                    if (file2.isDirectory()) {
                        System.out.println("文件夹:" + file2.getAbsolutePath());
                        readFile(file2.getAbsolutePath());

                    } else {
                        this.resultMap.put(file2.getName(), file2);
                    }
                }
            }
        } else {
            System.out.println("文件不存在!");
        }

        return this.resultMap;
    }
}

四、文件上传页面

在页面form表单中提交数据时,必须设置enctype="multipart/form-data" ,提交方式post

<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/Upload.do" method="post" enctype="multipart/form-data">

    上传文件1:<input type="file" name="file"> <br/>
    上传文件2:<input type="file" name="file"><br/>
    上传文件3:<input type="file" name="file"><br/>
    上传文件4:<input type="file" name="file"><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>

五、文件下载页面
<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1><a href="jsp/upload.jsp">上传</a></h1>
    <c:forEach var="file" items="${message}">
        ${file.key} <a href="down.do?name=${file.key}">文件下载</a><br/>
    </c:forEach>

</body>
</html>

六、效果如图所示

上传成功

文件夹是以年月日创建的,提高io性能

 

下载