普通的<download>
标签在谷歌和其他浏览器上都没问题,但是项目中,用户有很多是使用IE浏览器的,版本是11.1,下载PDF功能就失效,怎么都不行,搞了很久,用微软说明的Blob搭配window.navigator.msSaveOrOpenBlob或window.navigator.msSaveBlob函数可以解决。
步骤:
1.前端把pdf文件链接地址传到后台,后台下载转成流返回给前端,
2、前端再保存成为文件
**
前端:
**
</script>
// 下载 pdf pdfSrc为pdf的网络地址,格式为https:xxxxx/xx.pdf
function getDownLoadPdf(pdfSrc){
event.stopPropagation()
if (!!window.ActiveXObject || "ActiveXObject" in window){
//是 IE 浏览器
$.ajax({
type : 'GET',
async : false,
url : '${request.contextPath}/public/downLoadPdf?pdfSrc='+pdfSrc,
success : function(reponse) {
var code = reponse.replace(/[\n\r]/g, '');
var raw = window.atob(code);
let rawLength = raw.length;
//转换成pdf.js能直接解析的Uint8Array类型
let uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
//获取到了blob对象
let blob=new Blob([uInt8Array], {type: 'application/pdf'});
var uuid = getUuid().replace("-","");
var fileName=uuid+'.pdf';
//打开或保存
window.navigator.msSaveOrOpenBlob(blob, fileName);
//只保存
// window.navigator.msSaveBlob(blob, fileName);
layer.close(index);
},
error : function(xhr, type) {
layer.close(index);
}
});
}else{
var index = layer.msg('下载中', {
icon: 16,
shade: 0.01,
time: 1000 * 10,
offset: ['50%', '25%'],
});
$.ajax({
type : 'GET',
async : false,
url : '${request.contextPath}/public/downLoadPdf?pdfSrc='+pdfSrc,
success : function(reponse) {
var code = reponse.replace(/[\n\r]/g, '');
var raw = window.atob(code);
let rawLength = raw.length;
//转换成pdf.js能直接解析的Uint8Array类型
let uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
//获取到了blob对象
let blob=new Blob([uInt8Array], {type: 'application/pdf'});
//获取当前url,直接放到iframe就能用,下载同理
let blobURL = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = blobURL;
a.download = '';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(blobURL);
document.body.removeChild(a)
layer.close(index);
},
error : function(xhr, type) {
layer.close(index);
}
});
}
}
function getUuid() {
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
}
</script>
后台代码
省略了controller,自己写一个
public String downloadPdfAndEncoder(String fileUrl) {
logger.info("开始下载并转换pdf文件");
Base64.Encoder encoder = Base64.getEncoder();
DataInputStream in = null;
BufferedInputStream bin = null;
ByteArrayOutputStream baos = null;
BufferedOutputStream bout = null;
try {
if(fileUrl.contains("https://")) {
SSLContext sslcontext = SSLContext.getInstance("SSL", "SunJSSE");
sslcontext.init(null, new TrustManager[]{new X509TrustUtiil()}, new java.security.SecureRandom());
URL url = new URL(fileUrl);
HostnameVerifier ignoreHostnameVerifier = new HostnameVerifier() {
public boolean verify(String s, SSLSession sslsession) {
System.out.println("WARNING: Hostname is not matched for cert.");
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier);
HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext.getSocketFactory());
HttpsURLConnection urlCon = (HttpsURLConnection) url.openConnection();
urlCon.setConnectTimeout(6000);
urlCon.setReadTimeout(6000);
int code = urlCon.getResponseCode();
if (code != HttpURLConnection.HTTP_OK) {
throw new Exception("文件读取失败");
}
in = new DataInputStream(urlCon.getInputStream());
} else {
URL url = new URL(fileUrl);
// 创建链接
HttpURLConnection urlCon = (HttpURLConnection) url.openConnection();
urlCon.setRequestMethod("GET");
urlCon.setConnectTimeout(5000);
in = new DataInputStream(urlCon.getInputStream());
}
//在文件输出流上安装节点流(更大效率读取)
bin = new BufferedInputStream(in);
// 创建一个新的 byte 数组输出流,它具有指定大小的缓冲区容量
baos = new ByteArrayOutputStream();
//创建一个新的缓冲输出流,以将数据写入指定的底层输出流
bout = new BufferedOutputStream(baos);
byte[] buffer = new byte[1024];
int len = bin.read(buffer);
while(len != -1){
bout.write(buffer, 0, len);
len = bin.read(buffer);
}
//刷新此输出流并强制写出所有缓冲的输出字节,必须这行代码,否则有可能有问题
bout.flush();
byte[] bytes = baos.toByteArray();
// //sun公司的API
// return encode.encodeBuffer(bytes).trim();
//apache公司的API
//return Base64.encodeBase64String(bytes);
logger.info("下载并转换pdf文件完成");
return encoder.encodeToString(bytes);
} catch (Exception e) {
logger.info("开始下载并转换pdf失败");
e.printStackTrace();
} finally {
try {
in.close();
bin.close();
//关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException
//baos.close();
bout.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}