ssm如何呼叫其他伺服器地址介面
阿新 • • 發佈:2019-01-13
1、在專案的resource下的包裡面新建一個production.properties配置檔案,引用該生產的伺服器地址:
production.url=http://xx.xxx.xx.xx:8081/xx //本地其他機器的地址
3、在專案的工具包裡面新建一個工具類ProductionUtil.java
5..使用util工具呼叫生產的介面
// 如果呼叫介面簽名是yw開頭 呼叫的是生產的伺服器地址 ,如果沒有yw 呼叫的是本地其他機器的地址
String ss = productionUtil.sendPost("yw/production/queryMeasureDetailData.do", data);
JSONObject jsonObj = JSONObject.parseObject(ss);
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);