Spring MVC 文件下載及中文文件名亂碼解決

內(nèi)容參考 Paul Deck 著的《Spring MVC學(xué)習(xí)指南1 2版》

將文件這樣的資源發(fā)送到瀏覽器滓玖,需要在controller中完成以下工作:

  1. 在請(qǐng)求的處理方法中使用void返回類(lèi)型坪哄,并在方法中添加HttpServletResponse
  2. 設(shè)置Content-Type, Content-Type就是常說(shuō)的MIME類(lèi)型,將響應(yīng)的內(nèi)容類(lèi)型設(shè)為文件的內(nèi)容類(lèi)型势篡。Content-Type header 在某個(gè)實(shí)體的body中定義數(shù)據(jù)類(lèi)型, 包含media type(媒體類(lèi)型)和subtype identifiers(子類(lèi)標(biāo)識(shí)符)翩肌。訪問(wèn)http://www.iana.org/assignments/media-types 以了解更多的標(biāo)準(zhǔn)內(nèi)容類(lèi)型(standard content types)。如果不清楚如何設(shè)置Content-Type,要達(dá)到下載資源的效果禁悠,可以將Content-Type設(shè)置為application/octet-stream(不區(qū)分大小寫(xiě))念祭。
  3. 設(shè)置一個(gè) HTTP response header: Content-Disposition, 值為attachment; filename=fileName, 這個(gè)fileName就是下載文件后的文件名,這個(gè)文件名有可能會(huì)和這里設(shè)置fileName不一樣碍侦。

上碼:
方式1:讀取文件作為FileInputStream, 將內(nèi)容加載到一個(gè)字節(jié)數(shù)組粱坤。隨后獲取HttpServletResponse的OutputStream,并調(diào)用write方法傳入字節(jié)數(shù)組瓷产。
方式2:使用Java NIO's Files.copy()方法:

Path file = Paths.get(...);
Files.copy(file, response.getOutputStream());

這樣代碼少比规、而且運(yùn)行得更快。

看碼吧:

@Controller
public class DownloadController {   
    @RequestMapping(value="/download-resource")
    public void downloadResource(HttpServletRequest servletRequest, HttpServletResponse response) {
       // 文件保存在/WEB_INF/data目錄下 
        String dataDirectory = request.
                getServletContext().getRealPath("/WEB-INF/data");
        File file = new File(dataDirectory, "sunny.pdf");
        if (file.exists()) {
            response.setContentType("application/pdf");
            response.addHeader("Content-Disposition", 
                    "attachment; filename=sunny.pdf");
            byte[] buffer = new byte[1024];
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            // if using Java 7, use try-with-resources
            try {
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                OutputStream os = response.getOutputStream();
                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer, 0, i);
                    i = bis.read(buffer);
                }
            } catch (IOException ex) {
                // do something, 
                // probably forward to an Error page
            } finally {
                if (bis != null) {
                    try {
                        bis.close();
                    } catch (IOException e) {
                    }
                }
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                    }
                }
            }
        }
    }

    @RequestMapping(value="/download-resource1")
    public void downloadResource(HttpServletRequest servletRequest, HttpServletResponse response) {
        String dataDirectory = request.
                getServletContext().getRealPath("/WEB-INF/data");
        Path file = Paths.get(dataDirectory, "sunny.pdf");
        if (Files.exists(file)) {
            response.setContentType("application/pdf");
            String fileName = "sunny.pdf";
            response.addHeader("Content-Disposition", 
                    "attachment; filename=" + fileName);
/*
如果文件名有中文的話(huà)拦英,進(jìn)行URL編碼蜒什,讓中文正常顯示
response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
*/
            try {
                Files.copy(file, response.getOutputStream());
            } catch (IOException ex) {
            }
        }
    }
}

針對(duì)中文文件名下載后亂碼分析:

上面有說(shuō)

response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));

這行代碼是能解決中文文件名亂碼問(wèn)題的,但在Safari瀏覽器下下載的中文文件名還是亂碼的疤估,下面提供一個(gè)解決方案灾常,看代碼:

@RequestMapping(value = "/faq")
    public void downloadFAQPdf(HttpServletResponse response) throws Exception {
        String fileName = "幫助說(shuō)明.pdf";
// 獲取classpath下的文件
        URL url = UserController.class.getClassLoader().getResource("data/" + fileName);
        Path file = Paths.get(url.toURI());

        fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());

// 解決中文文件名亂碼關(guān)鍵行 
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"; filename*=utf-8''" + fileName);

        Files.copy(file, response.getOutputStream());
    }

具體原因我就不細(xì)說(shuō)了霎冯,參看下面這個(gè)鏈接(有詳細(xì)的描述):
http://ju.outofmemory.cn/entry/133400

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市钞瀑,隨后出現(xiàn)的幾起案子沈撞,更是在濱河造成了極大的恐慌,老刑警劉巖雕什,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缠俺,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡贷岸,警方通過(guò)查閱死者的電腦和手機(jī)壹士,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)偿警,“玉大人躏救,你說(shuō)我怎么就攤上這事∶簦” “怎么了盒使?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)七嫌。 經(jīng)常有香客問(wèn)我少办,道長(zhǎng),這世上最難降的妖魔是什么诵原? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任英妓,我火速辦了婚禮,結(jié)果婚禮上皮假,老公的妹妹穿的比我還像新娘。我一直安慰自己骂维,他們只是感情好惹资,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著航闺,像睡著了一般褪测。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上潦刃,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天侮措,我揣著相機(jī)與錄音,去河邊找鬼乖杠。 笑死分扎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的胧洒。 我是一名探鬼主播畏吓,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼墨状,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了菲饼?” 一聲冷哼從身側(cè)響起肾砂,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宏悦,沒(méi)想到半個(gè)月后镐确,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饼煞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年源葫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片派哲。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡臼氨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芭届,到底是詐尸還是另有隱情储矩,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布褂乍,位于F島的核電站持隧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏逃片。R本人自食惡果不足惜屡拨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望褥实。 院中可真熱鬧呀狼,春花似錦、人聲如沸损离。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)僻澎。三九已至貌踏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間窟勃,已是汗流浹背祖乳。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留秉氧,地道東北人眷昆。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親隙赁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子垦藏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)伞访,斷路器掂骏,智...
    卡卡羅2017閱讀 134,651評(píng)論 18 139
  • 本文包括:1、文件上傳概述2厚掷、利用 Commons-fileupload 組件實(shí)現(xiàn)文件上傳3弟灼、核心API——Dis...
    廖少少閱讀 12,546評(píng)論 5 91
  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線(xiàn)程,因...
    小菜c閱讀 6,401評(píng)論 0 17
  • 《裕語(yǔ)言》速成開(kāi)發(fā)手冊(cè)3.0 官方用戶(hù)交流:iApp開(kāi)發(fā)交流(1) 239547050iApp開(kāi)發(fā)交流(2) 10...
    葉染柒丶閱讀 26,638評(píng)論 5 19
  • 1月2號(hào)冒黑, 住在key largo的第一天田绑,我們?nèi)ヒ粋€(gè)海灘游泳。這地兒設(shè)計(jì)的還挺“貼心”抡爹,專(zhuān)門(mén)兒修了一條小f...
    AdamXiao閱讀 261評(píng)論 0 2