首先说下场景,pdf文件在linux根目录下比如/nasdata/xxx.pdf,所以前端无法直接访问了,我采用的servlet请求后返回给前端文件流的形式,但试了很多方法PC端能正常,而手机端点击后,不知道是不是被拦截还是什么,显示的未知文件。
用不太来,这个文本,希望大佬说下怎么才能在手机端下载?(必须那个路径,这个刚好是公司的类似外接硬盘)
servlet中post请求代码如下:
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp){
// String src=req.getSession().getServletContext().getRealPath("/");
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("application/pdf;charset=UTF-8");
// resp.setContentType("multipart/form-data");
resp.setHeader("Content-Disposition", "attachment;filename=a.pdf");
String path = req.getParameter("path");
File w2 = new File(path);
logger.info("pdf path:" + w2.getPath());
FileInputStream fs;
try {
fs = new FileInputStream(w2);
BufferedInputStream bs = new BufferedInputStream(fs);
PrintWriter outW = resp.getWriter();
byte buffBytes[] = new byte[3072];
/**
* 这里的新建的byte数组的大小必须是24的倍数,原因看下base64的原理
**/
int read = 0;
while ((read = bs.read(buffBytes)) != -1) {
String strTemp = new sun.misc.BASE64Encoder().encode(Arrays
.copyOfRange(buffBytes, 0, read));
outW.print(strTemp);
}
if (bs != null) {
try {
bs.close();
} catch (IOException e1) {
logger.error(e1.getMessage(), e1);
}
}
} catch (Exception e) {
logger.info("pdf出错");
logger.error(e.getMessage(), e);
}
}
js中请求:
$.ajax({
type: "post",
async: false,
url: projectName+"/PdfDownloadServlet?path="+path,
success: function (data) {
// var blob = new Blob([base64toBlob(data)], {type: "application/pdf;charset=utf-8"});
// saveAs(blob, "CF1002.pdf");
let URL = base64toBlob(data);
var reader = new FileReader();
reader.readAsDataURL(URL);
alert(URL);
reader.onload = function (e) {
// 兼容IE
if (window.navigator.msSaveOrOpenBlob) {
var bstr = atob(e.target.result.split(",")[1]);
var n = bstr.length;
var u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
var blob = new Blob([u8arr]);
window.navigator.msSaveOrOpenBlob(blob,'asd.pdf');
} else {
// 转换完成,创建一个a标签用于下载
var a = document.createElement('a');
a.download = 'asd.pdf';
a.href = e.target.result;
a.setAttribute("id", "export")
document.getElementById("purchaseManage").append(a); // 修复firefox中无法触发click
a.click();
document.getElementById("export").remove();
}
}
},error: function(e){
// 进入到了error,成功打印出信息,也刷新了list,
// 但是edit的弹窗页面和询问框没有正确关闭
console.log(e);
alert(e);
}
});
url: projectName+"/PdfDownloadServlet?path="+encodeURIComponent(path)
试试编码一下。
好的我试试看
还是一样的,传回去路径是正常的
@代码可乐: 下载一般不都是直接一个a 链接触发一个get请求就可以了,你这用一个post请求干什么?
@代码可乐: 还有一点不理解,下载文件直接输出byte就可以了,为什么要转成base64?
@blackheart: 因为文件在linux根路径下啊,公司的项目的外接硬盘吧,用来放大文件这些吧,项目路径下要是能放早好了。。。。
@代码可乐: 和文件放在哪有什么关系?没关系啊
@blackheart: 大佬可以给下思路吗?后端返回什么形式的数据,前端拿什么接收并转换?
@代码可乐: 不用转换啊,后端直接把fs = new FileInputStream(w2);的fs写入到httpresponse的相应流即可。
@blackheart: 好的我试试
@代码可乐:
protexted void doGet(HttpServletRequest req, HttpServletResponse resp) {
String fileName = req.getParameter("fileName");
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("application/pdf;charset=UTF-8");
resp.setHeader("Content-Disposition", "attachment;filename=a.pdf");
File file = new File("/你的文件存放目录/" + fileName);
try (InputStream fileInputStream = new FileInputStream(file);
OutputStream httpOutputStream = resp.getOutputStream();) {
int length = 0;
byte[] buffer = new byte[4096];
while ((length = fileInputStream.read(buffer)) != -1) {
httpOutputStream.write(buffer, 0, length);
}
resp.setHeader("Content-Length", String.valueOf(file.length()));
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
@blackheart: 我先试试哈谢谢大佬
大佬前端接收到data为空,是不是后端哪里有问题
@代码可乐: 还要前端发起ajax干什么?直接一个a标签或者window.open(url)就可以了啊。 对了url改成get方式访问。
@代码可乐: 还有,你这样传递path直接下载太不安全了,相当于把你的服务器的所有目录的所有文件数据拱手想让,肯定不能通过参数来随意指定文件路径的。 上面代码给你修改了一下,起码限定一下目录。参数上只传递文件名即可。
@blackheart: 前端我是按钮click时间里写直接window.open(项目名/servlet名?参数)?我再看下这个pdf好像不能正常打开
浏览器直接访问完整的url呢?
@blackheart:可以直接访问,但是看了那个pdf是0kb
@代码可乐: 设置content-length后就可以了,上面的代码我给你更新过了。
@blackheart: 可以了感谢大佬