首页 > 编程笔记

Spring MVC文件上传

Spring MVC 框架的文件上传基于 commons-fileupload 组件,并在该组件上做了进一步的封装,简化了文件上传的代码实现,取消了不同上传组件上的编程差异。

MultipartResolver接口

在 Spring MVC 中实现文件上传十分容易,它为文件上传提供了直接支持,即 MultpartiResolver 接口。MultipartResolver 用于处理上传请求,将上传请求包装成可以直接获取文件的数据,从而方便操作。

MultpartiResolver 接口有以下两个实现类:

MultpartiResolver 接口具有以下方法。

名称 作用
byte[] getBytes() 以字节数组的形式返回文件的内容
String getContentType() 返回文件的内容类型
InputStream getInputStream() 返回一个InputStream,从中读取文件的内容
String getName() 返回请求参数的名称
String getOriginalFillename() 返回客户端提交的原始文件名称
long getSize() 返回文件的大小,单位为字节
boolean isEmpty() 判断被上传文件是否为空
void transferTo(File destination) 将上传文件保存到目标目录下

下面我们使用 CommonsMultipartResolver 来完成文件上传,分为单文件上传和多文件上传两部分介绍。

单文件上传

1. 导入 jar 文件

文件上传使用 Apache Commons FileUpload 组件,需要导入 commons-io-2.4.jar 和 commons-fileupload-1.2.2.jar 两个 jar 文件(可在 Apache 官网下载)。

Maven 项目在 pom.xml 文件中添加以下依赖。
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.2.2</version>
</dependency>

2. 配置 MultipartResolver

使用 CommonsMultipartReslover 配置 MultipartResolver 解析器,在 springmvc-servlet.xml 中添加代码如下。
<!-- 配置MultipartResolver,用于上传文件,使用spring的CommonsMultipartResolver -->
<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="5000000" />
    <property name="defaultEncoding" value="UTF-8" />
</bean>

3. 编写文件上传表单页面

负责文件上传表单的编码类型必须是“multipart/form-data”类型。

fleUpload.jsp 代码如下。
<%@ page language="java" 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">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上传</title>
</head>
<body>
    <form action="${pageContext.request.contextPath }/fileupload"
        method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="myfile"><br> 
        文件描述:<input type="text" name="description"><br> 
        <input type="submit" value="提交">
    </form>
</body>
</html>
基于表单的文件上传需要使用 enctype 属性,并将它的值设置为 multipart/form-data,同时将表单的提交方式设置为 post。

表单的 enctype 属性指定的是表单数据的编码方式,该属性有以下 3 个值。
由上面 3 个属性的解释可知,在基于表单上传文件时 enctype 的属性值应为 multipart/form-data。

4. 创建POJO类

创建 net.biancheng.opjo 包,在该包下创建 FileDomain 类,在该 POJO 类中声明一个 MultipartFile 类型的属性封装被上传的文件信息,属性名与文件选择页面 filleUpload.jsp 中的 file 类型的表单参数名 myfile 相同,代码如下。
package net.biancheng.po;

import org.springframework.web.multipart.MultipartFile;

public class FileDomain {
    private String description;
    private MultipartFile myfile;

    /** 省略setter和getter参数*/
}

5. 编写控制器

创建 net.biancheng.controller 包,在该包下创建 FileUploadController 控制类,具体代码如下。
package net.biancheng.controller;

import java.io.File;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import net.biancheng.po.FileDomain;

@Controller
public class FileUploadController {
    // 得到一个用来记录日志的对象,这样在打印信息时能够标记打印的是哪个类的信息
    private static final Log logger = LogFactory.getLog(FileUploadController.class);

    @RequestMapping("getFileUpload")
    public String getFileUpload() {
        return "fileUpload";
    }

    /**
     * 单文件上传
     */
    @RequestMapping("/fileupload")
    public String oneFileUpload(@ModelAttribute FileDomain fileDomain, HttpServletRequest request) {
        /*
         * 文件上传到服务器的位置“/uploadfiles”,该位置是指 workspace\.metadata\.plugins\org.eclipse
         * .wst.server.core\tmp0\wtpwebapps, 发布后使用
         */
        String realpath = request.getServletContext().getRealPath("uploadfiles");
        String fileName = fileDomain.getMyfile().getOriginalFilename();
        File targetFile = new File(realpath, fileName);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        }
        // 上传
        try {
            fileDomain.getMyfile().transferTo(targetFile);
            logger.info("成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "showFile";
    }
}

6. 创建成功显示页面

showFile.jsp 代码如下。
<%@ page language="java" 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">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上传</title>
</head>
<body>
    文件描述:${fileDomain.description }
    <br>
    <!-- fileDomain.getMyFile().getOriginalFilename()-->
    文件名称:${fileDomain.myfile.originalFilename }
</body>
</html>

7. 测试文件上传

访问地址:http://localhost:8080/springmvcDemo2/getFileUpload,运行结果如下。

fileUpload.jsp页面
fileUpload.jsp 页面

showFile.jsp页面
showFile.jsp 页面

多文件上传

在以上代码的基础上,实现 Spring MVC 多文件上传。

1. 创建 JSP 页面

创建 multiFiles.jsp 页面,在该页面中使用表单上传多个文件。代码如下。
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="fm" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>多文件上传</title>
</head>
<body>
    <form action="${pageContext.request.contextPath }/multifile"
        method="post" enctype="multipart/form-data">
        选择文件1:<input type="file" name="myfile"><br>
        文件描述1:<input type="text" name="description"><br>
        选择文件2:<input type="file" name="myfile"><br>
        文件描述2:<input type="text" name="description"><br>
        选择文件3:<input type="file" name="myfile"><br>
        文件描述3:<input type="text" name="description"><br>
            <input type="submit" value="提交">
    </form>
</body>
</html>

2. 创建POJO类

创建 MultiFileDomain 类,上传多文件时用于封装文件信息,代码如下。
package net.biancheng.po;

import java.util.List;
import org.springframework.web.multipart.MultipartFile;

public class MultiFileDomain {
    private List<String> description;
    private List<MultipartFile> myfile;

    public List<String> getDescription() {
        return description;
    }

    public void setDescription(List<String> description) {
        this.description = description;
    }

    public List<MultipartFile> getMyfile() {
        return myfile;
    }

    public void setMyfile(List<MultipartFile> myfile) {
        this.myfile = myfile;
    }

}

3. 添加多文件上传处理方法

在 FileUploadController 控制器类中添加多文件上传处理方法 multifile,具体代码如下。
@RequestMapping("/getmultiFile")
public String getmultiFile() {
    return "multiFiles";
}

/**
* 多文件上传
*/
@RequestMapping("/multifile")
public String multiFileUpload(@ModelAttribute MultiFileDomain multiFileDomain, HttpServletRequest request) {
    String realpath = request.getServletContext().getRealPath("uploadfiles");
    File targetDir = new File(realpath);
    if (!targetDir.exists()) {
        targetDir.mkdirs();
    }
    List<MultipartFile> files = multiFileDomain.getMyfile();
    System.out.println("files"+files);
    for (int i = 0; i < files.size(); i++) {
        MultipartFile file = files.get(i);
        String fileName = file.getOriginalFilename();
        File targetFile = new File(realpath, fileName);
        // 上传
        try {
            file.transferTo(targetFile);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return "showMulti";
}

4. 创建成功显示页面

创建多文件上传成功显示页面 showMulti.jsp,具体代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>多文件上传显示</title>
</head>
<body>

    <table border="1px">
        <tr>
            <td>详情</td>
            <td>文件名</td>
        </tr>
        <!-- 同时取两个数组的元素 -->
        <c:forEach items="${multiFileDomain.description}" var="description"
            varStatus="loop">
            <tr>
                <td>${description}</td>
                <td>${multiFileDomain.myfile[loop.count-1].originalFilename}</td>
            </tr>
        </c:forEach>
        <!-- fileDomain.getMyfile().getOriginalFilename() -->
    </table>
</body>
</html>

5. 测试文件上传

访问地址:http://localhost:8080/springmvcDemo2/getmultiFile,运行结果如下。

multiFiles.jsp页面
multiFiles.jsp页面
 
showMulti.jsp页面
showMulti.jsp页面

推荐阅读