SpringMVC:七、文件上传下载

11、文件上传和下载

11.1、文件上传

回顾Java Web文件上传

  1. 浏览器处理上传文件,将文件以的形式提交到服务器端

    • commons-fileuploadApache 的文件上传组件,取代原生的文件上传流。
    • commons-iocommons-fileupload 组件依赖于该组件。
  2. 前端表单

    • 提交方式method=“post”
    • 编码类型enctype="multipart/form-data"

SpringMVC 文件上传

  • 提供了更简单的封装
  • 提供了即插即用的支持,通过 MultipartResolver 实现:
    • 需要 Apachecommons-fileupload组件支持;
    • 实现类CommonsMultipartResolver

11.1.1、实用类

  1. 服务器端收到请求时,DispatcherServletcheckMultipart()方法会调用 MultipartResolverisMultiPart()方法来判断请求中是否包含文件上传控件
  2. 如果请求数据中包含文件,调用 MultipartResolverresolveMultipart()方法来解析请求数据,将文件数据解析成 MultipartFile 并封装在 MultipartHttpServletRequest 对象中,再传递给 Controller
  3. MultipartFile 封装了请求数据中的文件,此时这个文件存储在内存中或临时的磁盘文件中,需要将其转存到一个合适的位置,因为请求结束后临时存储将被清空。

MultipartResolver

  • 类似原来的 ServletFileUpload
    • isMultipart()ServletFileUpload 类的isMultipartContent()
    • resolveMultipart()ServletFileUpload 类的parseRequest()
    • cleanupMultipart()DiskFileItem 类的delete()
// 判断请求是否包含文件上传控件
boolean isMultipart(HttpServletRequest request); 
// 解析请求
MultipartHttpServletRequest resolveMultipart(HttpServletRequest request); 
// 清除主题内容
void cleanupMultipart(MultipartHttpServletRequest request);

MultipartFile

类似原来的 FileItem

  • getName ():
  • getOriginalFilename ():
  • getContentType ():
// 获取参数的名称
String getName(); 
// 获取上传文件名
String getOriginalFilename(); 
// 获取文件内容的类型
String getContentType(); 
// 判断文件是否为空
boolean isEmpty();
// 获取文件大小
long getSize();
// 将文件内容以字节数组的形式返回
byte[] getBytes();
// 获取文件输入流:将文件内容以输入流的形式返回
InputStream getInputStream(); 
// 将上传文件内容保存到指定目录文件中
void transferTo(File dest); 

11.1.2、环境搭建

  1. 导入 commons-fileupload 的依赖,Maven 会自动导入它的依赖包 commons-io

    <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.4</version>
    </dependency>
    
  2. 新建 module,添加 web 框架支持:在项目结构中手动添加 lib 目录

  3. web.xml

    • DispatcherServlet
    • 字符编码过滤器
  4. applicationContext.xml

    • 添加注解支持
    • 静态资源过滤
    • 添加注解驱动
    • 视图解析器
  5. 配置 beanMultipartResolver

    • id 必须为 multipartResolver
    <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
          id="multipartResolver">
        <!-- 请求的编码格式,需与JSP的页面编码格式相同 -->
        <property name="defaultEncoding" value="utf-8"/>
        <!-- 上传文件大小的最大值,单位为byte -->
        <property name="maxUploadSize" value="10485760"/>
        <!-- 缓存文件的最大值,单位为byte -->
        <property name="maxInMemorySize" value="40960"/>
    </bean>
    

11.1.3、编写代码

Controller

  • 获取上传文件名
  • 设置上传文件的保存路径
  • 文件传输

使用 IO 流传输

  • 获取文件输入流
  • 获取文件输出流
  • 读取写出文件
@Controller
@RequestMapping("/file")
public class FileController {

    /**
     * @param file 封装了请求数据中的文件,如果有多个则声明为数组
     */
    @RequestMapping("/upload1")
    public String fileUpload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {

        // 获取上传文件名
        String originalFilename = file.getOriginalFilename();
        System.out.println("上传文件名 : " + originalFilename);

        // 如果没有上传文件,直接返回首页
        if ("".equals(originalFilename)) {
            return "redirect:/index.jsp";
        }

        // 设置上传文件保存路径
        String path = request.getServletContext().getRealPath("/upload");
        // 如果路径不存在,创建一个
        File realPath = new File(path);
        if (!realPath.exists()) {
            realPath.mkdir();
        }
        System.out.println("上传文件保存地址:" + realPath);

        // 文件传输
        // 获取文件输入流
        InputStream is = file.getInputStream();
        // 文件输出流
        OutputStream os = new FileOutputStream(new File(realPath, originalFilename));

        // 读取写出
        int len = 0;
        byte[] buffer = new byte[1024];
        while ((len = is.read(buffer)) != -1) {
            os.write(buffer, 0, len);
            os.flush();
        }
        os.close();
        is.close();

        return "success";
    }
}

使用 TransferTo 方法

除了使用流,还可以使用 MultipartFile 类的 TransferTo 方法来读取写出文件。

/**
 * @param file 封装了请求数据中的文件,如果有多个则声明为数组
 */
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {

    // 获取上传文件名
    String originalFilename = file.getOriginalFilename();
    System.out.println("上传文件名 : " + originalFilename);

    // 如果没有上传文件,直接返回首页
    if ("".equals(originalFilename)) {
        return "redirect:/index.jsp";
    }

    // 设置上传文件保存路径
    String path = request.getServletContext().getRealPath("/upload");
    // 如果路径不存在,创建一个
    File realPath = new File(path);
    if (!realPath.exists()) {
        realPath.mkdir();
    }
    System.out.println("上传文件保存地址:" + realPath);

    // 文件传输
    file.transferTo(new File(realPath + "/" + originalFilename));

    return "success";
}

相比原生的 Servlet 实现文件上传,省去了以下的手动操作:

  • 判断表单是否包含文件上传控件;
  • 创建临时文件的保存路径;
  • 创建 DiskFileItemFactoryServletFileUpload 对象;
  • 解析请求。

前端页面

<form action="${pageContext.request.contextPath}/file/upload1"
      enctype="multipart/form-data" method="post">
    <input type="file" name="file"><br>
    <input type="submit">
</form>

<form action="${pageContext.request.contextPath}/file/upload2"
      enctype="multipart/form-data" method="post">
    <input type="file" name="file"><br>
    <input type="submit">
</form>

SpringMVC:七、文件上传下载

上一篇:数据格式-JSON


下一篇:微信公众号开发系列-启用开发模式