SpringMVC 学习笔记 Part5

1. 文件上传的原理

本小节将回顾 JavaWeb 传统的文件上传方式和学习更为方便的 SpringMVC 提供的文件上传组件。首先先来回顾一下文件上传的一些前置知识。

  1. form 表单的 enctype 取值必须是:multipart/form-data (默认值是:application/x-www-form-urlencoded) ,enctype 是表单请求正文的类型,multipart属性表示请求正文将被分成好几个部分。
  2. form 表单的 method 属性取值必须是 Post 。
  3. form 表单中需提供一个文件选择域< input type=“file” />
<form action="user/fileupload" method="post" enctype="multipart/form-data"> 
    选择文件:<input type="file" name="upload"/><br/> 
    <input type="submit" value="上传文件"/> 
</form>

注:当 form 表单的 enctype 取值不是默认值后,request.getParameter()将失效。

当 form 表单的 enctype 取值为 ”application/x-www-form-urlencoded” 时,form 表单的正文内容是:key=value&key=value&key=value 。

当 form 表单的 enctype 取值为 “Mutilpart/form-data” 时,请求正文内容就变成每一部分都是 MIME 类型描述的正文:分解符、协议头、协议的正文以及协议的类型(MIME类型)。

2. 传统的文件上传

首先先导入文件上传相关的坐标。

<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>

编写文件上传的控制器方法。

@RequestMapping(value="/myUpload")
public String myUpload(HttpServletRequest request) throws Exception { 
    // 先获取到要上传的文件目录 
    String path = request.getSession().getServletContext().getRealPath("/uploads"); 
    // 创建File对象,一会向该路径下上传文件 
    File file = new File(path); 
    // 判断路径是否存在,如果不存在,创建该路径 
    if(!file.exists()) {
        file.mkdirs(); 
    }
    
    // 创建磁盘文件项工厂,再使用工厂创建文件上传解析器
    DiskFileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload fileUpload = new ServletFileUpload(factory); 
    // 解析request对象,得到了文件项的集合
    List<FileItem> items = fileUpload.parseRequest(request); 
    
    // 遍历 
    for (FileItem item : items) { 
        // 判断文件项是普通字段,还是上传的文件 
        if(item.isFormField()) { 
            //说明是普通表单项
        }else { 
            // 说明是上传文件项
            // 获取到上传文件的名称 
            String filename = item.getName();
            // 把文件的名称唯一化 
            String uuid = UUID.randomUUID().toString().replaceAll("-", ""); 
            filename = uuid+"_"+filename;
            // 上传文件 
            item.write(new File(file, filename)); 
            // 删除临时文件(当不超过10kb时,上传完服务器会自动清除。而当超过10kb时,上传完文件将会有临时文件,需要自行清除)
            item.delete(); 
        } 
    }
    return "success"; 
}

3. SpringMVC框架的文件上传

首先简述一下SpringMVC框架的文件上传的基本原理:首先需要有一个框架为我们提供的 MultipartFile 类对象。当我们点击 submit 提交后,request 将会被发送到前端控制器中,前端控制器将 request 送入配置文件解析器进行解析,解析完成会返回一个 upload文件上传项 给前端控制器,前端控制器再把这个 upload 送到 Controller 里我们编写的方法里。

MultipartFile 类对象如何创建也非常简单。第一步先在 xml 里配置创建进 IoC 容器里,其次只要加入我们编写文件上传的控制器方法中的形参里就好啦。

第一步:创建CommonsMultipartResolver进IoC容器。

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="10485760"/>
</bean>

注意此处CommonsMultipartResolver的bean创建,id属性值必须为multipartResolver,为其他的将会造成HTTP 500错误。

第二步:编写文件上传的控制器方法中加入MultipartFile的形参,并编写文件上传代码。

@RequestMapping("myUpload")
public String myUpload(HttpServletRequest request,MultipartFile upload) throws Exception {
    // 先获取到要上传的文件目录
    String path = request.getSession().getServletContext().getRealPath("/uploads");
    // 创建File对象,一会向该路径下上传文件
    File file = new File(path);
    // 判断路径是否存在,如果不存在,创建该路径
    if (!file.exists()) {
        file.mkdirs();
    }

    // upload是被springmvc解析完成的,是可以直接使用的上传文件项
    // 改动1.获取到上传文件的名称
    String filename = upload.getOriginalFilename();
    // 把文件的名称唯一化
    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
    filename = uuid + "_" + filename;
    // 改动2.完成文件上传
    upload.transferTo(new File(path,filename));

    return "success";
}

与传统的文件上传方式相比,共简化了两处代码,也省去了遍历操作。