浅谈java调用Restful API接口的方式
摘要:最近有一个需求,为客户提供一些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,String> paramBody) throws Exception { return doPost(httpsClient,url,paramHeader,paramBody,DEFAULT_CHARSET); } public static String doPost(HTTPSClient httpsClient,String> paramBody,String charset) throws Exception { String result = null; HttpPost httpPost = new HttpPost(url); setHeader(httpPost,paramHeader); setBody(httpPost,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> paramBody) throws Exception { return doGet(httpsClient,DEFAULT_CHARSET); } public static String doGet(HTTPSClient httpsClient,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,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,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","ankur.tandon.ap@xxx.com"); paramBody.put("client_secret","P@ssword_1"); String result = HTTPSClientUtil.doPost(httpsClient,paramBody); //String result = HTTPSClientUtil.doGet(httpsClient,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,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> paramBody) throws Exception { return doPost(httpClient,DEFAULT_CHARSET); } public static String doPost(HttpClient httpClient,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> paramBody) throws Exception { return doGet(httpClient,DEFAULT_CHARSET); } public static String doGet(HttpClient httpClient,paramHeader); HttpResponse response = httpClient.execute(httpGet); if (response != null) { HttpEntity resEntity = response.getEntity(); if (resEntity != null) { result = EntityUtils.toString(resEntity,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","P@ssword_1"); String result = HTTPSClientUtil.doPost(httpClient,null); System.out.println(result); } } 结果: <?xml version="1.0" encoding="utf-8"?> <token>RxitF9//7NxwXJS2cjIjYhLtvzUNvMZxxEQtGN0u07sC9ysJeIbPqte3hCjULSkoXPEUYGUVeyI9jv7/WikLrzxYKc3OSpaTSM0kCbCKphu0TB2Cn/nfzv9fMLueOWFBdyz+N0sEiI9K+0Gp7920DFEncn17wUJVmC0u2jwvM5FAjQKmilwodXZ6a0Dq+D7dQDJwVcwxBvJ2ilhyIb3pr805Vppmi9atXrVAKO0ODa006wEJFOfcgyG5p70wpJ5rrBL85vfy9WCvkd1R7j6NVjhXgH2gNimHkjEJorMjdXW2gKiUsiWsELi/XPswao7/CTWNwTnctGK8PX2ZUB0ZfA==</token> 二、HttpURLConnection @Controller public 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" class="org.springframework.http.client.SimpleClientHttpRequestFactory"> <property name="connectTimeout" value="10000" /> <property name="readTimeout" value="10000" /> </bean> <!--RestTemplate --> <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"> <constructor-arg ref="httpClientFactory" /> </bean> controller @Controller public 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}","呜呜呜呜"); 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}","bbb"); } return user; } } 以上就是本文关于浅谈java调用Restful API接口的方式的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他Java相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |