更新時間:2022-05-16 11:21:53 來源:動力節點 瀏覽1336次
本指南將引導您完成創建可以接收 HTTP 多部分文件上傳的服務器應用程序的過程。
您將創建一個接受文件上傳的 Spring Boot Web 應用程序。您還將構建一個簡單的 HTML 界面來上傳測試文件。
像大多數 Spring入門指南一樣,您可以從頭開始并完成每個步驟,也可以繞過您已經熟悉的基本設置步驟。無論哪種方式,您最終都會得到工作代碼。
要從頭開始,請繼續從 Spring Initializr 開始。
要跳過Java基礎教程,請執行以下操作:
下載并解壓縮本指南的源存儲庫,或使用Git克隆它:
git clone https://github.com/spring-guides/gs-uploading-files.git
光盤進入gs-uploading-files/initial
繼續創建應用程序類。
完成后,您可以對照中的代碼檢查結果gs-uploading-files/complete。
您可以使用這個預先初始化的項目并單擊 Generate 下載 ZIP 文件。此項目配置為適合本教程中的示例。
手動初始化項目:
導航到https://start.spring.io。該服務提取應用程序所需的所有依賴項,并為您完成大部分設置。
選擇 Gradle 或 Maven 以及您要使用的語言。本指南假定您選擇了 Java。
單擊Dependencies并選擇Spring Web和Thymeleaf。
單擊生成。
下載生成的 ZIP 文件,該文件是根據您的選擇配置的 Web 應用程序的存檔。
如果您的 IDE 具有 Spring Initializr 集成,您可以從您的 IDE 完成此過程。
你也可以從 Github 上 fork 項目并在你的 IDE 或其他編輯器中打開它。
要啟動 Spring Boot MVC 應用程序,首先需要一個啟動器。在此示例中,spring-boot-starter-thymeleaf并且spring-boot-starter-web已作為依賴項添加。要使用 Servlet 容器上傳文件,您需要注冊一個MultipartConfigElement類(在 web.xml 中)。感謝 Spring Boot,一切都是為您自動配置的!
開始使用此應用程序所需的只是以下UploadingFilesApplication類
package com.example.uploadingfiles;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UploadingFilesApplication {
public static void main(String[] args) {
SpringApplication.run(UploadingFilesApplication.class, args);
}
}
作為自動配置 Spring MVC 的一部分,Spring Boot 將創建一個MultipartConfigElementbean 并為文件上傳做好準備。
初始應用程序已經包含一些類來處理在磁盤上存儲和加載上傳的文件。它們都位于com.example.uploadingfiles.storage包裝中。您將在新的FileUploadController. 以下清單顯示了文件上傳控制器:
package com.example.uploadingfiles;
import java.io.IOException;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.example.uploadingfiles.storage.StorageFileNotFoundException;
import com.example.uploadingfiles.storage.StorageService;
@Controller
public class FileUploadController {
private final StorageService storageService;
@Autowired
public FileUploadController(StorageService storageService) {
this.storageService = storageService;
}
@GetMapping("/")
public String listUploadedFiles(Model model) throws IOException {
model.addAttribute("files", storageService.loadAll().map(
path -> MvcUriComponentsBuilder.fromMethodName(FileUploadController.class,
"serveFile", path.getFileName().toString()).build().toUri().toString())
.collect(Collectors.toList()));
return "uploadForm";
}
@GetMapping("/files/{filename:.+}")
@ResponseBody
public ResponseEntity<Resource> serveFile(@PathVariable String filename) {
Resource file = storageService.loadAsResource(filename);
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + file.getFilename() + "\"").body(file);
}
@PostMapping("/")
public String handleFileUpload(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
storageService.store(file);
redirectAttributes.addFlashAttribute("message",
"You successfully uploaded " + file.getOriginalFilename() + "!");
return "redirect:/";
}
@ExceptionHandler(StorageFileNotFoundException.class)
public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException exc) {
return ResponseEntity.notFound().build();
}
}
該類FileUploadController帶有注釋,@Controller以便 Spring MVC 可以拾取它并查找路由。每個方法都被標記@GetMapping或@PostMapping將路徑和 HTTP 操作綁定到特定的控制器操作。
在這種情況下:
GET /:從 中查找當前上傳文件的列表StorageService并將其加載到 Thymeleaf 模板中。它通過使用 計算到實際資源的鏈接MvcUriComponentsBuilder。
GET /files/{filename}:加載資源(如果存在)并使用Content-Disposition響應頭將其發送到瀏覽器進行下載。
POST /:處理多部分消息file并將其提供給StorageService保存。
您將需要提供一個StorageService以便控制器可以與存儲層(例如文件系統)進行交互。以下清單顯示了該界面:
package com.example.uploadingfiles.storage;
import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
import java.nio.file.Path;
import java.util.stream.Stream;
public interface StorageService {
void init();
void store(MultipartFile file);
Stream<Path> loadAll();
Path load(String filename);
Resource loadAsResource(String filename);
void deleteAll();
}
以下 Thymeleaf 模板顯示了如何上傳文件并顯示已上傳內容的示例:
<html xmlns:th="https://www.thymeleaf.org">
<body>
<div th:if="${message}">
<h2 th:text="${message}"/>
</div>
<div>
<form method="POST" enctype="multipart/form-data" action="/">
<table>
<tr><td>File to upload:</td><td><input type="file" name="file" /></td></tr>
<tr><td></td><td><input type="submit" value="Upload" /></td></tr>
</table>
</form>
</div>
<div>
<ul>
<li th:each="file : ${files}">
<a th:href="${file}" th:text="${file}" />
</li>
</ul>
</div>
</body>
</html>
該模板包含三個部分:
Spring MVC 在其中寫入flash-scoped message頂部的可選消息。
允許用戶上傳文件的表單。
從后端提供的文件列表。
配置文件上傳時,設置文件大小限制通常很有用。想象一下嘗試處理 5GB 文件上傳!MultipartConfigElement使用 Spring Boot,我們可以使用一些屬性設置來調整它的自動配置。
將以下屬性添加到現有屬性設置:
spring.servlet.multipart.max-file-size=128KB
spring.servlet.multipart.max-request-size=128KB
多部分設置的約束如下:
spring.servlet.multipart.max-file-size設置為 128KB,這意味著總文件大小不能超過 128KB。
spring.servlet.multipart.max-request-size設置為 128KB,這意味著 a 的總請求大小multipart/form-data不能超過 128KB。
您需要一個目標文件夾來上傳文件,因此您需要增強UploadingFilesApplicationSpring Initializr 創建的基本類并添加一個 BootCommandLineRunner以在啟動時刪除并重新創建該文件夾。以下清單顯示了如何執行此操作:
package com.example.uploadingfiles;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import com.example.uploadingfiles.storage.StorageProperties;
import com.example.uploadingfiles.storage.StorageService;
@SpringBootApplication
@EnableConfigurationProperties(StorageProperties.class)
public class UploadingFilesApplication {
public static void main(String[] args) {
SpringApplication.run(UploadingFilesApplication.class, args);
}
@Bean
CommandLineRunner init(StorageService storageService) {
return (args) -> {
storageService.deleteAll();
storageService.init();
};
}
}
@SpringBootApplication是一個方便的注釋,它添加了以下所有內容:
@Configuration: 將類標記為應用程序上下文的 bean 定義源。
@EnableAutoConfiguration:告訴 Spring Boot 根據類路徑設置、其他 bean 和各種屬性設置開始添加 bean。例如,如果spring-webmvc位于類路徑上,則此注釋將應用程序標記為 Web 應用程序并激活關鍵行為,例如設置DispatcherServlet.
@ComponentScan: 告訴 Spring 在包中查找其他組件、配置和服務com/example,讓它找到控制器。
該main()方法使用 Spring Boot 的SpringApplication.run()方法來啟動應用程序。您是否注意到沒有一行 XML?也沒有web.xml文件。這個 Web 應用程序是 100% 純 Java,您不必處理任何管道或基礎設施的配置。
您可以使用 Gradle 或 Maven 從命令行運行應用程序。您還可以構建一個包含所有必要依賴項、類和資源的單個可執行 JAR 文件并運行它。構建可執行 jar 可以在整個開發生命周期、跨不同環境等中輕松地作為應用程序交付、版本化和部署服務。
如果您使用 Gradle,則可以使用./gradlew bootRun. 或者,您可以使用構建 JAR 文件./gradlew build,然后運行 ??JAR 文件,如下所示:
java -jar build/libs/gs-uploading-files-0.1.0.jar
如果您使用 Maven,則可以使用./mvnw spring-boot:run. 或者,您可以使用構建 JAR 文件,./mvnw clean package然后運行該 JAR 文件,如下所示:
java -jar 目標/gs-uploading-files-0.1.0.jar
它運行接收文件上傳的服務器端部分。顯示記錄輸出。該服務應在幾秒鐘內啟動并運行。
在服務器運行的情況下,您需要打開瀏覽器并訪問http://localhost:8080/以查看上傳表單。選擇一個(小)文件,然后按Upload。您應該會從控制器中看到成功頁面。如果你選擇的文件太大,你會得到一個丑陋的錯誤頁面。
然后,您應該會在瀏覽器窗口中看到類似于以下內容的行:
“您成功上傳了<文件名>!”
有多種方法可以在我們的應用程序中測試此特定功能。以下清單顯示了一個示例,MockMvc它不需要啟動 servlet 容器:
package com.example.uploadingfiles;
import java.nio.file.Paths;
import java.util.stream.Stream;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import com.example.uploadingfiles.storage.StorageFileNotFoundException;
import com.example.uploadingfiles.storage.StorageService;
@AutoConfigureMockMvc
@SpringBootTest
public class FileUploadTests {
@Autowired
private MockMvc mvc;
@MockBean
private StorageService storageService;
@Test
public void shouldListAllFiles() throws Exception {
given(this.storageService.loadAll())
.willReturn(Stream.of(Paths.get("first.txt"), Paths.get("second.txt")));
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(model().attribute("files",
Matchers.contains("http://localhost/files/first.txt",
"http://localhost/files/second.txt")));
}
@Test
public void shouldSaveUploadedFile() throws Exception {
MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt",
"text/plain", "Spring Framework".getBytes());
this.mvc.perform(multipart("/").file(multipartFile))
.andExpect(status().isFound())
.andExpect(header().string("Location", "/"));
then(this.storageService).should().store(multipartFile);
}
@SuppressWarnings("unchecked")
@Test
public void should404WhenMissingFile() throws Exception {
given(this.storageService.loadAsResource("test.txt"))
.willThrow(StorageFileNotFoundException.class);
this.mvc.perform(get("/files/test.txt")).andExpect(status().isNotFound());
}
}
在這些測試中,您使用各種模擬來設置與您的控制器以及StorageService與 Servlet 容器本身的交互,使用MockMultipartFile.
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習