在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