ZK框架檔案下載檔名亂碼問題(空格,#截斷)解決
在Java的web開發中,檔案下載功能的檔名檔名亂碼問題是經常遇到的。
對於這個問題,不同的瀏覽器,解決的方法不太一樣。
IE的話,通過URLEncoder對filename進行UTF8編碼。
而其他的瀏覽器(firefox、chrome、safari、opera),則要通過位元組轉換成ISO8859-1了。
所以對此要在後臺獲取瀏覽器型別(主要識別是否是IE)從而使用不同的編碼方法
//檔案下載
@SuppressWarnings({ "unchecked", "deprecation" })
@Command
public void fileDownLoad() throws UnsupportedEncodingException
{
if(checkListitems==null||checkListitems.size ()==0)
{
Messagebox.show("請選擇下載的檔案","提示", Messagebox.OK, Messagebox.INFORMATION);
return;
}
Iterator it=checkListitems.iterator();
Map<String,Object> selectMap=(Map) it.next();
String filePath=selectMap.get("file_path")+"" ;
String fileExtension=filePath.substring(filePath.lastIndexOf("."));
String enCodeName=(String)selectMap.get("file_name");
if(!enCodeName.endsWith(fileExtension))
{
enCodeName=enCodeName+fileExtension;
}
//檔案亂碼問題相容IE
HttpServletRequest request =(HttpServletRequest) Executions.getCurrent ().getNativeRequest();
String header = request.getHeader("User-Agent").toUpperCase();
if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
enCodeName = URLEncoder.encode(enCodeName, "utf-8");
enCodeName = enCodeName.replace("+", "%20"); //IE下載檔名空格變+號問題
enCodeName = enCodeName.replace("#", "%23"); //遇到#截斷問題
}
else
{
enCodeName=new String(enCodeName.getBytes("UTF-8"), "ISO-8859-1");
//enCodeName = enCodeName.replace("#", "%23");//這裡設定不成功
}
File file=new File(MisUtils.getWebRootDir()+filePath);
InputStream is=null;
try {
is = new FileInputStream(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Messagebox.show("未找到對應檔案!", "錯誤", Messagebox.OK, Messagebox.ERROR);
return;
}
if(file.exists())
{
//Filedownload. save(is, null, enCodeName);
AMedia media=new AMedia(enCodeName, fileExtension.substring(1), null, is);
Clients.response(new AuDownload(Executions.getCurrent().getDesktop().getDownloadMediaURI(
media, enCodeName).replace("+", "%2B").replace("#", "%23")));
}
}
到此IE瀏覽器可以輕鬆解決檔名包含#或空格轉成+號問題
但是,chrome等瀏覽器使用的是另外一種編碼方式ISO8859-1
這個編碼方式並不對+或#編碼,導致檔案下載時伺服器後臺還是對+或#當成了特殊的符號處理,從而導致下載檔名不對或被截斷。
在此附上相關特殊字元的十六進位制編碼
url出現了有+,空格,/,?,%,#,&,=等特殊符號的時候,可能在伺服器端無法獲得正確的引數值,如何是好?
解決辦法
將這些字元轉化成伺服器可以識別的字元,對應關係如下:
URL字元轉義
用其它字元替代吧,或用全形的。
+ URL 中+號表示空格 %2B
空格 URL中的空格可以用+號或者編碼 %20
/ 分隔目錄和子目錄 %2F
? 分隔實際的URL和引數 %3F
% 指定特殊字元 %25
# 表示書籤 %23
& URL 中指定的引數間的分隔符 %26
= URL 中指定引數的值 %3D
由於利用chrome下載時使用的是ISO-8859-1對#和+並沒有編碼所以利用Filedownload. save(is, null, enCodeName);
伺服器還是對特殊符號解碼導致錯誤
為了解決這個問題需要從新使用新的方法再給特殊字元編碼(注意在ISO8859-1編碼後把#replace到%23不成功)
解決如下(把filedownload替換成下面程式碼):
//enCodeName為檔名,第二個引數是副檔名如txt,第三個引數是contenType如text/plain可使用null(取預設),第四個是檔案的流
AMedia media=new AMedia(enCodeName, fileExtension.substring(1), null, is);
//對download的uri所含有的特殊字元進行替換編碼
Clients.response(new AuDownload(Executions.getCurrent().getDesktop().getDownloadMediaURI(
media, enCodeName).replace("+", "%2B").replace("#", "%23")));
在這裡丟擲一個疑問:如果普通的JavaWeb(不是使用ZK)使用非IE下載該如何解決這個問題?(
response.setHeader("Content-disposition", "attachment; filename=\"" + fileName + "\"");
response.setHeader("Content-Length", String.valueOf(fileLength));
)
參考:
http://blog.csdn.net/lisehouniao/article/details/52550539
https://stackoverflow.com/questions/47549771/zk8-filedownload-save-cut-filenames#
感謝ZK的Jean Yen ,在這裡在此謝謝您的幫助,祝願ZK越來越好
Thanks,
Hungly