SpringBoot实现文件上传和下载

it2023-01-24  62

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

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

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

@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测试了一下均成功。这里简单写一下前端的代码。

<!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配置,替换它的即可。

方式一:在 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. 求知若饥,虚心若愚。

 

最新回复(0)