摘要:最近有一個需求,為客戶提供一些RestfulAPI接口,QA使用postman進行測試,但是postman的測試接口與java調用的相似但並不相同,於是想自己寫一個程序去測試RestfulAPI接口,由於使用的是HTTPS,所以還要考慮到對於HTTPS的處理。由於我也是首次使用Java調用restful接口,所以還要研究一番,自然也是查閱了一些資料。
分析:這個問題與模塊之間的調用不同,比如我有兩個模塊frontend和backend,frontend提供前台展示,backend提供數據支持。之前使用過Hession去把backend提供的服務註冊成遠程服務,在frontend端可以通過這種遠程服務直接調到backend的接口。但這對於一個公司自己的一個項目耦合性比較高的情況下使用,沒有問題。但是如果給客戶註冊這種遠程服務,似乎不太好,耦合性太高。所以就考慮用一下方式進行處理。
基本介紹
Restful接口的調用,前端一般使用ajax調用,後端可以使用的方法比較多,
本次介紹三種:
1.HttpURLConnection實現
2.HttpClient實現
3.Spring的RestTemplate
一、HttpClient
HttpClient大家也許比較熟悉但又比較陌生,熟悉是知道他可以遠程調用比如請求一個URL,然後在response裡獲取到返回狀態和返回信息,但是今天講的稍微複雜一點,因為今天的主題是HTTPS,這個牽涉到證書或用戶認證的問題。
確定使用HttpClient之後,查詢相關資料,發現HttpClient的新版本與老版本不同,隨然兼容老版本,但已經不提倡老版本是使用方式,很多都已經標記為過時的方法或類。今天就分別使用老版本4.2和最新版本4.5.3來寫代碼。
老版本4.2
需要認證
在準備證書階段選擇的是使用證書認證
package com.darren.test.https.v42;import java.io.File;import java.io.FileInputStream;import java.security.KeyStore;import org.apache.http.conn.ssl.SSLSocketFactory;public class HTTPSCertifiedClient extends HTTPSClient {public HTTPSCertifiedClient() {}@Override public void prepareCertificate() throws Exception {// 獲得密匙庫KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());FileInputStream instream = new FileInputStream( new File("C:/Users/zhda6001/Downloads/software/xxx.keystore"));// FileInputStream instream = new FileInputStream(new File("C:/Users/zhda6001/Downloads/xxx.keystore")); // 密匙庫的密碼trustStore.load(instream, "password".toCharArray());// 註冊密匙庫this.socketFactory = new SSLSocketFactory(trustStore);// 不校驗域名socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);}}跳過認證
在準備證書階段選擇的是跳過認證
package com.darren.test.https.v42;import java.security.cert.CertificateException;import java.security.cert.X509Certificate;import javax.net.ssl.SSLContext;import javax.net.ssl.TrustManager;import javax.net.ssl.X509TrustManager;import org.apache.http.conn.ssl.SSLSocketFactory;public class HTTPSTrustClient extends HTTPSClient {public HTTPSTrustClient() {}@Override public void prepareCertificate() throws Exception {// 跳過證書驗證SSLContext ctx = SSLContext.getInstance("TLS");X509TrustManager tm = new X509TrustManager() {@Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}@Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}@Override public X509Certificate[] getAcceptedIssuers() {return null;}};// 設置成已信任的證書ctx.init(null, new TrustManager[] {tm}, null);// 穿件SSL socket 工廠,並且設置不檢查host名稱this.socketFactory = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);}}總結
現在發現這兩個類都繼承了同一個類HTTPSClient,並且HTTPSClient繼承了DefaultHttpClient類,可以發現,這裡使用了模板方法模式。
package com.darren.test.https.v42;import org.apache.http.conn.ClientConnectionManager;import org.apache.http.conn.scheme.Scheme;import org.apache.http.conn.scheme.SchemeRegistry;import org.apache.http.conn.ssl.SSLSocketFactory;import org.apache.http.impl.client.DefaultHttpClient;public abstract class HTTPSClient extends DefaultHttpClient {protected SSLSocketFactory socketFactory;/** * 初始化HTTPSClient * * @return 返回當前實例* @throws Exception */public HTTPSClient init() throws Exception {this.prepareCertificate();this.regist();return this;}/** * 準備證書驗證* * @throws Exception */public abstract void prepareCertificate() throws Exception;/** * 註冊協議和端口, 此方法也可以被子類重寫*/protected void regist() {ClientConnectionManager ccm = this.getConnectionManager();SchemeRegistry sr = ccm.getSchemeRegistry();sr.register(new Scheme("https", 443, socketFactory));}}下邊是工具類
package com.darren.test.https.v42;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.Set;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.NameValuePair;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.client.methods.HttpRequestBase;import org.apache.http.message.BasicNameValuePair;import org.apache.http.util.EntityUtils;public class HTTPSClientUtil {private static final String DEFAULT_CHARSET = "UTF-8";public static String doPost(HTTPSClient httpsClient, String url, Map<String, String> paramHeader, Map<String, String> paramBody) throws Exception {return doPost(httpsClient, url, paramHeader, paramBody, DEFAULT_CHARSET);}public static String doPost(HTTPSClient httpsClient, String url, Map<String, String> paramHeader, Map<String, String> paramBody, String charset) throws Exception {String result = null;HttpPost httpPost = new HttpPost(url);setHeader(httpPost, paramHeader);setBody(httpPost, paramBody, charset);HttpResponse response = httpsClient.execute(httpPost);if (response != null) {HttpEntity resEntity = response.getEntity();if (resEntity != null) {result = EntityUtils.toString(resEntity, charset);}}return result;}public static String doGet(HTTPSClient httpsClient, String url, Map<String, String> paramHeader, Map<String, String> paramBody) throws Exception {return doGet(httpsClient, url, paramHeader, paramBody, DEFAULT_CHARSET);}public static String doGet(HTTPSClient httpsClient, String url, Map<String, String> paramHeader, Map<String, String> paramBody, String charset) throws Exception {String result = null;HttpGet httpGet = new HttpGet(url);setHeader(httpGet, paramHeader);HttpResponse response = httpsClient.execute(httpGet);if (response != null) {HttpEntity resEntity = response.getEntity();if (resEntity != null) {result = EntityUtils.toString(resEntity, charset);}}return result;}private static void setHeader(HttpRequestBase request, Map<String, String> paramHeader) {// 設置Header if (paramHeader != null) {Set<String> keySet = paramHeader.keySet();for (String key : keySet) {request.addHeader(key, paramHeader.get(key));}}}private static void setBody(HttpPost httpPost, Map<String, String> paramBody, String charset) throws Exception {// 設置參數if (paramBody != null) {List<NameValuePair> list = new ArrayList<NameValuePair>();Set<String> keySet = paramBody.keySet();for (String key : keySet) {list.add(new BasicNameValuePair(key, paramBody.get(key)));}if (list.size() > 0) {UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, charset);httpPost.setEntity(entity);}}}}然後是測試類:
package com.darren.test.https.v42;import java.util.HashMap;import java.util.Map;public class HTTPSClientTest {public static void main(String[] args) throws Exception {HTTPSClient httpsClient = null;httpsClient = new HTTPSTrustClient().init();//httpsClient = new HTTPSCertifiedClient().init(); String url = "https://1.2.6.2:8011/xxx/api/getToken";//String url = "https://1.2.6.2:8011/xxx/api/getHealth"; Map<String, String> paramHeader = new HashMap<>();//paramHeader.put("Content-Type", "application/json"); paramHeader.put("Accept", "application/xml");Map<String, String> paramBody = new HashMap<>();paramBody.put("client_id", "[email protected]");paramBody.put("client_secret", "P@ssword_1");String result = HTTPSClientUtil.doPost(httpsClient, url, paramHeader, paramBody);//String result = HTTPSClientUtil.doGet(httpsClient, url, null, null); System.out.println(result);}}返回信息:
<?xml version="1.0" encoding="utf-8"?> <token>jkf8RL0sw+Skkflj8RbKI5hP1bEQK8PrCuTZPpBINqMYKRMxY1kWCjmCfT191Zpp88VV1aGHW8oYNWjEYS0axpLuGAX89ejCoWNbikCc1UvfyesXHLktcJqyUFiVjevhrEQxJPHncLQYWP+Xse5oD9X8vKFKk7InNTMRzQK7YBTZ/e3U7gswM/5cvAHFl6o9rEq9cWPXavZNohyvnXsohSzDo+BXAtXxa1xpEDLy/8h/UaP4n4dlZDJJ3B8t1Xh+CRRIoMOPxf7c5wKhHtOkEOeXW+xoPQKKSx5CKWwJpPuGIIFWF/PaqWg+JUOsVT7QGdPv8PMWJ9DwEwjTdxguDg==</token>
新版本4.5.3
需要認證
package com.darren.test.https.v45;import java.io.File;import java.io.FileInputStream;import java.security.KeyStore;import javax.net.ssl.SSLContext;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.conn.ssl.TrustSelfSignedStrategy;import org.apache.http.ssl.SSLContexts;public class HTTPSCertifiedClient extends HTTPSClient {public HTTPSCertifiedClient() {}@Override public void prepareCertificate() throws Exception {// 獲得密匙庫KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());FileInputStream instream = new FileInputStream( new File("C:/Users/zhda6001/Downloads/software/xxx.keystore"));// FileInputStream instream = new FileInputStream(new File("C:/Users/zhda6001/Downloads/xxx.keystore")); try {// 密匙庫的密碼trustStore.load(instream, "password".toCharArray());}finally {instream.close();}SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, TrustSelfSignedStrategy.INSTANCE) .build();this.connectionSocketFactory = new SSLConnectionSocketFactory(sslcontext);}}跳過認證
package com.darren.test.https.v45;import java.security.cert.CertificateException;import java.security.cert.X509Certificate;import javax.net.ssl.SSLContext;import javax.net.ssl.TrustManager;import javax.net.ssl.X509TrustManager;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;public class HTTPSTrustClient extends HTTPSClient {public HTTPSTrustClient() {}@Override public void prepareCertificate() throws Exception {// 跳過證書驗證SSLContext ctx = SSLContext.getInstance("TLS");X509TrustManager tm = new X509TrustManager() {@Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}@Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}@Override public X509Certificate[] getAcceptedIssuers() {return null;}};// 設置成已信任的證書ctx.init(null, new TrustManager[] {tm}, null);this.connectionSocketFactory = new SSLConnectionSocketFactory(ctx);}}總結
package com.darren.test.https.v45;import org.apache.http.config.Registry;import org.apache.http.config.RegistryBuilder;import org.apache.http.conn.socket.ConnectionSocketFactory;import org.apache.http.conn.socket.PlainConnectionSocketFactory;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClientBuilder;import org.apache.http.impl.client.HttpClients;import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;public abstract class HTTPSClient extends HttpClientBuilder {private CloseableHttpClient client;protected ConnectionSocketFactory connectionSocketFactory;/** * 初始化HTTPSClient * * @return 返回當前實例* @throws Exception */public CloseableHttpClient init() throws Exception {this.prepareCertificate();this.regist();return this.client;}/** * 準備證書驗證* * @throws Exception */public abstract void prepareCertificate() throws Exception;/** * 註冊協議和端口, 此方法也可以被子類重寫*/protected void regist() {// 設置協議http和https對應的處理socket鏈接工廠的對象Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", this.connectionSocketFactory) .build();PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);HttpClients.custom().setConnectionManager(connManager);// 創建自定義的httpclient對象this.client = HttpClients.custom().setConnectionManager(connManager).build();// CloseableHttpClient client = HttpClients.createDefault();}}工具類:
package com.darren.test.https.v45;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.Set;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.NameValuePair;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.client.methods.HttpRequestBase;import org.apache.http.message.BasicNameValuePair;import org.apache.http.util.EntityUtils;public class HTTPSClientUtil {private static final String DEFAULT_CHARSET = "UTF-8";public static String doPost(HttpClient httpClient, String url, Map<String, String> paramHeader, Map<String, String> paramBody) throws Exception {return doPost(httpClient, url, paramHeader, paramBody, DEFAULT_CHARSET);}public static String doPost(HttpClient httpClient, String url, Map<String, String> paramHeader, Map<String, String> paramBody, String charset) throws Exception {String result = null;HttpPost httpPost = new HttpPost(url);setHeader(httpPost, paramHeader);setBody(httpPost, paramBody, charset);HttpResponse response = httpClient.execute(httpPost);if (response != null) {HttpEntity resEntity = response.getEntity();if (resEntity != null) {result = EntityUtils.toString(resEntity, charset);}}return result;}public static String doGet(HttpClient httpClient, String url, Map<String, String> paramHeader, Map<String, String> paramBody) throws Exception {return doGet(httpClient, url, paramHeader, paramBody, DEFAULT_CHARSET);}public static String doGet(HttpClient httpClient, String url, Map<String, String> paramHeader, Map<String, String> paramBody, String charset) throws Exception {String result = null;HttpGet httpGet = new HttpGet(url);setHeader(httpGet, paramHeader);HttpResponse response = httpClient.execute(httpGet);if (response != null) {HttpEntity resEntity = response.getEntity();if (resEntity != null) {result = EntityUtils.toString(resEntity, charset);}}return result;}private static void setHeader(HttpRequestBase request, Map<String, String> paramHeader) {// 設置Header if (paramHeader != null) {Set<String> keySet = paramHeader.keySet();for (String key : keySet) {request.addHeader(key, paramHeader.get(key));}}}private static void setBody(HttpPost httpPost, Map<String, String> paramBody, String charset) throws Exception {// 設置參數if (paramBody != null) {List<NameValuePair> list = new ArrayList<NameValuePair>();Set<String> keySet = paramBody.keySet();for (String key : keySet) {list.add(new BasicNameValuePair(key, paramBody.get(key)));}if (list.size() > 0) {UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, charset);httpPost.setEntity(entity);}}}}測試類:
package com.darren.test.https.v45;import java.util.HashMap;import java.util.Map;import org.apache.http.client.HttpClient;public class HTTPSClientTest {public static void main(String[] args) throws Exception {HttpClient httpClient = null;//httpClient = new HTTPSTrustClient().init(); httpClient = new HTTPSCertifiedClient().init();String url = "https://1.2.6.2:8011/xxx/api/getToken";//String url = "https://1.2.6.2:8011/xxx/api/getHealth"; Map<String, String> paramHeader = new HashMap<>();paramHeader.put("Accept", "application/xml");Map<String, String> paramBody = new HashMap<>();paramBody.put("client_id", "[email protected]");paramBody.put("client_secret", "P@ssword_1");String result = HTTPSClientUtil.doPost(httpClient, url, paramHeader, paramBody);//String result = HTTPSClientUtil.doGet(httpsClient, url, null, null); System.out.println(result);}}結果:
<?xml version="1.0" encoding="utf-8"?> <token>RxitF9//7NxwXJS2cjIjYhLtvzUNvMZxxEQtGN0u07sC9ysJeIbPqte3hCjULSkoXPEUYGUVeyI9jv7/WikLrzxYKc3OSpaTSM0kCbCKphu0TB2Cn/nfzv9fMLueOWFBdyz+N0sEiI9K+0Gp7920DFEncn17wUJVmC0u2jwvM5FAjQKmilwodXZ6a0Dq+D7dQDJwVcwxBvJ2ilhyIb3pr805Vppmi9atXrVAKO0ODa006wEJFOfcgyG5p70wpJ5rrBL85vfy9WCvkd1R7j6NVjhXgH2gNimHkjEJorMjdXW2gKiUsiWsELi/XPswao7/CTWNwTnctGK8PX2ZUB0ZfA==</token>
二、HttpURLConnection
@Controllerpublic class RestfulAction {@Autowired private UserService userService;// 修改@RequestMapping(value = "put/{param}", method = RequestMethod.PUT) public @ResponseBody String put(@PathVariable String param) {return "put:" + param;}// 新增@RequestMapping(value = "post/{param}", method = RequestMethod.POST) public @ResponseBody String post(@PathVariable String param,String id,String name) {System.out.println("id:"+id);System.out.println("name:"+name);return "post:" + param;}// 刪除@RequestMapping(value = "delete/{param}", method = RequestMethod.DELETE) public @ResponseBody String delete(@PathVariable String param) {return "delete:" + param;}// 查找@RequestMapping(value = "get/{param}", method = RequestMethod.GET) public @ResponseBody String get(@PathVariable String param) {return "get:" + param;}// HttpURLConnection 方式調用Restful接口// 調用接口@RequestMapping(value = "dealCon/{param}") public @ResponseBody String dealCon(@PathVariable String param) {try {String url = "http://localhost:8080/tao-manager-web/";url+=(param+"/xxx");URL restServiceURL = new URL(url);HttpURLConnection httpConnection = (HttpURLConnection) restServiceURL .openConnection();//param 輸入小寫,轉換成GET POST DELETE PUT httpConnection.setRequestMethod(param.toUpperCase());// httpConnection.setRequestProperty("Accept", "application/json");if("post".equals(param)){//打開輸出開關httpConnection.setDoOutput(true);// httpConnection.setDoInput(true);//傳遞參數String input = "&id="+ URLEncoder.encode("abc", "UTF-8");input+="&name="+ URLEncoder.encode("啊啊啊", "UTF-8");OutputStream outputStream = httpConnection.getOutputStream();outputStream.write(input.getBytes());outputStream.flush();}if (httpConnection.getResponseCode() != 200) {throw new RuntimeException( "HTTP GET Request Failed with Error code : " + httpConnection.getResponseCode());}BufferedReader responseBuffer = new BufferedReader( new InputStreamReader((httpConnection.getInputStream())));String output;System.out.println("Output from Server: /n");while ((output = responseBuffer.readLine()) != null) {System.out.println(output);}httpConnection.disconnect();}catch (MalformedURLException e) {e.printStackTrace();}catch (IOException e) {e.printStackTrace();}return "success";}}三、Spring的RestTemplate
springmvc.xml增加
<!-- 配置RestTemplate --> <!--Http client Factory --> <bean id="httpClientFactory" > <property name="connectTimeout" value="10000" /> <property name="readTimeout" value="10000" /> </bean> <!--RestTemplate --> <bean id="restTemplate"> <constructor-arg ref="httpClientFactory" /> </bean>
controller
@Controllerpublic class RestTemplateAction {@Autowired private RestTemplate template;@RequestMapping("RestTem") public @ResponseBody User RestTem(String method) {User user = null;//查找if ("get".equals(method)) {user = template.getForObject( "http://localhost:8080/tao-manager-web/get/{id}", User.class, "嗚嗚嗚嗚");//getForEntity與getForObject的區別是可以獲取返回值和狀態、頭等信息ResponseEntity<User> re = template. getForEntity("http://localhost:8080/tao-manager-web/get/{id}", User.class, "嗚嗚嗚嗚");System.out.println(re.getStatusCode());System.out.println(re.getBody().getUsername());//新增} else if ("post".equals(method)) {HttpHeaders headers = new HttpHeaders();headers.add("X-Auth-Token", UUID.randomUUID().toString());MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();postParameters.add("id", "啊啊啊");postParameters.add("name", "部版本");HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>( postParameters, headers);user = template.postForObject( "http://localhost:8080/tao-manager-web/post/aaa", requestEntity, User.class);//刪除} else if ("delete".equals(method)) {template.delete("http://localhost:8080/tao-manager-web/delete/{id}","aaa");//修改} else if ("put".equals(method)) {template.put("http://localhost:8080/tao-manager-web/put/{id}",null,"bbb");}return user;}}以上就是本文關於淺談java調用Restful API接口的方式的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站其他Java相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!