1. 程式人生 > >spring boot 學習筆記 (5) 檔案上傳

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相關檔案中找。無語。