SpringMVC实现文件上传和下载


一、文件上传⬆

1.1 概述

Spring MVC中实现文件上传需要导入文件上传的jar包——commons-fileupload.jar,然后在springmvc.xml中配置文件上传解析器(或者在Spring MVC配置类中配置),然后创建对应控制器方法,对上传的文件进行解析,解析需要用到MultipartFile类,该类作用于控制器方法的形参上,对应表单中文件上传的表单项

🔺回顾JavaWeb实现文件上传:在JavaWeb学习的文件上传功能中,需要先导入文件上传相关的jar包(commons-fileUpload.jar),然后使用jar包中的ServletFileUpload类判断当前提交的表单是否是多段格式,然后再调用parseRequest()方法来解析上传数据并获取到表单项集合,最后遍历集合分别对不同类型的表单项做响应处理

1.2 实现文件上传的基本步骤

  1. 导入文件上传jar包

      <!-- 文件上传jar包 -->
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.1</version>
    </dependency>
    
  2. 配置文件上传解析器:对于上传到服务器的文件信息,Spring MVC不能直接获取,需要使用文件上传解析器来获取,而使用解析器需要先对其进行配置,有两种配置方式

    ① 在springmvc.xml中配置

    <!-- 配置文件上传解析器,id值必须设置为multipartResolver -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 对文件上传解析器的某些属性赋值(可以不操作) -->
        
       	<!-- 设置编码方式 -->
        <property name="defaultEncoding" value="utf-8"/>
        <!-- 设置上传文件大小上限,单位为字节(10485760=10M)-->
        <property name="maxUploadSize" value="10485760"/>
        <property name="maxInMemorySize" value="40960"/>
    </bean>
    

    ② 在Spring MVC配置类WebConfig中配置(完全注解开发)

    /**
     * 配置文件上传解析器,解析器的bean-id(@Bean中的value属性值)必须设置为multipartResolver
     */
    @Bean("multipartResolver")
    public CommonsMultipartResolver getMultipartResolver() {
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    
        // 设置编码方法
        multipartResolver.setDefaultEncoding("utf-8");
        return multipartResolver;
    }
    
  3. 创建对应的控制器方法,方法的具体实现如下

    ① 添加MultipartFile类型的形参uploadFile以及session形参

    ❓关于MultipartFile对象

    • 在配置了文件解析器之后,当提交表单时,Spring MVC会将此时上传的文件信息封装在MultipartFile对象中,在控制器方法中就能通过该对象来获取文件的信息并将文件写到指定位置
    • MultipartFile对象作用于控制器方法形参,对应的是表单中上传文件的表单项(<input type="file">标签),相当于对应上传的文件请求参数,而通过控制器方法形参获取请求参数时,形参名需要与请求参数名保持一致,如果不一致,则需添加@RequestParm("请求参数名")注解来标识相应形参

    ② 通过MultipartFile对象获取上传的文件名(带后缀)

    // 1. 先获取上传的文件名
    String filename = uploadFile.getOriginalFilename();
    

    ③ 先通过截取字符串的方式获取文件的后缀名,再通过UUID.randomUUID()随机生成一个字符串,将该字符串与后缀名拼接后替换原来的文件名,防止文件名冲突(也可以使用时间戳)

    // 2.1 获取文件的后缀名(文件名不为null和空情况下)
    String suffixName = "";
    if (filename != null && ! "".equals(filename)) {
        // 截取字符串,获取字符串后面的后缀名
        suffixName = filename.substring(filename.lastIndexOf("."));
    }
    // 2.2 通过UUID随机生成一个字符串,与后缀名拼接替换原来的文件名,防止文件名冲突
    filename = UUID.randomUUID().toString().replace("-", "") + suffixName;
    

    ④ 通过session形参对象获取servletContext对象,然后通过servletContext对象调用getRealPath("/photo")方法获取工程下的photo目录路径dirPath

    // 3. 通过session获取servletContext对象,并获取工程下的photo目录的路径
    String dirPath = session.getServletContext().getRealPath("/photo");
    

    ❓关于getRealPath()获取的路径:servletContextgetRealPath()方法获取的是当前工程下的文件路径或目录路径,当前工程下是指工程的输出目录,而部署到tomcat服务器的Web工程输出目录默认为target目录下的名字与上下文路径(Application context)一样的目录,在idea的Project Structure中可以修改工程的输出目录。我当前Web工程名为SpringMVCLearn,上下文路径也是SpringMVCLearn,所以我这里通过getRealPath("/photo")获取的完整路径应该为【D:/ideaProject/practice_ssm/SpringMVCLearn/target/SpringMVCLearn/photo】


    out目录🆚target目录(参考博文:intellj idea中target目录和out目录的区别

    • out目录存放的是该项目下所有Module(模块),即整个工程的编译结果(打包文件),在idea的Project Structure的Project中可以查看和修改

    • target目录存放的是单个Module的编译结果,在idea的Project Structure的Modules中可以查看和修改

    • 在Modules中可以设置每个module的编译输出路径,如果指定了某个mudule的编译输出路径,一般输出到target目录,则不会再输出到out目录中

    ⑤ 创建dirPath对应的File对象,再根据File对象判断该目录是否存在,如果不存在就在对应位置创建photo目录

    // 4. 根据获取的photo目录路径创建File对象,再判断该目录是否存在,如果不存在就创建
    File file = new File(dirPath);
    if (! file.exists()) {
        // 如果不存在就创建对应目录
        file.mkdir();
    }
    

    ⑥ 创建文件上传的最终路径finalPath,通过File.separator设置文件之间的分隔符,然后再创建对应的File对象

    // 5.1 设置文件上传的位置
    String finalPath = dirPath + File.separator + filename;
    // 5.2 根据上传路径创建出对应的File对象
    File finalPathFile = new File(finalPath);
    

    PS:这里演示的是动态设置文件上传的路径,也可以设置固定的上传路径,设置固定的上传路径就无需进行④⑤⑥三步操作,直接创建上传路径对应的File对象即可

    ⑦ 调用MultipartFile对象的transferTo()方法,将文件上传的最终路径对应的File对象传入即可

    // 6. 调用MultipartFile对象的transferTo()方法,将上传的文件写到对应的位置
    uploadFile.transferTo(finalPathFile);
    

    ❓关于配置文件解析器的注意事项

    • 文件解析器的bean-id值必须设置为multipartResolver(bean-id --> <bean>中的id值或@Bean标签中的value属性值)
    • 如果配置时不设置id值,或者id值设置为其他值,Spring MVC就找不到配置的文件解析器,也就无法为其创建对象,也不会为控制器方法中添加的MultipartFile类型的形参赋值,因此在控制器方法中使用的MultipartFile对象就是个null,此时在前端页面点击提交表单,页面就会报500错误,因为在控制器方法中解析上传文件数据需要调用MultipartFile对象的方法,而此时该对象为null,所以服务器会报空指针错误
    • 如果采用第二种方式,即在配置类中配置文件上传解析器,则@Bean注解中可以不添加value属性,但此时@Bean所标识的方法名必须为multipartFile,因为不设置value属性值时,@Bean注解会默认将方法名作为value属性值
    • MultipartResolver接口才是真正的文件上传解析器,但它是一个接口,一般不直接通过接口创建对象,而是使用其实现类来创建,因此配置文件上传解析器时,采用其实现类CommonsMultipartResolver来创建文件上传解析器对象

1.3 完整代码

 @RequestMapping("/fileUpload")
    public String fileUpload(MultipartFile uploadFile, HttpSession session) throws IOException {
        // 1. 先获取上传的文件名
        String filename = uploadFile.getOriginalFilename();
        System.out.println("上传文件名 --> " + filename);
    
        // 2.1 获取文件的后缀名(文件名不为null和空情况下)
        String suffixName = "";
        if (filename != null && ! "".equals(filename)) {
            // 截取字符串,获取字符串后面的后缀名
            suffixName = filename.substring(filename.lastIndexOf("."));
        }
        // 2.2 通过UUID随机生成一个字符串,与后缀名拼接替换原来的文件名,防止文件名冲突
        filename = UUID.randomUUID().toString().replace("-", "") + suffixName;
    
        // 3. 通过session获取servletContext对象,并获取工程下的photo目录的路径
        String dirPath = session.getServletContext().getRealPath("/photo");
    
        // 4. 根据获取的photo目录路径创建File对象,再判断该目录是否存在,如果不存在就创建
        File file = new File(dirPath);
        if (! file.exists()) {
            // 如果不存在就创建对应目录
            file.mkdir();
        }
    
        // 5.1 设置文件上传的位置
        String finalPath = dirPath + File.separator + filename;
    
        // 设置固定的上传路径
        //        String finalPath =
        //                "D:\\ideaProject\\practice_ssm\\SpringMVCLearn\\src\\main\\webapp\\static\\image\\" +
        //                        filename;
    
        // 5.2 根据上传路径创建出对应的File对象
        File finalPathFile = new File(finalPath);
    
        // 6. 调用MultipartFile对象的transferTo()方法,将上传的文件写到对应的位置
        uploadFile.transferTo(finalPathFile);
    
        return "success";
    }

二、文件下载⬇

2.1 概述

Spring MVC中可以直接在控制器方法中使用ResponseEntity对象来设置响应报文信息,而且创建ResponseEntity对象时直接传入文件字节数据(响应体信息)和响应头对象,然后将ResponseEntity对象返回即可,无需创建输出流和手动设置响应体的MIME类型

🔺回顾JavaWeb实现文件下载:在JavaWeb实现的文件下载功能中,采用的是原生servletAPI,即在Servlet的doPost()方法中使用resp对象获取并设置响应报文信息,在Spring MVC中当然也可以在控制器方法中添加resp对象,然后通过resp设置响应信息,用法与servletAPI中一样

2.2 实现文件下载的基本步骤

(在控制器方法中实现)

  1. 获取文件名请求参数:在控制器方法中添加文件名请求参数对应的形参filename

  2. 获取servletContext对象,并通过该servletContext对象获取要下载的文件资源并转化为输入流:在控制器方法中添加session对象,通过session对象获取servletContext对象,然后通过servletContext对象调用getResourceAsStream("文件路径")方法将获取文件并转换为流

    // 2.1 获取servletContext对象
    ServletContext servletContext = session.getServletContext();
    // 2.2 通过servletContext对象获取文件资源并转化为输入流
    InputStream fileIn = servletContext.getResourceAsStream("/static/image/code.png");
    
  3. 创建字节数组,并将文件输入流读取到字节数组中:字节数组的长度设置为fileIn.available(),表示输入流的全部字节数,通过输入流的read()方法将流读取到数组中

    // 3. 创建字节数据,并将文件流读取字节数据中(fileIn.available()为输入流的全部字节数)
    byte[] bytes = new byte[fileIn.available()];
    fileIn.read(bytes);
    
  4. 创建响应头对象,并通过响应头对象设置响应头信息:创建MultiValueMap<String, String>类型的响应头对象headers,然后调用其add()方法以键值对的形式设置响应头Content-Dispositionattachment;filename=文件名;除了文件名可变,其他形式固定,且必须设置

    // 4.1 创建请求头对象
    MultiValueMap<String, String> headers = new HttpHeaders();
    // 4.1 通过请求头设置请求头信息
    headers.add("Content-Disposition", "attachment;filename=" +
                URLEncoder.encode(filename, "utf-8"));
    
  5. 创建响应状态码,并设置状态为OK

    // 5. 创建响应状态码对象并设置响应状态为OK
    HttpStatus status = HttpStatus.OK;
    
  6. 创建ResponseEntity对象,泛型设置为<byte[]>(控制器方法的返回值的泛型也一样),然后传入字节数组、响应头对象和响应状态码对象,最后关闭文件输入流的资源(别忘了!)

    // 6. 创建responseEntity对象,并传入文件字节数据(响应体信息)、响应头对象、响应状态码对象
    ResponseEntity<byte[]> respEntity = new ResponseEntity<>(bytes, headers, status);
    
    // 7. 关闭资源
    fileIn.close();
    
  7. 返回ResponseEntity对象

2.3 完整代码

@RequestMapping("/fileDownload")
   public ResponseEntity<byte[]> fileDownload(String filename, HttpSession session) throws IOException {
       // 1. 获取请求参数——文件名filename
       System.out.println("文件名 -->" + filename);
   
       // 2.1 获取servletContext对象
       ServletContext servletContext = session.getServletContext();
       // 2.2 通过servletContext对象获取文件资源并转化为输入流
       InputStream fileIn = servletContext.getResourceAsStream("/static/image/code.png");
   
       // 3. 创建字节数据,并将文件流读取字节数据中(fileIn.available()为输入流的全部字节数)
       byte[] bytes = new byte[fileIn.available()];
       fileIn.read(bytes);
   
       // 4.1 创建请求头对象
       MultiValueMap<String, String> headers = new HttpHeaders();
       // 4.1 通过请求头设置请求头信息
       headers.add("Content-Disposition", "attachment;filename=" +
                   URLEncoder.encode(filename, "utf-8"));
   
       // 5. 创建响应状态码对象并设置响应状态为OK
       HttpStatus status = HttpStatus.OK;
   
       // 6. 创建responseEntity对象,并传入文件字节数据(响应体信息)、响应头对象、响应状态码对象
       ResponseEntity<byte[]> respEntity = new ResponseEntity<>(bytes, headers, status);
   
       // 7. 关闭资源
       fileIn.close();
   
       System.out.println("文件下载成功!");
   
       return respEntity;
   }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现Spring MVC的文件上传下载功能,需要进行以下步骤: 1、引入Apache Commons FileUpload组件的依赖。在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> ``` 2、配置文件上传解析器。在Spring MVC的配置文件中,配置一个MultipartResolver的Bean用于处理文件上传请求。 3、创建文件上传的表单。在HTML表单中,设置enctype为"multipart/form-data",并添加一个文件选择框。 4、创建文件上传的控制器。在控制器中,使用MultipartFile参数接收上传的文件,并执行相应的操作,比如保存文件到指定位置。 5、创建文件下载的控制器。在控制器中,使用ResponseEntity<byte[]>对象来实现文件的下载,设置相应的响应头信息,如Content-Disposition和文件名。 下面是一个示例的代码,演示了如何实现文件上传下载: ``` // 文件上传的控制器 @Controller public class FileUploadController { @RequestMapping("/fileUpload") public String testFileUpload(MultipartFile photo, HttpSession session) throws IOException { String filename = photo.getOriginalFilename(); ServletContext servletContext = session.getServletContext(); String realPath = servletContext.getRealPath("photo"); File file = new File(realPath); if (!file.exists()) { file.mkdir(); } String finalPath = realPath + File.separator + filename; photo.transferTo(new File(finalPath)); return "success"; } } // 文件下载的控制器 @Controller public class FileDownloadController { @RequestMapping("/fileDownload") public ResponseEntity<byte[]> testFileDownload(HttpSession session) throws IOException { ServletContext servletContext = session.getServletContext(); String realPath = servletContext.getRealPath("static/img/a.jpg"); InputStream inputStream = new FileInputStream(realPath); byte[] bytes = new byte[inputStream.available()]; inputStream.read(bytes); MultiValueMap<String, String> headers = new HttpHeaders(); headers.add("Content-Disposition", "attachment;filename=a.jpg"); HttpStatus status = HttpStatus.OK; ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, status); inputStream.close(); return responseEntity; } } // 文件上传的表单 <form action="${pageContext.request.contextPath}/fileUpload" method="post" enctype="multipart/form-data"> <input type="file" name="photo" multiple> <input type="submit" value="上传"/> </form> ``` 通过以上步骤,你可以在Spring MVC中实现文件的上传和下载功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值