我去,Excel文件導入失敗都搞不定麼----記一次Excel文件導入失敗--is not valid

前言

昨晚8點左右,正準備下班走人,突然,產品小姐姐的在QQ上猛地抖動了我一下。產品小姐姐果然是無事不登三寶殿。線上出了問題!!!!!!!好幾個版本沒有變動多的文件導入突然不行了。客戶催運營,運營催產品,產品催我這個小開發。哎,苦逼的程序員。

說明

本項目用的是 SpringBoot 2.x

問題重現

org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is java.io.IOException: The temporary upload location [/tmp/tomcat.46678487236333023.8030/work/Tomcat/localhost/extend] is not valid

我的腦門多了許多黑人問號??/tmp/tomcat.46678487236333023.8030/work/Tomcat/localhost/extend這是個啥文件夾?上傳文件爲啥會操作這個文件夾?這個文件夾是啥時候創建的呢?
帶着這一連串的問題,我開始了面向google的開發。 根據The temporary upload location is not valid關鍵字,搜索到如下結果:
在這裏插入圖片描述
說的是,這個文件夾沒有,需要手動在tmp下創建該文件夾。然後,我就在線上用我的common用戶,創建了這個文件夾,文件夾創建好之後,我接着嘗試去上傳Excel。緊接着又報了一個:

Failed to parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-data request failed. /tmp/tomcat.46678487236333023.8030/work/Tomcat/localhost/extend/upload_2062a9c2_2ecf_4176_9622_6ae54d0fe80b_00000003.tmp (權限不夠)

權限不夠,然後一看我這個文件夾的默認權限drwxrwxr-x,而我們項目部署的時候用的是Tomcat用戶,這個用戶是沒有權限在我新創建的文件夾下寫臨時文件。
而我小小的common用戶又沒有權限進行chmod。無奈只能請求我們的運維幫忙,用Tomcat用戶在tmp下創建這個文件夾。創建好之後,我再一試就可以。看似這個問題已經完美的解決了。但是,我的疑問還是沒有被解答。

解決疑問

  1. 上傳文件爲啥會操作這個文件呢?
  2. /tmp/tomcat.46678487236333023.8030/work/Tomcat/localhost/extend 是啥時候創建的呢?
    帶着這幾個疑問,我繼續google。

第一個問題 上傳文件爲啥會操作這個文件呢?

SpringBoot的文件上傳處理是基於Servlet實現的,Content-type是multipart/form-data, boundary=“boundaryStr”,在Servlet2.5及早期版本之前,文件上傳需要藉助commons-fileupload組件來實現。從Servlet 3.0規範之後,提供了對文件上傳的原生支持,進一步簡化了應用程序的實現。
以Tomcat爲例,在文件上傳之後會通過將數據寫入臨時文件,最終將文件實體傳參到應用層,如下:
在這裏插入圖片描述
Tomcat實現了Servlet3.0規範,通過ApplicationPart對文件上傳流實現封裝,其中,DiskFileItem描述了上傳文件實體,在請求解析時生成該對象,需要關注的是,DiskFileItem聲明瞭一個臨時文件,用於臨時存儲上傳文件的內容,SpringMVC對上層的請求實體再次封裝,最終構造爲MultipartFile傳遞給應用程序。
臨時文件;
臨時文件的路徑定義:

{temp_dir}/upload_xx_xxx.tmp

temp_dir是臨時目錄,通過系統屬性java.io.tmpdir指定,默認值爲;

操作系統 路徑
windows C:\Users{username}\AppData\Local\Temp\
Linux /tmp

第一個問題解決了,接着就是第二個問題,既然,上傳需要用到這個文件夾,那麼這個文件夾是啥時候生成的呢?

第二個問題 {temp_dir}/upload_xx_xxx.tmp 是啥時候創建的呢?

很顯然,上傳的時候沒有生成文件夾,不然不會報is not valid那就只有可能是項目啓動的時候生成的
爲了驗證我的想法:我在開發服務器進行了下模擬,首先,把tmp下所有tomcat爲前綴的文件夾都刪除了。然後重啓應用。重啓後查看。
在這裏插入圖片描述
重啓之後我發現/tmp下新生成了tomcat.5195341930943680007.8030這個文件夾。跟原來的tomcat.46678487236333023.8030不一致。這麼說每次項目啓動之後就會生成一個新的tomcat.xxxx地址。爲了驗證我的猜想,我又把項目重啓了一遍。再觀察,果然如下,結果如下圖所示:
在這裏插入圖片描述

解決問題

最終解決這個問題呢?一個保險的方法就是指定上傳文件的臨時文件夾。在SpringBoot下只需要如下配置:

spring:
	  servlet:
		multipart:
		  #開啓swagger
		  enabled: true
		  #最大上傳文件大小
		  max-file-size: 5MB
		  #臨時文件夾
		  location: /srv/www/extend

或者使用配置類,如下:

@Configuration
    public static class FileConfig {
        @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setMaxFileSize(DataSize.parse("5MB"));
        factory.setMaxRequestSize(DataSize.parse("5MB"));
        factory.setLocation("/srv/www/extend");
        return factory.createMultipartConfig();
    }
    }

linux 命令查缺補漏

命令 作用 舉例
rm -rf 默默的刪除文件,慎用 rm -rf tomcat.* 刪除所有前綴爲tomcat. 的文件夾
chmod 給文件賦予權限
ll 查看該目錄下所有文件夾以及文件的屬性
rz -be 用於上傳大文件
sz 用於下載文件 sz log.text 下載log.text文件
adduser 用於創建新用戶 adduser test
su 切換用戶 su root 切換到root用戶

chmod

我們先用 ll 查看文件,結果如下:

總用量 4
drwxr-xr-x 3 test test 4096 6月  11 15:06 work

PS: 用 ls -ld 文件夾名 例如:ls -ld work/ 可以指定查看work文件夾的屬性。結果跟用ll一樣的。

drwxr-xr-x 3 test test 4096 6月 11 15:06 work
用戶權限 連接數 所有者 用戶組 文件大小 修改日期 文件夾名

文件類型與權限
在這裏插入圖片描述

  • r:表示用戶可以查看該目錄下的內容,即可以使用"ls"命令
  • w:表示用戶可以修改該目錄下的內容,包括增加、刪除、重命名等
  • x: 表示用戶可以進入該目錄,既可以使用"cd"命令
    我們不僅可以用rwx表示文件的權限,還可以同數字表示,具體如下:
  • r:4
  • w:2
  • x:1
    每種身份各自的三個權限(r、w、x)分數是需要累加的,例如當權限爲[-rwxrwxr-x]分數則是:
    owner=rwx=4+2+1=7
    group=rwx=4+2+1=7
    others=r-x=4+1=5
    所以,該文件的權限數字就是 775。

總結

本文由一個線上問題,將自己的種種不足都暴露出來了。挺好的。

參考

補習系列(11)-springboot 文件上傳原理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章