spring boot 學習筆記 (5) 檔案上傳
一、配置
新增依賴包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
引入了 spring-boot-starter-thymeleaf 做頁面模板引擎。
新增配置
#是否支援 multipart 上傳檔案 spring.servlet.multipart.enabled=true #支援檔案寫入磁碟 #spring.servlet.multipart.file-size-threshold=0 #上傳檔案的臨時目錄 #spring.servlet.multipart.location= #最大支援檔案大小 spring.servlet.multipart.maxFileSize=10MB #最大支援請求大小 spring.servlet.multipart.maxRequestSize=10MB #是否支援 multipart 上傳檔案時懶載入 #spring.servlet.multipart.resolve-lazily=false
再啟動類中增加相關方法
@SpringBootApplication public class FileUploadWebApplication { public static void main(String[] args) throws Exception { SpringApplication.run(FileUploadWebApplication.class, args); } //Tomcat large file upload connection reset @Bean public TomcatServletWebServerFactory tomcatEmbedded() { TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory(); tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> { if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) { //-1 means unlimited ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1); } }); return tomcat; } }
TomcatServletWebServerFactory() 方法主要是為了解決上傳檔案大於 10M 出現連線重置的問題,此異常內容 GlobalException 也捕獲不到。
二、相關程式碼
單檔案上傳
上傳業務處理:
@PostMapping("/upload")
public String singleFileUpload(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
if (file.isEmpty()) {
return "Please select a file to upload";
}
try {
// Get the file and save it somewhere
byte[] bytes = file.getBytes();
// UPLOADED_FOLDER 檔案本地儲存地址
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
Files.write(path, bytes);
} catch (IOException e) {
e.printStackTrace();
}
return "You successfully uploaded '" + file.getOriginalFilename() + "'";
}
異常處理
這裡演示的是 MultipartException 的異常處理,也可以稍微改造監控整個專案的異常問題。
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MultipartException.class)
public String handleError1(MultipartException e, RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("message", e.getCause().getMessage());
return "redirect:/uploadStatus";
}
}
設定一個 @ControllerAdvice 用來監控 Multipart 上傳的檔案大小是否受限,當出現此異常時在前端頁面給出提示。利用 @ControllerAdvice 可以做很多東西,比如全域性的統一異常處理等,感興趣的讀者可以抽空了解一下。
多檔案上傳
@PostMapping("/uploadMore")
public String moreFileUpload(@RequestParam("file") MultipartFile[] files,
RedirectAttributes redirectAttributes) {
if (files.length==0) {
return "Please select a file to upload";
}
for(MultipartFile file:files){
try {
byte[] bytes = file.getBytes();
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
Files.write(path, bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
return "You successfully uploaded all";
}
總的來說,檔案上傳的程式碼還是比較簡單的,但是要注意,需要按照實際的需求去處理相關的業務,比如返回上傳圖片地址,儲存檔案的相對路徑到資料庫,
三、採坑記錄
1、IDEA控制檯 中文亂碼問題,
在pom檔案中新增 編碼格式
IDEA設定編碼的地方很多,需要注意要保持一致,
2、設定檔案上傳路徑和顯示路徑
在開發過程中,如果不設定上傳檔案路徑, 或者路徑設定在專案中的檔案中的時候,當專案重新發布時,上傳的檔案就丟失了。
所以這裡我把檔案上傳到了本地資料夾。
這樣帶來一個問題,怎麼顯示上傳的檔案。
① 如果是直接放在tomcat中,可以通過修改tomcat的配置,
在tomcat>conf>server.xml 中,新增檔案的對映
② 如果是用的IDEA釋出的,可以修改相關配置。
先配置上傳檔案路徑和外部訪問路徑
#靜態資源對外暴露的訪問路徑
file.staticAccessPath=upload/**
#檔案上傳目錄(注意Linux和Windows上的目錄結構不同)
#file.uploadFolder=/root/uploadFiles/
file.uploadFolder=G://upload/
新增檔案UploadFilePathConfig 用於對映兩個路徑的關係
@Configuration
public class UploadFilePathConfig extends WebMvcConfigurerAdapter {
@Value("${file.staticAccessPath}")
private String staticAccessPath;
@Value("${file.uploadFolder}")
private String uploadFolder;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(staticAccessPath).addResourceLocations("file:" + uploadFolder);
}
}
注意,這裡的外部訪問路徑都是相對路徑,沒有包含專案的根路徑context-path, 在前端介面 使用時,需要手動新增。
這裡我沒有把根目錄配置到檔案路徑中進去,而是在前段拼接。因為我會把檔案的路徑儲存在資料庫中,如果帶有根路徑相關資料,在專案名發生改變的時候改動會很多,
3、關於@RestController 和@Controller 的區別
@RestController是 @Controller 和 @ResponseBody 註解的合體版 ; 如果配置,則返回 相關字串
如果配置為 @Controller,代表輸出對應的頁面。
不用弄錯了
4、jsp和Thymeleaf混合使用
之前的上傳介面是用jsp寫的,引入進來之後,jsp介面一直找不到,
報錯:
Error resolving template [hello], template might not exist or might not be accessible by any of the configured Template Resolvers
但是反覆確認了jsp檔案和相關的配置都沒有問題,後來才看到
spring boot 不建議使用jsp,並且對JSP支援存在一些限制
- 使用Jetty和Tomcat,如果使用war包裝,它應該可以工作。可執行的war在啟動時將起作用java -jar,並且也可以部署到任何標準容器。使用可執行jar時不支援JSP。
- Undertow不支援JSP。
- 建立自定義error.jsp頁面不會覆蓋錯誤處理的預設檢視 。 應該使用自定義錯誤頁面。
但是如果真的要使用jsp,還是有辦法的:
1、在配置檔案application.properties 中 配置 jsp,和之前的差不多,
spring.mvc.view.prefix=/WEB-INF/
spring.mvc.view.suffix=.jsp
spring.mvc.view.view-name=jsp/*
spring.mvc.view.order=2
2、在SpringbootApplication檔案中新增對應的對映方法,並將相關配置設定到方法中
@Value("${spring.mvc.view.prefix}")
private String prefix;
@Value("${spring.mvc.view.suffix}")
private String suffix;
@Value("${spring.mvc.view.view-name}")
private String viewName;
@Value("${spring.mvc.view.order}")
private int order;
@Bean
InternalResourceViewResolver jspViewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix(prefix);
viewResolver.setSuffix(suffix);
viewResolver.setViewNames(viewName);
viewResolver.setOrder(order);
return viewResolver;
}
3、在控制器中使用
@RequestMapping("/welcome")
public String welcome(Map<String, Object> model) {
model.put("time", new Date());
model.put("message", "www.richduckling.com");
model.put("count", 16);
return "jsp/hello";
}
注意:
這裡配置jsp檔案位置引數 時,我設定的是“spring.mvc.view.prefix=/WEB-INF/jsp” ,使用時 “return "jsp/hello"”,但是還是報錯。重新安置上面的設定,就可以。因為 如果在控制器中不設定jsp路徑,會預設去Thymeleaf的相關路徑中去找,如果找不到對應的Thymeleaf檢視就會報錯,於是排在後面用來解析Jsp檢視的InternalResourceViewResolver就失效了,不會繼續在jsp相關檔案中找。無語。