1. 程式人生 > >java使用httpClient解決外部url請求訪問

java使用httpClient解決外部url請求訪問

一,在一般專案中,涉及第三方介面呼叫,一般是採用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"
					+"&timestamp="+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是讀取的配置檔案。