java使用httpClient解決外部url請求訪問
阿新 • • 發佈:2018-12-17
一,在一般專案中,涉及第三方介面呼叫,一般是採用webService或者httpClient。
基於專案要求,我這邊做一個httpClient請求檔案上傳,是先從資料庫表中讀取二進位制流,然後轉存到本地伺服器上面,最後呼叫httpClient上傳至檔案伺服器上面,具體程式碼如下
package com.hxzq.s0026.my168.service.impl; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Service; import com.google.gson.Gson; import com.hxzq.commons.db.mapper.SQLQueryMapResult; import com.hxzq.commons.ioc.HxSpringUtil; import com.hxzq.s0026.my168.constants.Constants; import com.hxzq.s0026.my168.dao.My168PhotoInitMapper; import com.hxzq.s0026.my168.service.My168PhotoInitService; import com.thinkive.base.config.Configuration; import com.thinkive.base.exception.CommonException; import com.thinkive.base.jdbc.DataRow; import com.thinkive.base.util.JsonHelper; import com.thinkive.base.util.StringHelper; import com.thinkive.server.exception.BusinessException; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; @Service public class My168PhotoInitServiceImpl implements My168PhotoInitService { static Logger logger=Logger.getLogger(My168PhotoInitServiceImpl.class); private static RequestConfig requestConfig; private static String photoUrl; // private static List<String> localPaths;//用於刪除本地檔案 static { //request配置超時時間 requestConfig = RequestConfig.custom() .setConnectTimeout(60000)//設定連線超時時間,單位毫秒 .setConnectionRequestTimeout(1000)//設定從connect Manager獲取Connection 超時時間,單位毫秒。這個屬性是新加的屬性,因為目前版本是可以共享連線池的 .setSocketTimeout(60000)//請求獲取資料的超時時間,單位毫秒。 如果訪問一個介面,多少時間內無法返回資料,就直接放棄此次呼叫 .build(); photoUrl=Configuration.getString("my168.photo_url");//獲取檔案上傳檔案伺服器 } @Override public void initPhoto() { // TODO Auto-generated method stub My168PhotoInitMapper my168PhotoInitMapper = HxSpringUtil.getBean(Constants.sysNo, My168PhotoInitMapper.class); SQLQueryMapResult rs = my168PhotoInitMapper.queryPhoto(); List<DataRow> list = rs.getDataList(); if (list.size() == 0) { throw new CommonException(1, "頭像不存在"); } BASE64Encoder encoder = null; String fileName = null; String absolutePath = null; // String // location=request.getSession().getServletContext().getRealPath("/upload"); // 迴圈讀取對應的影象二進位制流,轉換成圖片上傳進檔案伺服器 for (int i = 0; i < list.size(); i++) { try { byte[] bytes = (byte[]) list.get(i).get("avatar"); if (bytes==null) { continue; } String userid = (String) list.get(i).get("userid"); fileName = userid + ".jpg"; encoder = new BASE64Encoder(); String avatarStr = encoder.encode(bytes); BASE64Decoder decoder = new BASE64Decoder(); byte[] bytes1 = decoder.decodeBuffer(avatarStr); InputStream bais = new ByteArrayInputStream(bytes1); // 使用imageIo檔案流出現型別異常,推薦使用二進位制流 // JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(new // InputStream(bais)); // BufferedImage sourceImg = decoder.decodeAsBufferedImage(); // BufferedImage bi1 = ImageIO.read(bais); // File f1 = new File(fileName); // ImageIO.write(bi1, "jpg", f1); File file = new File(fileName);// 可以是任何圖片格式.jpg,.png等 FileOutputStream fos = new FileOutputStream(file); byte[] b = new byte[1024]; int nRead = 0; while ((nRead = bais.read(b)) != -1) { fos.write(b, 0, nRead); } fos.flush(); fos.close(); bais.close(); absolutePath = file.getAbsolutePath();// 獲取真實路徑 DataRow data = (DataRow) this.updateFile(absolutePath); absolutePath = (String) data.get("file_path"); // 同步更新對應的資料庫 my168PhotoInitMapper.updatePhotoAddrs(absolutePath, userid); } catch (IOException e) { throw new CommonException(2, "處理圖片失敗"); } } } /** * * @說明: 開啟一個httpClient連線,然後進行單個檔案上傳,後續可以考慮提供批量上傳 * @方法名稱: updateFile * @引數 @param filePath 本地伺服器上面的真實路徑 * @引數 @return * @返回型別 Object * @建立者: 敬進 * @建立時間: 2018年10月23日 下午1:57:21 * @修改者: 敬進 * @修改時間: 2018年10月23日 下午1:57:21 */ @SuppressWarnings("all") private Object updateFile(String filePath) { if (com.thinkive.base.util.StringUtil.isEmpty(filePath)) { throw new BusinessException(1, "檔案上傳失敗,附件為空!"); } CloseableHttpClient httpClient = null; HttpPost httpPost = null; try { httpClient = HttpClients.createDefault(); httpPost = new HttpPost(photoUrl); httpPost.setConfig(requestConfig);//設定訪問引數 Map<String,Object> dataMap = new HashMap<String,Object>(); dataMap.put("business_code", "png_upload"); //請求引數 String data=new Gson().toJson(dataMap); //轉成base64字串 data= new BASE64Encoder().encode(data.getBytes()); //時間戳 String timestamp=String.valueOf(System.currentTimeMillis()); //商戶id String merchant_id="THINKIVEFILE"; //簽名引數 //將引數拼接成簽名字串 String signStr ="data="+data +"&merchant_id="+merchant_id +"&signKey=53e079663bfe4f0bc4cb14f9a819e3d5" +"×tamp="+timestamp; //簽名結果值 String sign= encryptToMD5(signStr); //設定訪問入參 MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setCharset(Charset.forName(HTTP.UTF_8));// 設定請求編碼格式 builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);// 設定瀏覽器相容模式 builder.addBinaryBody("upfile", new File(filePath));//設定上傳路徑 builder.addTextBody("timestamp",timestamp); builder.addTextBody("data", data); builder.addTextBody("merchant_id", merchant_id); builder.addTextBody("sign", sign); HttpEntity entity = builder.build(); httpPost.setEntity(entity); //執行http訪問 HttpResponse response = httpClient.execute(httpPost); int statusCode = response.getStatusLine().getStatusCode();//獲取訪問狀態嗎 if (statusCode == HttpStatus.SC_OK) { HttpEntity resEntity = response.getEntity(); String jsonStr = EntityUtils.toString(resEntity);// httpClient自帶的工具類讀取返回資料 EntityUtils.consume(resEntity); if (StringHelper.isEmpty(jsonStr)) { throw new BusinessException(1, "檔案上傳異常,響應結果為空!"); } // 解析響應結果 DataRow dataRow = JsonHelper.getObjectByJSON(jsonStr, DataRow.class); if (dataRow.getInt("error_no") != 0) { throw new BusinessException(dataRow.getInt("error_no"), dataRow.getString("error_info")); } //獲取資料然後封裝給對應的datarow List<Map> list = (List<Map>) dataRow.get("results"); List<DataRow> newList = null; if (null != list) { newList = new ArrayList<DataRow>(); for (Map map : list) { DataRow row = new DataRow(); row.putAll(map); newList.add(row); } logger.info("服務端返回地址:"+newList.get(0)); return newList.get(0); } } else { throw new BusinessException(1, "檔案上傳失敗!狀態碼:" + statusCode); } } catch (Exception e) { // TODO: handle exception throw new BusinessException(1,"檔案下載異常!"); } finally { if (null != httpPost) { try { httpPost.clone(); } catch (CloneNotSupportedException e) { } } if (null != httpClient) { try { httpClient.close(); } catch (IOException e) { } } } return null; } //設定模板加密,加密為MD5 public String encryptToMD5(String info) { byte[] digesta = null; try { MessageDigest mDigest = MessageDigest.getInstance("MD5"); mDigest.update(info.getBytes()); digesta = mDigest.digest(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return bytesToHex(digesta); } //格式轉換 private String bytesToHex(byte[] bytes) { String hex = ""; String temp = ""; for (int i = 0; i < bytes.length; i++) { temp = Integer.toHexString(bytes[i] & 0xFF); if (temp.length() == 1) { hex = hex + "0" + temp; } else { hex = hex + temp; } } return hex; } //上傳成功後刪除本地圖片,暫時未開發 private void deleteLocalPath(List<String> paths){ File file=null; for (String path : paths) { file=new File(path); if (file.isDirectory()) { throw new BusinessException(-1, "不允許刪除資料夾"); }else{ file.delete(); } } } }
ps:這邊有一部分程式碼呼叫是呼叫本地庫,傳入的url是讀取的配置檔案。