文件上传和下载是Web应用程序比较经常使用的功能之一,在本章节中,我将以一个简单的案例来说解在Spring Boot中如何进行文件的上传与下载。在开始正文以前,咱们经过一张思惟导图来了解一下文件上传与下载的简单流程:javascript
对于文件上传,控制器中对应的上传方法的参数必须是MultipartFile对象,MultipartFile对象能够是一个数组对象,也能够是单个对象,若是是一个数组对象,则能够进行多文件上传;这里咱们仅演示单个文件上传,下面的代码展现了文件上传方法的基本结构:html
@PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @ResponseBody public String fileUpload(@RequestParam("file") MultipartFile file) throws IOException { return null; } 复制代码
接下来,咱们使用FileOutputStream对象将客户端上传的文件写入到磁盘中,并返回**“File is upload successfully”**的提示信息,下面是文件上传完整的代码:java
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 */ @Controller public class FileController { @Value ( "${file.upload.root.dir}" ) String fileUploadRootDir; private static Map<String,FileInfo> fileRepository = new HashMap<>(); @PostConstruct public void initFileRepository(){ 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) @ResponseBody public String fileUpload(@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用于存放已上传文件的索引信息。git
在Spring Boot应用程序中,咱们可使用InputStreamResource对象来下载文件,在下载文件的方法中,咱们须要经过Response来设置HttpHeander对象的相关属性,如Content-Disposition、Cache-Control、Pragma和Expires等属性。除此以外,还须要指定Response的响应类型。下面的代码给出了文件下载的详细信息:github
@GetMapping("/download/{fileName}") @ResponseBody public 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; } 复制代码
下面给出的是完整的文件上传和下载的代码:web
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 */ @Controller public class FileController { @Value ( "${file.upload.root.dir}" ) String fileUploadRootDir; private static Map<String,FileInfo> fileRepository = new HashMap<>(); @PostConstruct public void initFileRepository(){ 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 String files(Model model){ Collection<FileInfo> files = fileRepository.values (); model.addAttribute ( "data",files ); return "files"; } @PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @ResponseBody public String fileUpload(@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}") @ResponseBody public 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; } } 复制代码
建立一个文件信息数据模型做为上传文件信息的载体,下面是FileInfo.java的代码:spring
package com.ramostear.application.model; import lombok.Data; import java.util.Date; /** * @author : ramostear * @date : 2019/3/8 0008-15:25 */ @Data public class FileInfo { private String name; private Date uploadTime = new Date(); public FileInfo setFileName(String name){ this.setName ( name ); return this; } } 复制代码
下面是本次demo应用程序的pom.xml文件配置清单:apache
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="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模板引擎做为视图模板数组
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/
在视图文件中,建立了一个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); }); 复制代码
使用Maven命令对应用程序进行打包,下面是maven打包的命令:
mvn clean install
复制代码
在控制台窗口中运行上述命令,等待maven打包。若控制台中显示**“BUILD SUCCESS”**信息,你能够在当前工程目录下的target文件夹中找到相应的JAR文件。
如今,你可使用下面的命令来运行JAR文件:
java -jar YOUR_JARFILE_NAME
复制代码
JAR文件成功启动后,你能够在控制台窗口中看到以下的信息:
打开浏览器并在地址栏输入:http://localhost:8080/files 。下面是成功请求后的浏览器截图:
接下来,点击其中任意一个download按钮,测试文件下载功能是否正常:
最后,咱们测试一下文件上传功能是否正常。在进行测试以前,咱们先看一下文件上传目录中存储的文件信息:
接下来,咱们选择一份须要上传的文件,而后点击upload按钮上传文件:
此时,文件以及上传成功,咱们再次观察文件上传目录中的文件信息,以验证文件是否成功写入磁盘:
本章节的所有源代码已经上传至Github代码仓库中,你能够访问下面的地址得到所有的源码:github.com/ramostear/S…
做者:谭朝红,原文:在Spring Boot程序中上传和下载文件