Spring Boot文件上传和下载
文件上传和下载是Web应用程序比较常用的功能之一,在本章节中,我将以一个简单的案例来讲解在Spring Boot中如何进行文件的上传与下载。在开始正文之前,我们通过一张思维导图来了解一下文件上传与下载的简单流程:
1. 文件上传
对于文件上传,控制器中对应的上传方法的参数必须是MultipartFile对象,MultipartFile对象可以是一个数组对象,也可以是单个对象,如果是一个数组对象,则可以进行多文件上传;这里我们仅演示单个文件上传,下面的代码展示了文件上传方法的基本结构:
@PostMapping(value ="/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)@ResponseBodypublic StringfileUpload(@RequestParam("file") MultipartFile file)throws IOException{returnnull;
}复制代码
接下来,我们使用FileOutputStream对象将客户端上传的文件写入到磁盘中,并返回**“File is upload successfully”**的提示信息,下面是文件上传完整的代码:
package com.ramostear.application.controller;import com.ramostear.application.model.FileInfo;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.*;import org.springframework.web.multipart.MultipartFile;import javax.annotation.PostConstruct;import java.io.*;import java.util.HashMap;import java.util.Map;/**
*@author : ramostear
*@date : 2019/3/8 0008-15:35
*/@ControllerpublicclassFileController{@Value ("${file.upload.root.dir}" )
String fileUploadRootDir;privatestatic Map<String,FileInfo> fileRepository =new HashMap<>();@PostConstructpublicvoidinitFileRepository(){
FileInfo file1 =new FileInfo ().setFileName ("bg1.jpg" );
FileInfo file2 =new FileInfo ().setFileName ("bg2.jpg" );
FileInfo file3 =new FileInfo ().setFileName ("bg3.jpg" );
fileRepository.put ( file1.getName (),file1 );
fileRepository.put ( file2.getName (),file2 );
fileRepository.put ( file3.getName (),file3 );
}@PostMapping(value ="/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)@ResponseBodypublic StringfileUpload(@RequestParam("file") MultipartFile file)throws IOException{
File convertFile =new File ( fileUploadRootDir+file.getOriginalFilename ());
FileOutputStream fileOutputStream =new FileOutputStream ( convertFile );
fileOutputStream.write ( file.getBytes () );
fileOutputStream.close ();
FileInfo fileInfo =new FileInfo()
.setFileName ( file.getOriginalFilename());
fileRepository.put ( fileInfo.getName (),fileInfo);return"File is upload successfully";
}
}复制代码
fileRepository用于存放已上传文件的索引信息。
2. 文件下载
在Spring Boot应用程序中,我们可以使用InputStreamResource对象来下载文件,在下载文件的方法中,我们需要通过Response来设置HttpHeander对象的相关属性,如Content-Disposition、Cache-Control、Pragma和Expires等属性。除此之外,还需要指定Response的响应类型。下面的代码给出了文件下载的详细信息:
@GetMapping("/download/{fileName}")@ResponseBodypublic ResponseEntity<Object>downloadFile(@PathVariable(name ="fileName") String fileName)throws FileNotFoundException{
File file =new File ( fileUploadRootDir+fileName);
InputStreamResource resource =new InputStreamResource (new FileInputStream ( file ) );
HttpHeaders headers =new HttpHeaders();
headers.add ("Content-Disposition",String.format("attachment;filename=\"%s",fileName));
headers.add ("Cache-Control","no-cache,no-store,must-revalidate" );
headers.add ("Pragma","no-cache" );
headers.add ("Expires","0" );
ResponseEntity<Object> responseEntity = ResponseEntity.ok()
.headers ( headers )
.contentLength ( file.length ())
.contentType(MediaType.parseMediaType ("application/txt" ))
.body(resource);return responseEntity;
}复制代码
3. 代码清单
3.1 文件上传和下载控制器
下面给出的是完整的文件上传和下载的代码:
package com.ramostear.application.controller;import com.ramostear.application.model.FileInfo;import org.springframework.beans.factory.annotation.Value;import org.springframework.core.io.InputStreamResource;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpStatus;import org.springframework.http.MediaType;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.*;import org.springframework.web.multipart.MultipartFile;import javax.annotation.PostConstruct;import java.io.*;import java.util.Collection;import java.util.HashMap;import java.util.Map;/**
*@author : ramostear
*@date : 2019/3/8 0008-15:35
*/@ControllerpublicclassFileController{@Value ("${file.upload.root.dir}" )
String fileUploadRootDir;privatestatic Map<String,FileInfo> fileRepository =new HashMap<>();@PostConstructpublicvoidinitFileRepository(){
FileInfo file1 =new FileInfo ().setFileName ("bg1.jpg" );
FileInfo file2 =new FileInfo ().setFileName ("bg2.jpg" );
FileInfo file3 =new FileInfo ().setFileName ("bg3.jpg" );
fileRepository.put ( file1.getName (),file1 );
fileRepository.put ( file2.getName (),file2 );
fileRepository.put ( file3.getName (),file3 );
}@GetMapping("/files")public Stringfiles(Model model){
Collection<FileInfo> files = fileRepository.values ();
model.addAttribute ("data",files );return"files";
}@PostMapping(value ="/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)@ResponseBodypublic StringfileUpload(@RequestParam("file") MultipartFile file)throws IOException{
File convertFile =new File ( fileUploadRootDir+file.getOriginalFilename ());
FileOutputStream fileOutputStream =new FileOutputStream ( convertFile );
fileOutputStream.write ( file.getBytes () );
fileOutputStream.close ();
FileInfo fileInfo =new FileInfo()
.setFileName ( file.getOriginalFilename());
fileRepository.put ( fileInfo.getName (),fileInfo);return"File is upload successfully";
}@GetMapping("/download/{fileName}")@ResponseBodypublic ResponseEntity<Object>downloadFile(@PathVariable(name ="fileName") String fileName)throws FileNotFoundException{
File file =new File ( fileUploadRootDir+fileName);
InputStreamResource resource =new InputStreamResource (new FileInputStream ( file ) );
HttpHeaders headers =new HttpHeaders();
headers.add ("Content-Disposition",String.format("attachment;filename=\"%s",fileName));
headers.add ("Cache-Control","no-cache,no-store,must-revalidate" );
headers.add ("Pragma","no-cache" );
headers.add ("Expires","0" );
ResponseEntity<Object> responseEntity = ResponseEntity.ok()
.headers ( headers )
.contentLength ( file.length ())
.contentType(MediaType.parseMediaType ("application/txt" ))
.body(resource);return responseEntity;
}
}复制代码
3.2 数据模型
创建一个文件信息数据模型作为上传文件信息的载体,下面是FileInfo.java的代码:
package com.ramostear.application.model;import lombok.Data;import java.util.Date;/**
*@author : ramostear
*@date : 2019/3/8 0008-15:25
*/@DatapublicclassFileInfo{private String name;private Date uploadTime =new Date();public FileInfosetFileName(String name){this.setName ( name );returnthis;
}
}复制代码
3.3 Maven build 文件
下面是本次demo应用程序的pom.xml文件配置清单:
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version><relativePath/><!-- lookup parent from repository --></parent><groupId>com.ramostear</groupId><artifactId>file-handling</artifactId><version>0.0.1-SNAPSHOT</version><name>file-handling</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>复制代码
注:本次案例使用freemarker模板引擎作为视图模板
3.4 配置文件
application.properties文件主要设置了freemarker的相关属性以及自定义的**file.upload.root.dir **属性:
spring.freemarker.cache=false
spring.freemarker.prefix=
spring.freemarker.suffix=.html
spring.freemarker.enabled=true
spring.freemarker.charset=UTF-8
spring.freemarker.template-loader-path=classpath:/templates/
file.upload.root.dir = C:/work/upload/复制代码
file.upload.root.dir自定义属性设置了文件上传的更目录为:C:/work/upload/
3.5 视图
在视图文件中,创建了一个form表单用于上传文件,另外还创建了一个已上传文件列表,提供文件下载操作。
文件上传表单:
文件下载列表:
说明:文件上使用的是异步上传方式进行上传,没有使用同步提交form表单的方式进行
文件上传异步操作代码如下:
$("#upload").on("click",function (){var fileObj =document.getElementById("file").files[0];var form =new FormData();
form.append("file",fileObj);var xhr =new XMLHttpRequest();
xhr.open("post","http://localhost:8080/upload",true);
xhr.onload =function(event){
alert(event.currentTarget.responseText);window.location.href =window.location.href;
};
xhr.send(form);
});复制代码
4. 打包运行
使用Maven命令对应用程序进行打包,下面是maven打包的命令:
mvn clean install复制代码
在控制台窗口中运行上述命令,等待maven打包。若控制台中显示**“BUILD SUCCESS”**信息,你可以在当前工程目录下的target文件夹中找到相应的JAR文件。
现在,你可以使用下面的命令来运行JAR文件:
java -jar YOUR_JARFILE_NAME复制代码
JAR文件成功启动后,你可以在控制台窗口中看到如下的信息:
5. 测试
打开浏览器并在地址栏输入:http://localhost:8080/files 。下面是成功请求后的浏览器截图:
接下来,点击其中任意一个download按钮,测试文件下载功能是否正常:
最后,我们测试一下文件上传功能是否正常。在进行测试之前,我们先看一下文件上传目录中存储的文件信息:
接下来,我们选择一份需要上传的文件,然后点击upload按钮上传文件:
此时,文件以及上传成功,我们再次观察文件上传目录中的文件信息,以验证文件是否成功写入磁盘:
6. 附件
本章节的全部源代码已经上传至Github代码仓库中,你可以访问下面的地址获得全部的源码:github.com/ramostear/S…
作者:谭朝红,原文:在Spring Boot程序中上传和下载文件
转载于:https://juejin.im/post/5cadda1a51882554356af420