1. 程式人生 > >SpringBoot實現檔案上傳功能詳解

SpringBoot實現檔案上傳功能詳解

[toc] # 利用SpirngBoot實現檔案上傳功能 ## 零、本篇要點 - 介紹SpringBoot對檔案上傳的自動配置。 - 介紹MultipartFile介面。 - 介紹SpringBoot+Thymeleaf檔案上傳demo的整合。 - 介紹對檔案型別,檔名長度等判斷方法。 ## 一、SpringBoot對檔案處理相關自動配置 自動配置是SpringBoot為我們提供的便利之一,開發者可以在不作任何配置的情況下,使用SpringBoot提供的預設設定,如處理檔案需要的MultipartResolver。 ```java @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class }) @ConditionalOnProperty(prefix = "spring.servlet.multipart", name = "enabled", matchIfMissing = true) @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(MultipartProperties.class) public class MultipartAutoConfiguration { private final MultipartProperties multipartProperties; public MultipartAutoConfiguration(MultipartProperties multipartProperties) { this.multipartProperties = multipartProperties; } @Bean @ConditionalOnMissingBean({ MultipartConfigElement.class, CommonsMultipartResolver.class }) public MultipartConfigElement multipartConfigElement() { return this.multipartProperties.createMultipartConfig(); } @Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) @ConditionalOnMissingBean(MultipartResolver.class) public StandardServletMultipartResolver multipartResolver() { StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver(); multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily()); return multipartResolver; } } ``` - Spring3.1之後支援`StandardServletMultipartResolver`,且預設使用`StandardServletMultipartResolver`,它的優點在於:使用Servlet所提供的功能支援,不需要依賴任何其他的專案。 - 想要自動配置生效,需要配置`spring.servlet.multipart.enabled=true`,當然這個配置預設就是true。 - 相關的配置設定在`MultipartProperties`中,其中欄位就是對應的屬性設定,經典欄位有: - `enabled`:是否開啟檔案上傳自動配置,預設開啟。 - `location`:上傳檔案的臨時目錄。 - `maxFileSize`:最大檔案大小,以位元組為單位,預設為1M。 - `maxRequestSize`:整個請求的最大容量,預設為10M。 - `fileSizeThreshold`:檔案大小達到該閾值,將寫入臨時目錄,預設為0,即所有檔案都會直接寫入磁碟臨時檔案中。 - `resolveLazily`:是否惰性處理請求,預設為false。 - 我們也可以自定義處理的細節,需要實現MultipartResolver介面。 ## 二、處理上傳檔案MultipartFile介面 SpringBoot為我們提供了MultipartFile強大介面,讓我們能夠獲取上傳檔案的詳細資訊,如原始檔名,內容型別等等,介面內容如下: ```java public interface MultipartFile extends InputStreamSource { String getName(); //獲取引數名 @Nullable String getOriginalFilename();//原始的檔名 @Nullable String getContentType();//內容型別 boolean isEmpty(); long getSize(); //大小 byte[] getBytes() throws IOException;// 獲取位元組陣列 InputStream getInputStream() throws IOException;//以流方式進行讀取 default Resource getResource() { return new MultipartFileResource(this); } // 將上傳的檔案寫入檔案系統 void transferTo(File var1) throws IOException, IllegalStateException; // 寫入指定path default void transferTo(Path dest) throws IOException, IllegalStateException { FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest)); } } ``` ## 三、SpringBoot+Thymeleaf整合demo ### 1、編寫控制器 ```java /** * 檔案上傳 * * @author Summerday */ @Controller public class FileUploadController { private static final String UPLOADED_FOLDER = System.getProperty("user.dir"); @GetMapping("/") public String index() { return "file"; } @PostMapping("/upload") public String singleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) throws IOException { if (file.isEmpty()) { redirectAttributes.addFlashAttribute("msg", "檔案為空,請選擇你的檔案上傳"); return "redirect:uploadStatus"; } saveFile(file); redirectAttributes.addFlashAttribute("msg", "上傳檔案" + file.getOriginalFilename() + "成功"); redirectAttributes.addFlashAttribute("url", "/upload/" + file.getOriginalFilename()); return "redirect:uploadStatus"; } private void saveFile(MultipartFile file) throws IOException { Path path = Paths.get(UPLOADED_FOLDER + "/" + file.getOriginalFilename()); file.transferTo(path); } @GetMapping("/uploadStatus") public String uploadStatus() { return "uploadStatus"; } } ``` ### 2、編寫頁面file.html ```html 檔案上傳介面
``` ### 3、編寫頁面uploadStatus.html ```html 檔案上傳介面

``` ### 4、編寫配置 ```properties server.port=8081 spring.servlet.multipart.max-file-size=10MB spring.servlet.multipart.max-request-size=10MB ``` ### 5、配置虛擬路徑對映 這一步是非常重要的,我們將檔案上傳到伺服器上時,我們需要將我們的請求路徑和伺服器上的路徑進行對應,不然很有可能檔案上傳成功,但訪問失敗: ```java @Configuration public class MvcConfig implements WebMvcConfigurer { private static final String UPLOADED_FOLDER = System.getProperty("user.dir"); @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/upload/**") .addResourceLocations("file:///" + UPLOADED_FOLDER + "/"); } } ``` 對應關係需要自己去定義,如果訪問失敗,可以試著列印以下路徑,看看是否缺失了路徑分隔符。 >
注意:如果addResourceHandler不要寫成處理/**,這樣會攔截掉其他的請求 ### 6、測試頁面 執行`mvn spring-boot:run`,啟動程式,訪問`http://localhost:8081/`,選擇檔案,點選上傳按鈕,我們的專案目錄下出現了mongo.jpg,並且頁面也成功顯示: ![](https://img2020.cnblogs.com/blog/1771072/202011/1771072-20201113151153063-531316526.png) ## 四、SpringBoot的Restful風格,返回url ```java /** * 檔案上傳 * * @author Summerday */ @RestController public class FileUploadRestController { /** * 檔名長度 */ private static final int DEFAULT_FILE_NAME_LENGTH = 100; /** * 允許的檔案型別 */ private static final String[] ALLOWED_EXTENSIONS = { "jpg", "img", "png", "gif" }; /** * 專案路徑 */ private static final String UPLOADED_FOLDER = System.getProperty("user.dir"); @PostMapping("/restUpload") public Map singleFileUpload(@RequestParam("file") MultipartFile file) throws Exception { if (file.isEmpty()) { throw new Exception("檔案為空!"); } String filename = upload(file); String url = "/upload/" + filename; Map map = new HashMap<>(2); map.put("msg","上傳成功"); map.put("url",url); return map; } /** * 上傳方法 */ private String upload(MultipartFile file) throws Exception { int len = file.getOriginalFilename().length(); if (len > DEFAULT_FILE_NAME_LENGTH) { throw new Exception("檔名超出限制!"); } String extension = getExtension(file); if(!isValidExtension(extension)){ throw new Exception("檔案格式不正確"); } // 自定義檔名 String filename = getPathName(file); // 獲取file物件 File desc = getFile(filename); // 寫入file file.transferTo(desc); return filename; } /** * 獲取file物件 */ private File getFile(String filename) throws IOException { File file = new File(UPLOADED_FOLDER + "/" + filename); if(!file.getParentFile().exists()){ file.getParentFile().mkdirs(); } if(!file.exists()){ file.createNewFile(); } return file; } /** * 驗證檔案型別是否正確 */ private boolean isValidExtension(String extension) { for (String allowedExtension : ALLOWED_EXTENSIONS) { if(extension.equalsIgnoreCase(allowedExtension)){ return true; } } return false; } /** * 此處自定義檔名,uuid + extension */ private String getPathName(MultipartFile file) { String extension = getExtension(file); return UUID.randomUUID().toString() + "." + extension; } /** * 獲取副檔名 */ private String getExtension(MultipartFile file) { String originalFilename = file.getOriginalFilename(); return originalFilename.substring(originalFilename.lastIndexOf('.') + 1); } } ``` ## 五、原始碼下載 本文內容均為對優秀部落格及官方文件總結而得,原文地址均已在文中參考閱讀處標註。最後,文中的程式碼樣例已經全部上傳至Gitee:[https://gitee.com/tqbx/springboot-samples-learn](https://gitee.com/tqbx/springboot-samples-learn),另有其他SpringBoot的整合哦。 ## 六、參考閱讀 - [官方文件:SpringWebMVC#DispatcherServlet#Multipart Resolver](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-multipart) - [Spring Boot file upload example](https://mkyong.com/spring-boot/spring-boot-file-upload-example/)