production.url=http://xx.xxx.xx.xx:8081/xx //本地其他機器的地址
production.ywurl=http://xx.xxx.xx.x:8080/xx(項目名) //雲上的服務器地址
2.在項目的 applicationContext.xml 下引用該配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd"
default-lazy-init="true">
// 調用接口的配置文件的路徑
<context:property-placeholder location="classpath:properties/production.properties" ignore-resource-not-found="true" ignore-unresolvable="true" />
<!-- 工具類調用生產接口 -->
<bean class="com.xxx.oil.util.ProductionUtil">
<property name="url" value="${production.url}" />
<property name="ywurl" value="${production.ywurl}" />
</bean>
</beans>
3、在項目的工具包裏面新建一個工具類ProductionUtil.java
public class ProductionUtil {
private String url;
private String ywurl;
public String sendGet(String method, Map<String, String> params){
String requestUrl = "";
if ("yw".equals(method.substring(0,2))){
requestUrl = this.getYwurl() + method.substring(2, method.length());
} else {
requestUrl = this.getUrl() + method;
}
System.out.println(requestUrl);
if(params != null && params.size() > 0){
String param = "";
for(Map.Entry<String,String> entry : params.entrySet()){
if(entry.getValue() != null){
param = param + "&" + entry.getKey() + "=" + entry.getValue();
}
}
param = param.substring(1,param.length());
requestUrl = requestUrl + "?" + param;
}
return HttpClientUtilOil.sendGetRequest(requestUrl);
}
public String sendPost(String method, Map<String, String> params){
String requestUrl = "";
if ("yw".equals(method.substring(0,2))){
requestUrl = this.getYwurl() + method.substring(2, method.length());
} else {
requestUrl = this.getUrl() + method;
}
System.out.println(requestUrl);
return HttpClientUtilOil.sendPostRequest(requestUrl, params, "UTF-8");
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getYwurl() {
return ywurl;
}
public void setYwurl(String ywurl) {
this.ywurl = ywurl;
}
}
4. 在項目的工具包裏面新建一個工具類HttpClientUtilOil.java
package com.qdport.oil.util;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
/**
* 封裝了採用HttpClient發送HTTP請求的方法
* @see 本工具所採用的是HttpComponents-Client-4.2.1
* @see ===================================================================================================
* @see 開發HTTPS應用時,時常會遇到兩種情況
* @see 1、測試服務器沒有有效的SSL證書,客戶端連接時就會拋異常
* @see javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
* @see 2、測試服務器有SSL證書,但可能由於各種不知名的原因,它還是會拋一堆爛碼七糟的異常,諸如下面這兩種
* @see javax.net.ssl.SSLException: hostname in certificate didn't match: <123.125.97.66> != <123.125.97.241>
* @see javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
* @see ===================================================================================================
* @see 這裏使用的是HttpComponents-Client-4.2.1創建的連接,所以就要告訴它使用一個不同的TrustManager
* @see 由於SSL使用的模式是X.509,對於該模式,Java有一個特定的TrustManager,稱爲X509TrustManager
* @see TrustManager是一個用於檢查給定的證書是否有效的類,所以我們自己創建一個X509TrustManager實例
* @see 而在X509TrustManager實例中,若證書無效,那麼TrustManager在它的checkXXX()方法中將拋出CertificateException
* @see 既然我們要接受所有的證書,那麼X509TrustManager裏面的方法體中不拋出異常就行了
* @see 然後創建一個SSLContext並使用X509TrustManager實例來初始化之
* @see 接着通過SSLContext創建SSLSocketFactory,最後將SSLSocketFactory註冊給HttpClient就可以了
* @see ===================================================================================================
* @version v1.7
* @history v1.0-->新建<code>sendGetRequest()</code>和<code>sendPostRequest()</code>方法
* @history v1.1-->新增<code>sendPostSSLRequest()</code>方法,用於發送HTTPS的POST請求
* @history v1.2-->新增<code>sendPostRequest()</code>方法,用於發送HTTP協議報文體爲任意字符串的POST請求
* @history v1.3-->新增<code>java.net.HttpURLConnection</code>實現的<code>sendPostRequestByJava()</code>
* @history v1.4-->所有POST方法中增加連接超時限制和讀取超時限制
* @history v1.5-->重組各方法,並補充自動獲取HTTP響應文本編碼的方式,移除<code>sendPostRequestByJava()</code>
* @history v1.6-->整理GET和POST請求方法,使之更爲適用
* @history v1.7-->修正<code>sendPostRequest()</code>請求的CONTENT_TYPE頭信息,並優化各方法參數及內部處理細節
* @create Feb 1, 2012 3:02:27 PM
* @update Jul 23, 2013 1:18:35 PM
*/
public class HttpClientUtilOil {
private static Logger logger = Logger.getLogger(HttpClientUtilOil.class);
private HttpClientUtilOil(){}
/**
* 發送HTTP_GET請求
* @see 1)該方法會自動關閉連接,釋放資源
* @see 2)方法內設置了連接和讀取超時時間,單位爲毫秒,超時或發生其它異常時方法會自動返回"通信失敗"字符串
* @see 3)請求參數含中文時,經測試可直接傳入中文,HttpClient會自動編碼發給Server,應用時應根據實際效果決定傳入前是否轉碼
* @see 4)該方法會自動獲取到響應消息頭中[Content-Type:text/html; charset=GBK]的charset值作爲響應報文的解碼字符集
* @see 若響應消息頭中無Content-Type屬性,則會使用HttpClient內部默認的ISO-8859-1作爲響應報文的解碼字符集
* @param requestURL 請求地址(含參數)
* @return 遠程主機響應正文
*/
public static String sendGetRequest(String reqURL){
String respContent = "通信失敗"; //響應內容
HttpClient httpClient = new DefaultHttpClient(); //創建默認的httpClient實例
//設置代理服務器
//httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, new HttpHost("10.0.0.4", 8080));
httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000); //連接超時10s
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 20000); //讀取超時20s
HttpGet httpGet = new HttpGet(reqURL); //創建org.apache.http.client.methods.HttpGet
try{
HttpResponse response = httpClient.execute(httpGet); //執行GET請求
HttpEntity entity = response.getEntity(); //獲取響應實體
if(null != entity){
//respCharset=EntityUtils.getContentCharSet(entity)也可以獲取響應編碼,但從4.1.3開始不建議使用這種方式
Charset respCharset = ContentType.getOrDefault(entity).getCharset();
respContent = EntityUtils.toString(entity, respCharset);
//Consume response content
EntityUtils.consume(entity);
}
// System.out.println("-------------------------------------------------------------------------------------------");
StringBuilder respHeaderDatas = new StringBuilder();
for(Header header : response.getAllHeaders()){
respHeaderDatas.append(header.toString()).append("\r\n");
}
// String respStatusLine = response.getStatusLine().toString(); //HTTP應答狀態行信息
// String respHeaderMsg = respHeaderDatas.toString().trim(); //HTTP應答報文頭信息
// String respBodyMsg = respContent; //HTTP應答報文體信息
// System.out.println("HTTP應答完整報文=[" + respStatusLine + "\r\n" + respHeaderMsg + "\r\n\r\n" + respBodyMsg + "]");
// System.out.println("-------------------------------------------------------------------------------------------");
} catch (ConnectTimeoutException cte){
//Should catch ConnectTimeoutException, and don`t catch org.apache.http.conn.HttpHostConnectException
logger.error("請求通信[" + reqURL + "]時連接超時,堆棧軌跡如下", cte);
} catch (SocketTimeoutException ste){
logger.error("請求通信[" + reqURL + "]時讀取超時,堆棧軌跡如下", ste);
}catch(ClientProtocolException cpe){
//該異常通常是協議錯誤導致:比如構造HttpGet對象時傳入協議不對(將'http'寫成'htp')or響應內容不符合HTTP協議要求等
logger.error("請求通信[" + reqURL + "]時協議異常,堆棧軌跡如下", cpe);
}catch(ParseException pe){
logger.error("請求通信[" + reqURL + "]時解析異常,堆棧軌跡如下", pe);
}catch(IOException ioe){
//該異常通常是網絡原因引起的,如HTTP服務器未啓動等
logger.error("請求通信[" + reqURL + "]時網絡異常,堆棧軌跡如下", ioe);
}catch (Exception e){
logger.error("請求通信[" + reqURL + "]時偶遇異常,堆棧軌跡如下", e);
}finally{
//關閉連接,釋放資源
httpClient.getConnectionManager().shutdown();
}
return respContent;
}
/**
* 發送HTTP_POST請求
* @see 1)該方法允許自定義任何格式和內容的HTTP請求報文體
* @see 2)該方法會自動關閉連接,釋放資源
* @see 3)方法內設置了連接和讀取超時時間,單位爲毫秒,超時或發生其它異常時方法會自動返回"通信失敗"字符串
* @see 4)請求參數含中文等特殊字符時,可直接傳入本方法,並指明其編碼字符集encodeCharset參數,方法內部會自動對其轉碼
* @see 5)該方法在解碼響應報文時所採用的編碼,取自響應消息頭中的[Content-Type:text/html; charset=GBK]的charset值
* @see 若響應消息頭中未指定Content-Type屬性,則會使用HttpClient內部默認的ISO-8859-1
* @param reqURL 請求地址
* @param reqData 請求參數,若有多個參數則應拼接爲param11=value11&22=value22&33=value33的形式
* @param encodeCharset 編碼字符集,編碼請求數據時用之,此參數爲必填項(不能爲""或null)
* @return 遠程主機響應正文
*/
public static String sendPostRequest(String reqURL, Map<String, String> params, String encodeCharset){
String reseContent = "通信失敗";
HttpClient httpClient = new DefaultHttpClient();
httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 4000);
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 4000);
HttpPost httpPost = new HttpPost(reqURL);
//由於下面使用的是new StringEntity(....),所以默認發出去的請求報文頭中CONTENT_TYPE值爲text/plain; charset=ISO-8859-1
//這就有可能會導致服務端接收不到POST過去的參數,比如運行在Tomcat6.0.36中的Servlet,所以我們手工指定CONTENT_TYPE頭消息
httpPost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded; charset=" + encodeCharset);
try{
if(null != params){
List<NameValuePair> formParams = new ArrayList<NameValuePair>();
for(Map.Entry<String,String> entry : params.entrySet()){
formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
httpPost.setEntity(new UrlEncodedFormEntity(formParams, encodeCharset));
}
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
if (null != entity) {
reseContent = EntityUtils.toString(entity, ContentType.getOrDefault(entity).getCharset());
EntityUtils.consume(entity);
}
} catch (ConnectTimeoutException cte){
logger.error("請求通信[" + reqURL + "]時連接超時,堆棧軌跡如下", cte);
} catch (SocketTimeoutException ste){
logger.error("請求通信[" + reqURL + "]時讀取超時,堆棧軌跡如下", ste);
}catch(Exception e){
logger.error("請求通信[" + reqURL + "]時偶遇異常,堆棧軌跡如下", e);
}finally{
httpClient.getConnectionManager().shutdown();
}
return reseContent;
}
/**
* 發送HTTP_POST_SSL請求
* @see 1)該方法會自動關閉連接,釋放資源
* @see 2)該方法亦可處理普通的HTTP_POST請求
* @see 3)當處理HTTP_POST_SSL請求時,默認請求的是對方443端口,除非reqURL參數中指明瞭SSL端口
* @see 4)方法內設置了連接和讀取超時時間,單位爲毫秒,超時或發生其它異常時方法會自動返回"通信失敗"字符串
* @see 5)請求參數含中文等特殊字符時,可直接傳入本方法,並指明其編碼字符集encodeCharset參數,方法內部會自動對其轉碼
* @see 6)方法內部會自動註冊443作爲SSL端口,若實際使用中reqURL指定的SSL端口非443,可自行嘗試更改方法內部註冊的SSL端口
* @see 7)該方法在解碼響應報文時所採用的編碼,取自響應消息頭中的[Content-Type:text/html; charset=GBK]的charset值
* @see 若響應消息頭中未指定Content-Type屬性,則會使用HttpClient內部默認的ISO-8859-1
* @param reqURL 請求地址
* @param params 請求參數
* @param encodeCharset 編碼字符集,編碼請求數據時用之,當其爲null時,則取HttpClient內部默認的ISO-8859-1編碼請求參數
* @return 遠程主機響應正文
*/
public static String sendPostSSLRequest(String reqURL, Map<String, String> params, String encodeCharset){
String responseContent = "通信失敗";
HttpClient httpClient = new DefaultHttpClient();
httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000);
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 20000);
//創建TrustManager()
//用於解決javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
X509TrustManager trustManager = new X509TrustManager(){
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {return null;}
};
//創建HostnameVerifier
//用於解決javax.net.ssl.SSLException: hostname in certificate didn't match: <123.125.97.66> != <123.125.97.241>
X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier(){
public void verify(String host, SSLSocket ssl) throws IOException {}
public void verify(String host, X509Certificate cert) throws SSLException {}
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {}
public boolean verify(String arg0, SSLSession arg1) {return true;}
};
try {
//TLS1.0與SSL3.0基本上沒有太大的差別,可粗略理解爲TLS是SSL的繼承者,但它們使用的是相同的SSLContext
SSLContext sslContext = SSLContext.getInstance(SSLSocketFactory.TLS);
//使用TrustManager來初始化該上下文,TrustManager只是被SSL的Socket所使用
sslContext.init(null, new TrustManager[]{trustManager}, null);
//創建SSLSocketFactory
SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext, hostnameVerifier);
//通過SchemeRegistry將SSLSocketFactory註冊到HttpClient上
httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, socketFactory));
//創建HttpPost
HttpPost httpPost = new HttpPost(reqURL);
//由於下面使用的是new UrlEncodedFormEntity(....),所以這裏不需要手工指定CONTENT_TYPE爲application/x-www-form-urlencoded
//因爲在查看了HttpClient的源碼後發現,UrlEncodedFormEntity所採用的默認CONTENT_TYPE就是application/x-www-form-urlencoded
//httpPost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded; charset=" + encodeCharset);
//構建POST請求的表單參數
if(null != params){
List<NameValuePair> formParams = new ArrayList<NameValuePair>();
for(Map.Entry<String,String> entry : params.entrySet()){
formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
httpPost.setEntity(new UrlEncodedFormEntity(formParams, encodeCharset));
}
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
if (null != entity) {
responseContent = EntityUtils.toString(entity, ContentType.getOrDefault(entity).getCharset());
EntityUtils.consume(entity);
}
} catch (ConnectTimeoutException cte){
logger.error("請求通信[" + reqURL + "]時連接超時,堆棧軌跡如下", cte);
} catch (SocketTimeoutException ste){
logger.error("請求通信[" + reqURL + "]時讀取超時,堆棧軌跡如下", ste);
} catch (Exception e) {
logger.error("請求通信[" + reqURL + "]時偶遇異常,堆棧軌跡如下", e);
} finally {
httpClient.getConnectionManager().shutdown();
}
return responseContent;
}
}
5..使用util工具調用生產的接口
// 如果調用接口簽名是yw開頭 調用的是生產的服務器地址 ,如果沒有yw 調用的是本地其他機器的地址
String ss = productionUtil.sendPost("yw/production/queryMeasureDetailData.do", data);
JSONObject jsonObj = JSONObject.parseObject(ss);