package jframe.pay.wx.http.client; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jframe.pay.wx.http.util.HttpClientUtil; /** * 财付通http或者https网络通信客户端<br/> * ========================================================================<br/> * api说明:<br/> * setReqContent($reqContent),设置请求内容,无论post和get,都用get方式提供<br/> * getResContent(), 获取应答内容<br/> * setMethod(method),设置请求方法,post或者get<br/> * getErrInfo(),获取错误信息<br/> * setCertInfo(certFile, certPasswd),设置证书,双向https时需要使用<br/> * setCaInfo(caFile), 设置CA,格式未pem,不设置则不检查<br/> * setTimeOut(timeOut), 设置超时时间,单位秒<br/> * getResponseCode(), 取返回的http状态码<br/> * call(),真正调用接口<br/> * getCharset()/setCharset(),字符集编码<br/> * * ========================================================================<br/> * */ public class TenpayHttpClient { static Logger LOG = LoggerFactory.getLogger(TenpayHttpClient.class); private static final String USER_AGENT_VALUE = "Mozilla/4.0 (compatible; MSIE 6.0; Windows XP)"; private static final String JKS_CA_FILENAME = "tenpay_cacert.jks"; private static final String JKS_CA_ALIAS = "tenpay"; private static final String JKS_CA_PASSWORD = ""; /** ca证书文件 */ private File caFile; /** 证书文件 */ private File certFile; /** 证书密码 */ private String certPasswd; /** 请求内容,无论post和get,都用get方式提供 */ private String reqContent; /** 应答内容 */ private String resContent; /** 请求方法 */ private String method; /** 错误信息 */ private String errInfo; /** 超时时间,以秒为单位 */ private int timeOut; /** http应答编码 */ private int responseCode; /** 字符编码 */ private String charset; private InputStream inputStream; public TenpayHttpClient() { this.caFile = null; this.certFile = null; this.certPasswd = ""; this.reqContent = ""; this.resContent = ""; this.method = "POST"; this.errInfo = ""; this.timeOut = 30;// 30秒 this.responseCode = 0; this.charset = "UTF-8"; this.inputStream = null; } /** * 设置证书信息 * * @param certFile * 证书文件 * @param certPasswd * 证书密码 */ public void setCertInfo(File certFile, String certPasswd) { this.certFile = certFile; this.certPasswd = certPasswd; } /** * 设置ca * * @param caFile */ public void setCaInfo(File caFile) { this.caFile = caFile; } /** * 设置请求内容 * * @param reqContent * 表求内容 */ public void setReqContent(String reqContent) { this.reqContent = reqContent; } /** * 获取结果内容 * * @return String * @throws IOException */ public String getResContent() { try { this.doResponse(); } catch (Exception e) { this.errInfo = e.getMessage(); // return ""; LOG.error(e.getMessage()); } return this.resContent; } /** * 设置请求方法post或者get * * @param method * 请求方法post/get */ public void setMethod(String method) { this.method = method; } /** * 获取错误信息 * * @return String */ public String getErrInfo() { return this.errInfo; } /** * 设置超时时间,以秒为单位 * * @param timeOut * 超时时间,以秒为单位 */ public void setTimeOut(int timeOut) { this.timeOut = timeOut; } /** * 获取http状态码 * * @return int */ public int getResponseCode() { return this.responseCode; } /** * 执行http调用。true:成功 false:失败 * * @return boolean */ public boolean call() { boolean isRet = false; // http if (null == this.caFile && null == this.certFile) { try { this.callHttp(); isRet = true; } catch (IOException e) { this.errInfo = e.getMessage(); } return isRet; } // https try { this.callHttps(); isRet = true; } catch (Exception e) { this.errInfo = e.getMessage(); LOG.error(e.getMessage()); } return isRet; } protected void callHttp() throws IOException { if ("POST".equals(this.method.toUpperCase())) { String url = HttpClientUtil.getURL(this.reqContent); String queryString = HttpClientUtil.getQueryString(this.reqContent); byte[] postData = queryString.getBytes(this.charset); this.httpPostMethod(url, postData); return; } this.httpGetMethod(this.reqContent); } protected void callHttps() throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException { // ca目录 String caPath = this.caFile.getParent(); File jksCAFile = new File(caPath + "/" + TenpayHttpClient.JKS_CA_FILENAME); if (!jksCAFile.isFile()) { X509Certificate cert = (X509Certificate) HttpClientUtil.getCertificate(this.caFile); FileOutputStream out = new FileOutputStream(jksCAFile); // store jks file HttpClientUtil.storeCACert(cert, TenpayHttpClient.JKS_CA_ALIAS, TenpayHttpClient.JKS_CA_PASSWORD, out); out.close(); } FileInputStream trustStream = new FileInputStream(jksCAFile); FileInputStream keyStream = new FileInputStream(this.certFile); SSLContext sslContext = HttpClientUtil.getSSLContext(trustStream, TenpayHttpClient.JKS_CA_PASSWORD, keyStream, this.certPasswd); // 关闭流 keyStream.close(); trustStream.close(); if ("POST".equals(this.method.toUpperCase())) { String url = HttpClientUtil.getURL(this.reqContent); String queryString = HttpClientUtil.getQueryString(this.reqContent); byte[] postData = queryString.getBytes(this.charset); this.httpsPostMethod(url, postData, sslContext); return; } this.httpsGetMethod(this.reqContent, sslContext); } public boolean callHttpPost(String url, String postdata) { boolean flag = false; byte[] postData; try { postData = postdata.getBytes(this.charset); this.httpPostMethod(url, postData); flag = true; } catch (Exception e) { LOG.error(e.getMessage()); } return flag; } /** * 以http post方式通信 * * @param url * @param postData * @throws IOException */ protected void httpPostMethod(String url, byte[] postData) throws IOException { HttpURLConnection conn = HttpClientUtil.getHttpURLConnection(url); this.doPost(conn, postData); } /** * 以http get方式通信 * * @param url * @throws IOException */ protected void httpGetMethod(String url) throws IOException { HttpURLConnection httpConnection = HttpClientUtil.getHttpURLConnection(url); this.setHttpRequest(httpConnection); httpConnection.setRequestMethod("GET"); this.responseCode = httpConnection.getResponseCode(); this.inputStream = httpConnection.getInputStream(); } /** * 以https get方式通信 * * @param url * @param sslContext * @throws IOException */ protected void httpsGetMethod(String url, SSLContext sslContext) throws IOException { SSLSocketFactory sf = sslContext.getSocketFactory(); HttpsURLConnection conn = HttpClientUtil.getHttpsURLConnection(url); conn.setSSLSocketFactory(sf); this.doGet(conn); } protected void httpsPostMethod(String url, byte[] postData, SSLContext sslContext) throws IOException { SSLSocketFactory sf = sslContext.getSocketFactory(); HttpsURLConnection conn = HttpClientUtil.getHttpsURLConnection(url); conn.setSSLSocketFactory(sf); this.doPost(conn, postData); } /** * 设置http请求默认属性 * * @param httpConnection */ protected void setHttpRequest(HttpURLConnection httpConnection) { // 设置连接超时时间 httpConnection.setConnectTimeout(this.timeOut * 1000); // User-Agent httpConnection.setRequestProperty("User-Agent", TenpayHttpClient.USER_AGENT_VALUE); // 不使用缓存 httpConnection.setUseCaches(false); // 允许输入输出 httpConnection.setDoInput(true); httpConnection.setDoOutput(true); } /** * 处理应答 * * @throws IOException */ protected void doResponse() throws IOException { if (null == this.inputStream) { return; } // 获取应答内容 this.resContent = HttpClientUtil.InputStreamTOString(this.inputStream, this.charset); // 关闭输入流 this.inputStream.close(); } /** * post方式处理 * * @param conn * @param postData * @throws IOException */ protected void doPost(HttpURLConnection conn, byte[] postData) throws IOException { // 以post方式通信 conn.setRequestMethod("POST"); // 设置请求默认属性 this.setHttpRequest(conn); // Content-Type conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); try (BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream())) { final int len = 1024; // 1KB HttpClientUtil.doOutput(out, postData, len); // 关闭流 // out.close(); } // 获取响应返回状态码 this.responseCode = conn.getResponseCode(); // 获取应答输入流 this.inputStream = conn.getInputStream(); } /** * get方式处理 * * @param conn * @throws IOException */ protected void doGet(HttpURLConnection conn) throws IOException { // 以GET方式通信 conn.setRequestMethod("GET"); // 设置请求默认属性 this.setHttpRequest(conn); // 获取响应返回状态码 this.responseCode = conn.getResponseCode(); // 获取应答输入流 this.inputStream = conn.getInputStream(); } }