Spring MVC使用ResponseEntity<Resource>文件下載,文件損壞問題

我們實(shí)現(xiàn)http文件下載,主要是在響應(yīng)頭中讓Content-Disposition的值為attachment(意味著消息體應(yīng)該被下載到本地;大多數(shù)瀏覽器會(huì)呈現(xiàn)一個(gè)“保存為”的對(duì)話框,將filename的值預(yù)填為下載后的文件名,假如它存在的話)

之前我都是使用在下載的方法里注入HttpServletResponse,然后往response里寫數(shù)據(jù),然后設(shè)置Header中加入Content-Disposition

今天剛好又需要寫一個(gè)下載的功能,然而我不想注入什么HttpServletResponse,那樣很不美觀,從網(wǎng)上的資料了解到了ResponseEntity,從spring MVC的文檔中了解到這個(gè)類就像@ResponseBody,但是多了響應(yīng)頭和狀態(tài)碼。剛好下載文件是需要設(shè)置響應(yīng)頭的,所以就用了這個(gè)。

然而構(gòu)造方法是這樣的

public ResponseEntity(T body, MultiValueMap<String, String> headers, HttpStatus status) {
        super(body, headers);
        Assert.notNull(status, "HttpStatus must not be null");
        this.status = status;
    }

這個(gè)body能不能直接用File呢,答案是不能。我試著下載了一個(gè)txt文件,確實(shí)會(huì)下載一個(gè)文件,但是這個(gè)文件的內(nèi)容是文件的路徑。我猜估計(jì)是掉了File的toString方法。具體干了啥,感興趣的可以看看AbstractMessageConverterMethodProcessorwriteWithMessageConverters,debug一遍就清楚了。

不能直接用File,那該用什么呢,習(xí)慣性的在stackoverflow上搜了一下,有用Resource的,也有用Byte[]的。那么兩者有啥區(qū)別呢。
用Resource,你返回的時(shí)候還是依賴文件的,你的Controller在返回之后還要進(jìn)行一系列的操作,如果在這之前文件被刪了,那么下載下拉的文件就是損壞的。一開始我是這么干的

try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.valueOf("application/force-download"));
            headers.set("Content-Disposition", "attachment;fileName*=UTF-8''" + UriUtils.encode(file.getName(), "UTF-8"));
            return new ResponseEntity<Resource>(new FileSystemResource(file), headers, HttpStatus.OK);
        } finally {
            // 這里刪除文件
        }

這個(gè)finally會(huì)在return語句的計(jì)算之后返回之前執(zhí)行。所以文件被寫到響應(yīng)之前就被刪了。所以我決定采用這種方式

 try(FileInputStream fi = new FileInputStream(file)) {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.valueOf("application/force-download"));
            headers.set("Content-Disposition", "attachment;fileName*=UTF-8''" + UriUtils.encode(file.getName(), "UTF-8"));
            return new ResponseEntity<byte[]>(IOUtils.toByteArray(fi), headers, HttpStatus.OK);
        } finally {
            // 這里刪除文件
        }

文件流要關(guān)閉喲,希望大家都用try-with-resources,這都9102年了答應(yīng)我不要在finally里面close然后又try-catch了,我實(shí)在看不下去了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容