SpringMVC的请求数据参数化的处理机制,使得上传中小型文件变得方便、快捷。在前端页面,与传统开发模式一样,使用<input type="file" name="file"/>标签来添加文件,同时为form表单设置:enctype="multipart/form-data" 的属性,当此类型的表单被提交后,SpringMVC会对multipart类型的数据进行解析。

1、MultipartFile类

在SpringMVC中,MultipartFile类主要用来接收并转换request请求中的multipart类型的文件数据。执行Controller获得MultipartFile类型的参数后,就可以使用该参数进行文件的处理了。

MultipartFile类的常用方法:

方法名

返回值

说明

getContentType()

String

获取文件MIME类型。

getInputStream()

InputStream

获取文件流。

getName()

String

获取form表单中的文件组件的名字。

getOriginalFilename()

String

获取上传文件的原名。

getSize()

long

获取文件的大小,单位为byte。

isEmpty()

boolean

判断文件是否为空。

transferTo(File dest)

void

将数据保存到一个目标文件中。

 

2、实现文件的上传与下载

下面通过实现一个图片上传与下载的实例,来了解SpringMVC上传与下载文件的配置和操作,执行结果图如下:

spring 上传文件 单元测试 怎么写 springmvc如何实现文件上传_SpringMVC

2.1 配置multipart类型解析器

使用SpringMVC上传文件,首先需要在SpringMVC的核心配置文件springmvc.xml中配置multipart类型解析器,具体配置语句如下:

<!-- 多类型文件解析器、文件上传 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 设置上传文件的最大尺寸为1MB -->
    <property name="maxUploadSize" value="1048576"/>
</bean>

注意:在该配置中,id="multipartResolver"属性是必须加上的,并且值是固定的。如果不加该id属性,则项目在运行时会报异常。

2.2 下载依赖的jar包

使用SpringMVC上传文件,其内部实现也使用Apache开源上传软件包fileupload与io包(如下图),所以要将这两个jar包的依赖引入工程中。下载地址如下:

commons-fileupload.jar下载地址

commons-io.jar下载地址

spring 上传文件 单元测试 怎么写 springmvc如何实现文件上传_spring_02

如果使用Maven,则pom.xml文件配置如下:

<!-- 文件的上传 -->
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.4</version>
</dependency>
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.6</version>
</dependency>

2.3 编写JSP页面

创建名为FileUpload.jsp的页面,编写上传图片的前端页面代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>SpringMVC实现文件上传与下载</title>
    <meta name="author" content="pan_junbiao的博客">
    <style>
        table { border-collapse: collapse; margin-bottom: 10px}
        table,table tr th, table tr td { border:1px solid #000000; padding: 5px 10px;}
        .txtBox{padding: 3px;width: 300px;font-size: 16px;}
    </style>
</head>
<body>
<div align="center">
<form name="form1" action="${pageContext.request.contextPath}/file/uploadFile.action" method="post" enctype="multipart/form-data" onsubmit="return cheakSubmit()">
    <table>
        <caption>SpringMVC实现文件上传与下载</caption>
        <tr>
            <th>图片显示:</th>
            <td><img src="${pageContext.request.contextPath}/UploadImages/${requestScope.newFileName}" width="100px" height="100px"/></td>
        </tr>
        <tr>
            <th>上传文件:</th>
            <td><input type="file" name="file"/></td>
        </tr>
        <tr>
            <th>上传用户:</th>
            <td><input class="txtBox" type="text" name="userName" value="pan_junbiao的博客"/></td>
        </tr>
        <tr>
            <th>下载文件:</th>
            <td><a href="${pageContext.request.contextPath}/file/downloadFile.action?fileName=myImage.jpg">下载文件</a></td>
        </tr>
        <tr>
            <th>博客信息:</th>
            <td>您好,欢迎访问 pan_junbiao的博客</td>
        </tr>
        <tr>
            <th>博客地址:</th>
            <td>;
        </tr>
    </table>
    <input type="submit" value="上传"/>
    <!-- 显示执行信息 -->
    <span style="color:red"><%=request.getAttribute("message") == null ? "" : request.getAttribute("message")%></span>
</form>
</div>
</body>
<script>
    //提交校验
    function cheakSubmit()
    {
        var file = form1.file.value;
        if (file == null||file == ""){
            alert("请选择要上传的图片!");
            return false;
        }
        //如果不存在"."
        if (file.lastIndexOf('.')==-1){
            alert("路径不正确!");
            return false;
        }
        var fileExit=".jpg|.jpeg|.gif|.bmp|.png|";
        //获取文件后缀名,并转换为小写
        var suffix = file.substring(file.lastIndexOf(".")).toLowerCase();
        if(fileExit.indexOf(suffix+"|")==-1)
        {
            alert("对不起!请上传图片!");
            return false;
        }
        //校验成功
        return true;
    }
</script>
</html>

在该页面中,添加了一个包含enctype="multipart/form-data" 的属性的form表单,并且其中包含一个<input type="file" name="file"/>的文件上传标签。

2.4 编程Controller控制器

编写处理该上传与下载请求的Controller控制器类的方法。

package com.pjb.mvc.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 文件上传与下载控制器
 * @author pan_junbiao
 **/
@Controller
@RequestMapping("file")
public class FileController
{
    @Autowired
    private HttpServletRequest request;

    @Autowired
    private HttpServletResponse response;

    //目录名称
    private String _dirName = "/UploadImages/";

    /**
     * 上传文件
     */
    @RequestMapping("uploadFile")
    public String uploadFile(Model model, MultipartFile file, String userName)
    {
        try
        {
            if (file.isEmpty())
            {
                model.addAttribute("message", "请求选择要上传的文件");
                return "/FileUpload.jsp";
            }

            //上传的图片的原始名称
            String originalFilename = file.getOriginalFilename();

            //判断文件大小
            long size = file.getSize();
            if (size > 1048576)
            {
                model.addAttribute("message", "文件大于1M,不能上传");
                return "/FileUpload.jsp";
            }

            //获取文件后缀名,并转换为小写
            String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
            //只能上传图片,过滤不可上传的文件类型
            String fileExit = ".jpg|.jpeg|.gif|.bmp|.png|";
            if (fileExit.indexOf(suffix) <= -1)
            {
                model.addAttribute("message", "对不起!请上传图片");
                return "/FileUpload.jsp";
            }

            //目录路径
            String dirPath = request.getServletContext().getRealPath(_dirName);

            //判断文件目录是否存在,不存在则创建
            File dirFile = new File(dirPath);
            if (!dirFile.exists())
            {
                dirFile.mkdirs();
            }

            //新的文件名称(格式为:yyyyMMddHHmmss+随机4位数+后缀名)
            SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); //设置日期格式
            int randomNum = (int) (1000 + Math.random() * (9999 - 1000 + 1)); //随机4位数
            String newFileName = df.format(new Date()) + randomNum + suffix;

            //上传文件
            File newFile = new File(dirPath+newFileName);
            file.transferTo(newFile);

            //返回成功
            model.addAttribute("message", "文件上传成功");
            model.addAttribute("newFileName", newFileName);
            return "/FileUpload.jsp";
        }
        catch (Exception ex)
        {
            model.addAttribute("message", "文件上传失败");
            return "/FileUpload.jsp";
        }
    }

    /**
     * 下载文件
     */
    @RequestMapping("downloadFile")
    public ResponseEntity<byte[]> downloadFile(String fileName)
    {
        try
        {
            if(fileName==null || fileName.length()==0)
            {
                return null;
            }
            request.setCharacterEncoding("UTF-8");
            //目录路径
            String dirPath = request.getServletContext().getRealPath(_dirName);
            //获取文件
            File file = new File(dirPath+fileName);
            //判断文件是否存在
            if(!file.exists())
            {
                return null;
            }
            //解决文件名乱码
            String downloadFileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1");
            //读取二进制文件
            byte[] body = null;
            InputStream is = new FileInputStream(file);
            body = new byte[is.available()];
            is.read(body);
            //通知浏览器以attachment(下载方式)打开图片
            response.setHeader("Content-Disposition", "attchement;filename=" + downloadFileName);
            //application/octet-stream二进制流数据(最常见的文件下载)。
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            //文件下载的Http协议中的状态最好使用HttpStatus.OK。
            HttpStatus statusCode = HttpStatus.OK;
            ResponseEntity<byte[]> entity = new ResponseEntity<byte[]>(body, statusCode);
            return entity;
        }
        catch (Exception ex)
        {
            ex.toString();
            return null;
        }
    }
}

 

3、上传多张图片

当需要上传多张图片时,可以在页面创建多个name相同的<input type="file" name="file"/>标签,这样就可以提交多张图片。或者利用移动端HTML5的特性,一个input一次性选择多张图片。多张图片的选择方式主要以前端设计为主,不过多介绍,这里主要介绍后台的处理逻辑,因为不论前端的图片选择模式如何,后台的上传处理逻辑是相同的。在处理图片上传的Controlller方法中,在参数中使用MultipartFile类的数组来接收相同name的文件资源,代码如下:

/**
 * 上传多个文件
 */
@RequestMapping("uploadFiles")
public String uploadFiles(Model model, @RequestParam("files") MultipartFile[] files)
{
    //利用数组的方式来处理多张图片,处理过程忽略...
}

注意:假设前端文件input的name为“files”,那么Controller方法中的MultipartFile数组的前面要添加@RequestParam("files")注解,表示解析所有名为files的文件资源,将其添加至MultipartFile数组(这里MultipartFile数组的名称仅为参数名称,可以任意命名),该注解不可以省略。