欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringBoot实现文件上传和下载

程序员文章站 2022-03-11 20:07:23
...

文件上传需要使用到 MultipartResolver接口

Spring MVC 使用 MultipartResolver接口的实现类:CommonsMultipartResolver 。CommonsMultipartResolver类是基于Apache Commons FileUpload技术实现的。 所以,SpringMVC的文件上传需要依赖Apache Commons FileUpload的组件。传送门:SpringMVC实现文件上传和下载

SpringBoot 默认使用 MultipartResolver接口的实现类:StandardServletMultipartResolver。默认配置了单文件大小限制等。所以,不需要依赖Apache Commons FileUpload的组件,即可直接使用。

SpringBoot实现文件上传和下载

    @Bean
    public MultipartResolver multipartResolver() {
        // 默认配不配都行,如果使用CommonsMultipartResolver,注入就行
//        StandardServletMultipartResolver resolver = new StandardServletMultipartResolver(); 
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        return resolver;
    }

 

新建一个SpringBoot项目,引入web依赖。使用默认的resolver。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

一、文件上传

1、单文件上传

MultipartFile 类封装了请求数据中的文件,此时这个文件存储在内存中或临时的磁盘文件中,需要将其转存到一个合适的位置,因为请求结束后临时存储将被清空。在 MultipartFile 接口中有如下方法:

  • String getName();                   // 获取参数的名称
  • String getOriginalFilename(); // 获取文件的原名称
  • String getContentType();        // 文件内容的类型
  • boolean isEmpty();                 // 文件是否为空
  • long getSize();                        // 文件大小
  • byte[] getBytes();                    // 将文件内容以字节数组的形式返回
  • InputStream getInputStream(); // 将文件内容以输入流的形式返回
  • void transferTo(File dest);      // 将文件内容传输到指定文件中
@Controller
@RequestMapping("/file")
public class FileController {

    @PostMapping("/upload")
    @ResponseBody
    public String upload(MultipartFile file) {
        if(file.isEmpty()){
            return "文件不能为可空!";
        }
        // 使用日期来分类管理上传的文件
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        File folder = new File("D:/E/upload/" + format);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        String oldName = file.getOriginalFilename();
        String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
        File newFile = new File(folder, newName);
        try {
            //保存文件,返回文件路径
            file.transferTo(newFile);
            return folder + newName;
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        return "error";
    }

}

2、多文件上传

1)可以和单文件上传一样,多定义几个MultipartFile对象:

    @PostMapping("/uploads2")
    @ResponseBody
    public String uploads2(MultipartFile file1, MultipartFile file2) {
        // 使用日期来分类管理上传的文件
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        File folder = new File("D:/E/upload/" + format);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        try {
            String oldName = file1.getOriginalFilename();
            String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
            File newFile = new File(folder, newName);
            //保存文件
            file1.transferTo(newFile);

            oldName = file2.getOriginalFilename();
            newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
            newFile = new File(folder, newName);
            //保存文件
            file2.transferTo(newFile);
            return "success";
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        return "error";
    }

2)可以使用 MultipartFile[] 数组来接受:

    @PostMapping("/uploads")
    @ResponseBody
    public String uploads(MultipartFile[] files) {
        // 使用日期来分类管理上传的文件
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        File folder = new File("D:/E/upload/" + format);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        try {
            for (MultipartFile file : files) {
                if(file.isEmpty()){
                    System.out.println("文件不能为可空!");
                    continue;
                }
                String oldName = file.getOriginalFilename();
                String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
                File newFile = new File(folder, newName);
                //保存文件
                file.transferTo(newFile);
            }
            return "success";
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        return "error";
    }

我使用 postman测试了一下均成功。这里简单写一下前端的代码。

SpringBoot实现文件上传和下载

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>文件上传和下载</title>
</head>
<body>
    <form action='http://localhost:8080/file/upload' method='post' enctype='multipart/form-data'>
        <input type='file' name='file'>
        <button type='submit'>上传</button>
    </form>
    <a href="template/asd.jpg" download="aaname.jpg">下载</a>
</body>
</html>

3、修改 SpringBoot对文件限制的默认配置项

MultipartAutoConfiguration类中会看到创建的默认值,我们要自定义,添加bean配置,替换它的即可。

SpringBoot实现文件上传和下载

SpringBoot实现文件上传和下载

方式一:在 application.yaml 配置文件中自定义:

spring:
  servlet:
    multipart:
      enabled: true  #是否启用http上传处理
      max-request-size: 100MB #最大请求文件的大小
      max-file-size: 900KB      #设置单个文件的大小
      file-size-threshold: 15MB  #当文件达到多少时进行磁盘写入(临时文件的存放目录)
      location: D:/E/upload/temp #当磁盘写入时的临时文件的存放目录(目录不存在会自动创建,上传完毕会自动删除临时文件)
#      resolve-lazily: false   #当前文件和参数被访问时是否再解析成文件

方式二:在 配置类中自定义:

在@Configuration注解的配置类中,增加Bean配置。通过 MultipartConfigFactory类中的得到 MultipartConfigElement

@Configuration
public class UploadConfig {

    @Bean
    MultipartConfigElement multipartConfigElement(){
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setLocation("D:/E/upload/temp");
        factory.setFileSizeThreshold(DataSize.parse("15", DataUnit.MEGABYTES)); //15MB
        factory.setMaxRequestSize(DataSize.parse("100", DataUnit.MEGABYTES)); //100MB
        factory.setMaxFileSize(DataSize.parse("90", DataUnit.KILOBYTES)); //900KB
        MultipartConfigElement element = factory.createMultipartConfig();
        return element;
    }

}

如果想使用 CommonsMultipartResolver ,添加bean配置即可:

    @Bean
    public MultipartResolver multipartResolver() {
        // 默认配不配都行,如果使用CommonsMultipartResolver,注入就行
//        StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setDefaultEncoding("UTF-8");
        resolver.setMaxInMemorySize(900 * 1024); // 900KB
        resolver.setMaxUploadSize(100 * 1024 * 1024);// 上传文件大小 100M
        return resolver;
    }

 

二、文件下载

1、固定模板文件下载

不需要后台处理,使用html的<a> 标签即可实现。

<a href="template/asd.jpg" download="aaname.jpg">下载</a>

2、后台处理文件下载

对文件的处理更加灵活,最后把文件二进制数据写到响应中即可。

注意:不同浏览器文件名乱码的问题。

这里使用了 org.apache.commons.io.FileUtils工具类来处理文件流的操作,所以添加它的依赖。你也可以自己写。

        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>
    @GetMapping("/download")
    @ResponseBody
    public ResponseEntity<byte[]> download() throws Exception{
        //下载文件,简单new个文件
        String downloadFilePath = "D:/E/upload/2020-10-20/8d053ae3-5fcb-4a7a-ab68-6e69e706f84c.jpg";
        File downloadFile = new File(downloadFilePath);
        String downloadFilenName ="下载文件名123" + downloadFile.getName().substring(downloadFile.getName().lastIndexOf("."));

        HttpHeaders headers = new HttpHeaders();
        //下载显示的文件名,并解决中文名称乱码问题
        String downloadFileName = new String(downloadFilenName.getBytes("UTF-8"),"iso-8859-1");
        //通知浏览器以attachment(下载方式)打开
        headers.setContentDispositionFormData("attachment", downloadFileName);
        //applicatin/octet-stream: 二进制流数据(最常见的文件下载)
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);

        // 使用下org.apache.commons.io.FileUtils工具类
        byte[] bytes = FileUtils.readFileToByteArray(downloadFile);
        return new ResponseEntity<byte[]>(bytes, headers, HttpStatus.CREATED);
    }

这里文件操作都在本地,项目中可能会使用文件服务器,比如:FTP服务器,阿里OSS云存储等。操作大同小异。

 

—— Stay Hungry. Stay Foolish. 求知若饥,虚心若愚。