使用java的 htpUrlConnection post请求 下载pdf文件,然后输出到页面进行预览和下载
使用java的 htpUrlConnection post请求 下载pdf文件,然后输出到页面进行预览和下载
2018年06月07日 10:42:26 守望dfdfdf 阅读数:235 标签: java httpUrlConnection post 更多
个人分类: 工作 问题
编辑
版权声明:本文为博主原创文章,转载请注明文章链接。 https://blog.csdn.net/xiaoanzi123/article/details/80596524
因为pdf文件存在第三方系统,只能通过接口调用去获取文件。第三方接口返回的是response.getOutPutStream.write(byte[])的响应流。我所涉及的代码逻辑就是:
无论是页面预览pdf的请求还是下载文件的请求,都访问本方法。接收参数,然后post请求第三方接口下载文件得到流【httpurlconnection的post请求的使用】,然后转byte数组【这一步很关键,参考的网页已经找不到了,但是非常感谢原文章作者】,然后同样用响应流输出到页面【out.write()】
代码如下【至于后续代码的规范划的拆分、优化暂时就不粘贴在这里了】:
/**
* "MY_LICENCE_DETAIL"
* @author 作 者:
* @createdTime 创建时间:2018年5月16日 下午4:17:27
* @description 方法说明:根据 infoFileId 文件绝对路径 查询 文件 页面展示并提供下载
* @param fileId 文件路径
* @param fileName 文件名字
* @param flag 预览还是下载标志位 flag 为null默认预览 , flag不为null为下载
* @throws UnsupportedEncodingException
*/
@RequestMapping(value = "/common/xxxxx.do", method = RequestMethod.GET)
public void xxxxxttttt(String fileId,String fileName,String flag, HttpServletResponse response) throws IOException{
log.info("------接受到 入参fileId是"+fileId+"---fileName是"+fileName+"---flag是"+flag+"---");
fileId= new String(fileId.getBytes("iso-8859-1"),"utf-8");
fileName= new String(fileName.getBytes("iso-8859-1"),"utf-8");
log.info("------转码处理后 入参fileId是"+fileId+"---fileName是"+fileName+"---flag是"+flag+"---");
if(null == fileName || "".equals(fileName)){
fileName = "证件文件.pdf";
}else{
//请求的接口的文件均为pdf格式
fileName = fileName+".pdf";
}
if(fileId == null || "".equals(fileId)){
log.info("参数无效");
ResultUtil.sendString(response, "参数无效");
}else{
//直接请求接口下载文件
InputStream in = null;
OutputStream out = null;
try{
//相关接口url配置在xml读取
String stringUrl = GlobalConfig.getInstance().getString("my.xxx.detail.xxxxx.xxxxxxxx");
log.info("-----请求的url地址是:"+stringUrl+"----");
URL url = new URL(stringUrl);
URLConnection urlConnection = url.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
httpURLConnection.setUseCaches(false);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Charsert", "UTF-8");
httpURLConnection.setRequestProperty("connection", "Keep-Alive");
httpURLConnection.setConnectTimeout(60000);
httpURLConnection.setReadTimeout(60000);
httpURLConnection.setInstanceFollowRedirects(true);
httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpURLConnection.connect();
// 创建输入输出流,用于往连接里面输出携带的参数,(输出内容为?后面的内容) 正文,正文内容其实跟get的URL中 '? '后的参数字符串一致
DataOutputStream dataout = new DataOutputStream(httpURLConnection.getOutputStream());
String parm = "fileId=" + URLEncoder.encode(fileId, "utf-8");
// 为字符串进行编码 将参数输出到连接
dataout.writeBytes(parm);
// 输出完成后刷新并关闭流
dataout.flush();
dataout.close(); // 重要且易忽略步骤 (关闭流,切记!)
in = httpURLConnection.getInputStream();//这一步才是真正的发送请求并获取相应流结果
//把inputstream转为byte数组
ByteArrayOutputStream outTemp=new ByteArrayOutputStream();
byte[] buffer=new byte[1024*4];
int n=0;
while ( (n=in.read(buffer)) !=-1) {
outTemp.write(buffer,0,n);
}
byte[] fileData = outTemp.toByteArray();
//获取文件大小
int contentLength = httpURLConnection.getContentLength();
log.info("-----获取文件长度httpURLConnection.getContentLength() = "+contentLength+"-----");
int responceCode = httpURLConnection.getResponseCode();
log.info("----responceCode==="+responceCode+"----");
if (responceCode == HttpURLConnection.HTTP_OK){
response.reset();
// 设置response的Header, 对文件进行url编码
String name = new String(URLEncoder.encode(fileName, "UTF-8").getBytes("UTF-8"),"ISO8859-1");
//预览还是下载,设置不同的响应头
if(flag == null){
response.setHeader("content-disposition", "inline;filename=" + name);
log.info("---预览----");
}else{
response.setHeader("content-disposition", "attachment;filename=" + name);
log.info("---下载----");
}
response.setContentLength(fileData.length);
out = response.getOutputStream();
out.write(fileData);
out.flush();
}else{
log.info("-----从接口下载文件 失败,responceCode != 200-----");
ResultUtil.sendString(response, "获取文件失败");
}
}catch(Exception e){
log.info("-----获取文件异常--------");
e.printStackTrace();
ResultUtil.sendString(response, "获取文件异常");
}finally{
try {
if(in != null){
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(out != null){
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
预览和下载都是访问本方法,只是下载比预览多传递一个flag参数。根据falg以此来设置响应头content-disposition",是attachment【下载】还是在页面 inline【预览】
页面上的预览代码为页面引入的js中自动初始化加载一个方法,在这个方法中把预览的请求url赋值给一个iframe的src属性:
js代码:
//dom元素
var $iframe=$('#iframe-viewpdf');
var xxxx= {
init: function() {
var url = CONTEXTPATH + '/common/xxxxxx.do?fileId=' + fileId +'&fileName=' + fileName;
$iframe.attr('src',url);
}
};
jsp代码:
<iframe id="iframe-viewpdf" src="" frameborder="0" width="100%" height="100%"></iframe>
整体上功能就实现了。点击查看在页面预览pdf文件,点击下载,文件直接下载到本地。
但是这一路上走了很多弯路,有个人原因,也有客观原因【很蛋疼,涉及到系统对接、各种扯皮、心累】。甚是折腾。
我把一路上遇到的问题回忆下,把有用的信息记录在此:
①本来请求第三方接口下载文件,是不能按我上面代码的方式直接调用的,因为公司有一个专门的转发系统【gsb】,我要组织参数发给gsb,在gsb里配置第三方接口的信息,然后gsb自动去请求,然后把结果自动转给我,我只负责和gsb交互就行。但是之前都是gsb接收返回json字符串的配置,现在那边给gsb返回的是文件流,报错。问了一大帮人都没遇到过这种情况,尝试各种参数配置组合都不行,卡着了。没办法为了先实现功能,我就另辟蹊径选择了用java请求文件,先实现功能。
【这是后话了,直到昨天才确定,调的接口那边,要把文件byte[],不要直接放在out.write()里面返回给gsb,要把byte[]转为base64字符串再返回,才能被gsb系统识别接收。。。。。。是他那边返回方式的问题。说到这了,那就把这个内容 byte[] 与base64字符串的 编码解码 记录在这。】
byte[] fileData = preFormFileServiceImpl.downloadByPath(fileId);
String file = Base64.encodeToString(fileData); //注意,别导错包了 import jodd.util.Base64
接收String以后要转回byte数组。代码如下:
jodd.util.Base64 decoder = new jodd.util.Base64();
// Base64解码 接受的gsb结果转byte 数组
byte[] fileData = decoder.decode(resultStr);
if (fileData == null) {
log.info("-----获取文件gsb返回结果转byte[]为null--------");
ResultUtil.sendString(response, "");
}else{
for (int i = 0; i < fileData.length; ++i) {
if (fileData[i] < 0) {// 调整异常数据
fileData[i] += 256;
}
}
//接下来设置response的响应头等信息......
②关于使用httpclient发送请求。有几种方式,我选择的是使用httpUrlConnection发送post请求。可是页面上啥也没有。排查发现
httpURLConnection.getContentLength()获取返回的文件大小 输出 是 0,
然而返回的状态码httpURLConnection.getResponseCode() 输出是 200,纳闷了啊。成功但是没有下载到文件。
好一通折腾,比如之前我是这样添加请求参数的,
httpURLConnection.setRequestProperty(”key“,"value");
后来发现要先用流把参数放进去,这样:
// 创建输入输出流,用于往连接里面输出携带的参数,(输出内容为?后面的内容) 正文,正文内容其实跟get的URL中 '? '后的参数字符串一致
DataOutputStream dataout = new DataOutputStream(httpURLConnection.getOutputStream());
String parm = "fileId=" + URLEncoder.encode(fileId, "utf-8");
// 为字符串进行编码
// 将参数输出到连接
dataout.writeBytes(parm);
// 输出完成后刷新并关闭流
dataout.flush();
dataout.close(); // 重要且易忽略步骤 (关闭流,切记!)
之后再去发送请求。
还有关于请求成功,但是流为0 ,有不少博客说加上这一行:
//解决 下载文件大小httpURLConnection.getContentLength() 为0 的问题
//httpURLConnection.setRequestProperty("Accept-Encoding", "identity");
也没有效果。还是为0。
总之各种尝试,相关的博客基本上翻遍了。。。现在我怀疑是接口那边文件的问题,换个测试参数值,好了,不为 0 了。吐血。。。。至于上面提到的两种post请求参数的设置方式,我目前用的第二种,第一种没有再尝试,但我认为应该也是可以的,因为在别人博客中使用过。
③接下来就是输出数据到页面了。httpUrlConnection 发送请求返回的接收是一个InPutStream in.
in = httpURLConnection.getInputStream(); //这一步才是真正发送请求并接收返回结果。
之前一直是这样写的返回代码
bin = new BufferedInputStream(in);//把InPutStream 转为 BufferedInputStream
out = response.getOutputStream();
int size = 0;
//读取文件流
byte[] buf = new byte[1024];
if(bin.read(buf) == -1){
log.info("=====读取下载的文件流,出现【bin.read(buf) == -1】的情况====");
ResultUtil.sendString(response, "文件不存在");
}
while((size = bin.read(buf)) != -1){
//写文件流
out.write(buf,0,size);
}
bin.close();
out.flush();
但是页面一直啥也没有,感觉也没啥问题啊,其他博客还有以前记得就是这么写的。。。迷惑【流的知识点我一直很薄弱,理解不透还经常记混淆,有大神看出问题还望指正交流】
后来,把返回的iuputStream流转为byte数组,直接全部out.write(byte[]),也别搞什么while循环了。问题解决【代码在开头,此处就不再粘贴了】。关一这一点,不是很明白。
④还漏了一点,就是关于pdf文件在页面预览,这个问题也折腾。目前我用的iframe src的方式。后端response的header设置上,有说设置response.setContentType("application/pdf");的,可我最终没有这一步也成功了,总之各种说法都有,都看得乱了。一点点摸索尝试。对了,关于ajax是不能 直接 下载文件的,因为传输数据形式在限制。但是有巧妙办法,相关办法很多博客有说,可以自行查阅。
下面的代码是自己尝试的最后代码:没有成功。有兴趣可以对比下差异【流转byte[]、直接byte[]全部out.write()】
@RequestMapping(value = "/common/xxxxxx.do", method = RequestMethod.GET)
public void xxxxxxx(String fileId,String fileName,String flag, HttpServletResponse response) throws UnsupportedEncodingException{
fileId= new String(fileId.getBytes("iso-8859-1"),"utf-8");
fileName= new String(fileName.getBytes("iso-8859-1"),"utf-8");
log.info("------入参fileId是"+fileId+"---fileName是"+fileName+"---flag是"+flag+"---");
if(null == fileName || "".equals(fileName)){
fileName = "文件.pdf";
}else{
fileName = fileName+".pdf";
}
if(fileId == null || "".equals(fileId)){
log.info("传入参数无效");
ResultUtil.sendString(response, "");
}else{
//直接wen jian 接口
InputStream in = null;
OutputStream out = null;
BufferedInputStream bin = null;
try{
//接口url配置在xml读取
String stringUrl = GlobalConfig.getInstance().getString("my.xxx.detail.xxx.downloadPdfByCode");
log.info("-----请求的url地址是:"+stringUrl+"----");
URL url = new URL(stringUrl);
URLConnection urlConnection = url.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
httpURLConnection.setUseCaches(false);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Charsert", "UTF-8");
httpURLConnection.setRequestProperty("connection", "Keep-Alive");
httpURLConnection.setConnectTimeout(60000);
httpURLConnection.setReadTimeout(60000);
httpURLConnection.setInstanceFollowRedirects(true);
httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
//解决 下载文件大小httpURLConnection.getContentLength() 为0 的问题
//httpURLConnection.setRequestProperty("Accept-Encoding", "identity");
httpURLConnection.connect();
// 创建输入输出流,用于往连接里面输出携带的参数,(输出内容为?后面的内容) 正文,正文内容其实跟get的URL中 '? '后的参数字符串一致
DataOutputStream dataout = new DataOutputStream(httpURLConnection.getOutputStream());
String parm = "fileId=" + URLEncoder.encode(fileId, "utf-8");
// 为字符串进行编码
// 将参数输出到连接
dataout.writeBytes(parm);
// 输出完成后刷新并关闭流
dataout.flush();
dataout.close(); // 重要且易忽略步骤 (关闭流,切记!)
in = httpURLConnection.getInputStream();
//获取文件大小
int contentLength = httpURLConnection.getContentLength();
log.info("-----获取文件长度httpURLConnection.getContentLength() = "+contentLength+"-----");
int responceCode = httpURLConnection.getResponseCode();
log.info("----responceCode==="+responceCode+"----");
if (responceCode == HttpURLConnection.HTTP_OK){
// 清空response
response.reset();
response.setCharacterEncoding("utf-8");
response.setContentType("application/pdf");
// 设置response的Header, 对文件进行url编码
String name = URLEncoder.encode(fileName, "UTF-8");
//预览还是下载
if(flag == null){
response.setHeader("Content-Disposition", "inline;filename="+name);
log.info("---预览----");
}else{
response.setHeader("Content-Disposition", "attachment;filename="+name);
log.info("---下载----");
}
//response.setHeader("Content-Length",""+contentLength);
bin = new BufferedInputStream(in);
out = response.getOutputStream();
int size = 0;
//读取文件流
byte[] buf = new byte[1024];
if(bin.read(buf) == -1){
log.info("=====读取下载的文件流,出现【bin.read(buf) == -1】的情况====");
ResultUtil.sendString(response, "文件不存在");
}
while((size = bin.read(buf)) != -1){
//写文件流
out.write(buf,0,size);
}
bin.close();
out.flush();
}else{
log.info("-----从接口下载文件 失败,responceCode != 200-----");
ResultUtil.sendString(response, "获取文件失败");
}
}catch(Exception e){
log.info("-----获取文件异常--------");
e.printStackTrace();
ResultUtil.sendString(response, "获取文件异常");
}finally{
try {
if(in != null){
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(out != null){
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用java的 htpUrlConnection post请求 下载pdf文件,然后输出到页面进行预览和下载的更多相关文章
- 阿里云OSS下载pdf文件,并在pdf文件上添加水印
代码: 兵马未动,粮草先行 作者: 传说中的汽水枪 如有错误,请留言指正,欢迎一起探讨. 转载请注明出处. 公司要求从阿里云OSS下载pdf文件并且需要添加水印. 因此这里总结一下. 首先添加了一个F ...
- PDF文件预览和下载
背景:项目中实现pdf文件的预览以及下载 环境:jdk1.8.SpringBoot2.0.Maven PDF.js下载地址将下载的源码拷入项目中 修改viewer.js: 将default ...
- 知网下载pdf文件的方法
title: 知网下载pdf文件的方法 toc: false date: 2018-11-02 17:54:43 categories: methods tags: 知网 平时我们使用的是国内版的知网 ...
- 【转】Python编程: 多个PDF文件合并以及网页上自动下载PDF文件
1. 多个PDF文件合并1.1 需求描述有时候,我们下载了多个PDF文件, 但希望能把它们合并成一个PDF文件.例如:你下载的数个PDF文件资料或者电子发票,你可以使用python程序合并成一个PDF ...
- 从七牛服务下载PDF文件
/** * 从七牛下载PDF文件 * @param request * @param response * @param exhiId * @throws MalformedURLException ...
- 用pdf.js实现在移动端在线预览pdf文件
用pdf.js实现在移动端在线预览pdf文件1.下载pdf.js 官网地址:https://mozilla.github.io/pdf.js/ 2.配置 下载下来的文件包,就是一个demo ...
- Asp.Net Core 2.0 项目实战(3)NCMVC角色权限管理前端UI预览及下载
Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了 Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架 Asp.Ne ...
- javafx实现读者文摘上的文章预览及下载
功能设计: 1.实现读者文章的预览及下载 (实现了单击预览,双击下载) 2.实现文章查找 (实现了通过文章名查找(关键字)或者文章期数或年份(或者年份加期数)) 实现步骤: 首先是数据库设计: 数据库 ...
- Visual Studio 2022 预览版下载来了(x64位)
Visual Studio 2022 预览版下载:https://visualstudio.microsoft.com/zh-hans/vs/preview/vs2022/
随机推荐
- VS2015无法创建C++工程解决方法!!
VS2015默认安装时候没有安装C++,如果安装C++没有选择全部C++项目,则无法创建C++工程,在控制面板里的删除程序中,选择VS2015,随后选择修改,把C++项目都选择上就可以了,这样安装完毕 ...
- #6432. 「PKUSC2018」真实排名(组合数学)
题面 传送门 题解 这数据范围--这输出大小--这模数--太有迷惑性了-- 首先对于\(0\)来说,不管怎么选它们的排名都不会变,这个先特判掉 对于一个\(a_i\)来说,如果它不选,那么所有大于等于 ...
- django 学习之DRF (一)
Django框架基础DRF-01 前后端分离介绍 1.前后端不分离图解 2.前后端分离图解 3.为什么要学习DRF DRF可以帮助我们开发者快速的开发⼀个依托于Django的前后后端分离 ...
- 在PowerShell中操作SharePoint对象
1. 用PowerShell创建一个SharePoint内容对象创建一个自定义列表:$SPSite = New-Object Microsoft.SharePoint.SPSite("htt ...
- 树状数组【bzoj3155】: Preprefix sum
3155: Preprefix sum 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3155 把给出的a_i当成查分数组d_i做就可以了 ...
- DP【洛谷P2134】 百日旅行
[洛谷P2134] 百日旅行 题目背景 重要的不是去哪里,而是和你在一起.--小红 对小明和小红来说,2014年7月29日是一个美好的日子.这一天是他们相识100天的纪念日. (小明:小红,感谢你2场 ...
- [转]SQL truncate 、delete与drop区别
转自: https://www.cnblogs.com/8765h/archive/2011/11/25/2374167.html 相同点: 1.truncate和不带where子句的delete.以 ...
- 老男孩python作业3-购物车程序优化
购物车优化要求:用户入口: 1.商品信息存在文件里 2.已购商品,余额记录.第一次启动程序时需要记录工资,第二次启动程序时谈出上次余额 3.允许用户根据商品编号购买商品 4.用户选择商品后,检测是否够 ...
- B. Sereja and Suffixes
B. Sereja and Suffixes time limit per test 1 second memory limit per test 256 megabytes input standa ...
- android 快速开发框架
https://github.com/lipanquan/LPQRapidDevelopmentFramework 依赖LPQLibrary https://github.com/lipanquan/ ...