內(nèi)容參考 Paul Deck 著的《Spring MVC學(xué)習(xí)指南1 2版》
將文件這樣的資源發(fā)送到瀏覽器滓玖,需要在controller中完成以下工作:
- 在請(qǐng)求的處理方法中使用void返回類(lèi)型坪哄,并在方法中添加
HttpServletResponse
- 設(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ě))念祭。 - 設(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