文件上傳和下載是Web應用程序比較經常使用的功能之一,在本章節中,我將以一個簡單的案例來說解在Spring Boot中如何進行文件的上傳與下載。在開始正文以前,咱們經過一張思惟導圖來了解一下文件上傳與下載的簡單流程:javascript
對於文件上傳,控制器中對應的上傳方法的參數必須是MultipartFile對象,MultipartFile對象能夠是一個數組對象,也能夠是單個對象,若是是一個數組對象,則能夠進行多文件上傳;這裏咱們僅演示單個文件上傳,下面的代碼展現了文件上傳方法的基本結構:php
@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」**的提示信息,下面是文件上傳完整的代碼:html
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用於存放已上傳文件的索引信息。java
在Spring Boot應用程序中,咱們可使用InputStreamResource對象來下載文件,在下載文件的方法中,咱們須要經過Response來設置HttpHeander對象的相關屬性,如Content-Disposition、Cache-Control、Pragma和Expires等屬性。除此以外,還須要指定Response的響應類型。下面的代碼給出了文件下載的詳細信息:git
@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;
}
複製代碼
下面給出的是完整的文件上傳和下載的代碼:github
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的代碼:web
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文件配置清單:spring
<?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模板引擎做爲視圖模板apache
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程序中上傳和下載文件