SpringBoot: 淺談文件上傳和訪問的坑 (MultiPartFile)

本次的項目環(huán)境為 SpringBoot 2.0.4, JDK8.0. 服務(wù)器環(huán)境為CentOS7.0, Nginx的忘了版本.


前言


SpringBoot使用MultiPartFile接收來自表單的file文件,然后進行服務(wù)器的上傳是一個項目最基本的需求,我以前的項目都是基于SpringMVC框架搭建的,所以在使用SpringBoot的時候進行MultiPartFile上傳遇到了坑,這里說一下,其中主要包含兩個坑點.

  • 使用transferTo()方法寫入File時找不到文件路徑.

  • 訪問文件時Nginx的403 forbidden問題.


使用transferTo()方法寫入File時找不到文件路徑


在我們解決問題之前,我們先看一下封裝的上傳方法以及報錯日志.

    public static final String BASE_PATH = "/test/";

    public static String upload(MultipartFile imageFile) {

        if (imageFile.isEmpty()) {
            return null;
        }
        String filename = imageFile.getOriginalFilename();
        
        String ext= null;
        if(filename.contains(".")){
            ext = filename.substring(filename.lastIndexOf("."));
        }else{
            ext = "";
        }
        
        String uuid =  UUID.randomUUID().toString().replaceAll("-", "");
        String nfileName = uuid + ext;
        String dirPath = DateFormatUtils.format(new Date(), "yyyyMMdd");
        String filepath = BASE_PATH.endsWith("/") ? BASE_PATH+dirPath : BASE_PATH+"/"+dirPath;
        File targetFile = new File(filepath, nfileName);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        } else {
            targetFile.delete();
        }
        try {
            imageFile.transferTo(targetFile);
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        String accessUrl =  "/"+nfileName;
        logger.debug("上傳文件成功 URL:" + nfileName);
        return accessUrl;
    }

報錯日志如下所示.

java.io.IOException: java.io.FileNotFoundException: /test/20181025/be3676dffca94c6dac5e96a1a41dcd97.jpg (Is a directory)
    at org.apache.catalina.core.ApplicationPart.write(ApplicationPart.java:122)
    at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.transferTo(StandardMultipartHttpServletRequest.java:255)
    at com.dong.runline.common.utils.UploadUtils.upload(UploadUtils.java:56)
    at com.dong.runline.controller.TimeLineController.createTimeLineAction(TimeLineController.java:55)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)

這里就出現(xiàn)了java.io.FileNotFoundException錯誤,這是怎么造成的呢?,通過Debug下的斷點我們發(fā)現(xiàn)是下面的位置發(fā)生了錯誤.

這里我用的本地環(huán)境進行了測試,發(fā)現(xiàn)本地創(chuàng)建了這個樣的一個路徑,最后的圖片被創(chuàng)建成一個這樣的路徑.

在SpringMVC環(huán)境下并沒有這樣的問題,在SpringBoot卻出現(xiàn)了這樣的問題,那么到底怎么造成的呢?網(wǎng)上的很多博客寫到,通過查詢transferTo()方法源碼找到了問題關(guān)鍵所在.

@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
    this.part.write(dest.getPath());
}

我們接著進入write()方法.

    @Override
    public void write(String fileName) throws IOException {
        File file = new File(fileName);
        if (!file.isAbsolute()) {
            file = new File(location, fileName);
        }
        try {
            fileItem.write(file);
        } catch (Exception e) {
            throw new IOException(e);
        }
    }

這時候我們看到如果!file.isAbsolute()成立,也就是我們沒有使用絕對路徑,那么file = new File(location,fileName);會在原來的基礎(chǔ)上加上location路徑.這就是原因所在,解決起來也很方便,網(wǎng)上總共有兩種方案.

  • 使用絕對路徑
  • 修改location的值

第一種方案我們就不過多解釋了,我們看一下如何修改location的值.我們只需要在啟動類中注入如下Bean即可.把路徑指向我們的存儲路徑.

    @Bean
    MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setLocation(UploadUtils.BASE_PATH);
        return factory.createMultipartConfig();
    }

然后我們再修改下UploadUtils中的創(chuàng)建File方法即可.

        String uuid =  UUID.randomUUID().toString().replaceAll("-", "");
        String nfileName = uuid + ext;
        File targetFile = new File(nfileName);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        } else {
            targetFile.delete();
        }


訪問文件時Nginx的403 forbidden問題


所謂的Nginx的403錯誤其實就是訪問權(quán)限錯誤.當前用戶沒有訪問該資源的權(quán)限,這樣理解的話,我們就有兩種方案可行.一,降低文件訪問的權(quán)限等級.二,升高用戶的訪問權(quán)限.下面我們一個一個來看一下如何進行實現(xiàn).

  • 降低文件訪問的權(quán)限等級

降低文件的訪問權(quán)限,我們只需要用到 chmod指令即可.這里簡單解釋一下chmod指令.

在Mac的使用過程中我們也經(jīng)常會修改 某個文件的權(quán)限,例如:

chmod 777 file

如果如上設(shè)置的話,那么任何一個用戶都會對這個file文件擁有全部權(quán)限.

那么為什么是三位數(shù)呢?這是因為這三位數(shù)分別代表著檔案擁有者User、群組Group、其他Other三者的權(quán)限.也就是說擁有者的權(quán)限等級為7,群組的權(quán)限等級為7,其他權(quán)限等級也為7.

那么為什么是7呢?這是因為一個linux文件總共有三種權(quán)限,分別是讀r,寫w,操作x.對應(yīng)的值分別是4,2,1.當一個用戶對某個文件擁有7的數(shù)值時,這時候為4+2+1,也就是說他擁有該文件全部的權(quán)限.

上面說了 chmod指令的如何使用,那么接下來我們就可以對服務(wù)器的文件使用chmod 664 file指令,然后降低文件訪問的權(quán)限等級.使全部用戶都擁有文件的訪問權(quán)限.但是問題來了,難道用戶上傳一次,我們就需要手動修改一次文件的權(quán)限,這顯然是不正確的,那么我們該怎么辦呢?這時候我們就需要提高用戶的訪問權(quán)限了.

  • 升高用戶的訪問權(quán)限

提高用戶的訪問權(quán)限,這里其實是修改Nginx的啟動者,我們把啟動者設(shè)置為最多權(quán)限者,那么我們就可以訪問到文件了.

首先我們先看是誰啟動了Nginx需要用到如下的指令.

 ps aux | grep "nginx: worker process" | awk '{print $1}'

這里我已經(jīng)做了修改,截圖如下所示.

本來要是不對Nginx的配置進行任何設(shè)置訪問的話,那么第一個root應(yīng)該為nobody,也就是Nginx的啟動者.先前已經(jīng)使用** ls -l file **指令查詢了文件的權(quán)限情況,root 擁有讀寫權(quán)限,other沒有任何權(quán)限.所以我們要把啟動者改為root即可.

打開Nginx配置文件所在的位置,{nginx}表示你的nginx安裝路徑.

vi {nginx}/conf/nginx.conf

添加啟動者,如下所示.

user root

返回到sbin目錄中,準備檢測配置文件和重新啟動Ngnix.

cd ../sbin/

檢測配置文件的正確性

./nginx -t

檢測沒有任何問題,重新啟動

./nginx -s reload

這時候即可正常訪問到文件了.


結(jié)語


這篇博客算是日常的問題收集吧,整理一下.沒什么可多說的,就是搞事.歡迎關(guān)注騷棟



?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末躬贡,一起剝皮案震驚了整個濱河市菲饼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绷耍,老刑警劉巖六敬,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異升筏,居然都是意外死亡,警方通過查閱死者的電腦和手機瘸爽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門您访,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人剪决,你說我怎么就攤上這事灵汪。” “怎么了柑潦?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵享言,是天一觀的道長。 經(jīng)常有香客問我渗鬼,道長览露,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任譬胎,我火速辦了婚禮差牛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘堰乔。我一直安慰自己偏化,他們只是感情好,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布镐侯。 她就那樣靜靜地躺著夹孔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上搭伤,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天只怎,我揣著相機與錄音,去河邊找鬼怜俐。 笑死身堡,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的拍鲤。 我是一名探鬼主播贴谎,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼季稳!你這毒婦竟也來了擅这?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤景鼠,失蹤者是張志新(化名)和其女友劉穎仲翎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铛漓,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡溯香,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了浓恶。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玫坛。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖包晰,靈堂內(nèi)的尸體忽然破棺而出湿镀,到底是詐尸還是另有隱情,我是刑警寧澤伐憾,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布勉痴,位于F島的核電站,受9級特大地震影響塞耕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嘴瓤,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一扫外、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧廓脆,春花似錦筛谚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春吮铭,著一層夾襖步出監(jiān)牢的瞬間时迫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工谓晌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掠拳,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓纸肉,卻偏偏與公主長得像溺欧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子柏肪,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容