1. 程式人生 > >使用java的 htpUrlConnection post請求 下載pdf文件,然後輸出到頁面進行預覽和下載

使用java的 htpUrlConnection post請求 下載pdf文件,然後輸出到頁面進行預覽和下載

原因 path dir sta 2018年 while循環 download acc 輸入輸出

使用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文件,然後輸出到頁面進行預覽和下載