httpClient接口调用
httpClient作用:通过java代码模拟浏览器发起请求.
解决的问题:后台服务器之间的跨域问题.
1.快速案例:
import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; @Test public void testGet() throws IOException {//通过java代码模拟浏览器发起请求 String url="https://www.centbrowser.cn/index.html"; HttpGet get=new HttpGet(url); HttpClient htClient = HttpClients.createDefault(); HttpResponse response = htClient.execute(get); if (200==response.getStatusLine().getStatusCode()) { String result= EntityUtils.toString(response.getEntity(),"utf-8"); System.out.println(result); } }
缺点:1.每次发起界面请求时,HttpClient都要取创建对象,会导致访问速度效率很低,2.代码层面:每次调用都要写这么多代码,代码复用性低;
说明:HttpClient是一个接口,他的实现类CloseableHttpClient注入给他
2.将CloseableHttpClient对象池化思想(涉及模式:设计模式),将HttpClient的api进行封装:
2.1)将CloseableHttpClient对象池化思想:
package com.jt.config; import javax.annotation.PreDestroy; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.pool.PoolStats; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component //交给spring容器管理 public class HttpClientClose extends Thread{ @Autowired private PoolingHttpClientConnectionManager manage; private volatile boolean shutdown; //开关 volatitle表示多线程可变数据,一个线程修改,其他线程立即修改 public HttpClientClose() { ///System.out.println("执行构造方法,实例化对象"); //线程开启启动 this.start(); } @Override public void run() { try { //如果服务没有关闭,执行线程 while(!shutdown) { synchronized (this) { wait(5000); //等待5秒 //System.out.println("线程开始执行,关闭超时链接"); //关闭超时的链接 PoolStats stats = manage.getTotalStats(); int av = stats.getAvailable(); //获取可用的线程数量 int pend = stats.getPending(); //获取阻塞的线程数量 int lea = stats.getLeased(); //获取当前正在使用的链接数量 int max = stats.getMax(); //System.out.println("max/"+max+": av/"+av+": pend/"+pend+": lea/"+lea); manage.closeExpiredConnections(); } } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(); } super.run(); } //关闭清理无效连接的线程 @PreDestroy //容器关闭时执行该方法. public void shutdown() { shutdown = true; synchronized (this) { //System.out.println("关闭全部链接!!"); notifyAll(); //全部从等待中唤醒.执行关闭操作; } } }
2.2)将HttpClient的api进行封装:
编辑配置类://其中主要的bean对象:CloseableHttpClient;RequestConfig
package com.jt.config; import org.apache.http.client.config.RequestConfig; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @Configuration @PropertySource(value="classpath:/properties/httpClient.properties") public class HttpClientConfig { @Value("${http.maxTotal}") private Integer maxTotal; //最大连接数 @Value("${http.defaultMaxPerRoute}") private Integer defaultMaxPerRoute; //最大并发链接数 @Value("${http.connectTimeout}") private Integer connectTimeout; //创建链接的最大时间 @Value("${http.connectionRequestTimeout}") private Integer connectionRequestTimeout; //链接获取超时时间 @Value("${http.socketTimeout}") private Integer socketTimeout; //数据传输最长时间 @Value("${http.staleConnectionCheckEnabled}") private boolean staleConnectionCheckEnabled; //提交时检查链接是否可用 //定义httpClient链接池 @Bean(name="httpClientConnectionManager") public PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager() { PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(); manager.setMaxTotal(maxTotal); //设定最大链接数 manager.setDefaultMaxPerRoute(defaultMaxPerRoute); //设定并发链接数 return manager; } //定义HttpClient /** * 实例化连接池,设置连接池管理器。 * 这里需要以参数形式注入上面实例化的连接池管理器 @Qualifier 指定bean标签进行注入 */ @Bean(name = "httpClientBuilder") public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager")PoolingHttpClientConnectionManager httpClientConnectionManager){ //HttpClientBuilder中的构造方法被protected修饰,所以这里不能直接使用new来实例化一个HttpClientBuilder,可以使用HttpClientBuilder提供的静态方法create()来获取HttpClientBuilder对象 HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); httpClientBuilder.setConnectionManager(httpClientConnectionManager); return httpClientBuilder; } /** * 注入连接池,用于获取httpClient * @param httpClientBuilder * @return */ @Bean public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder){ return httpClientBuilder.build(); } /** * Builder是RequestConfig的一个内部类 * 通过RequestConfig的custom方法来获取到一个Builder对象 * 设置builder的连接信息 * @return */ @Bean(name = "builder") public RequestConfig.Builder getBuilder(){ RequestConfig.Builder builder = RequestConfig.custom(); return builder.setConnectTimeout(connectTimeout) .setConnectionRequestTimeout(connectionRequestTimeout) .setSocketTimeout(socketTimeout) .setStaleConnectionCheckEnabled(staleConnectionCheckEnabled); } /** * 使用builder构建一个RequestConfig对象 * @param builder * @return */ @Bean public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder){ return builder.build(); } }
编辑关闭连接配置文件:
package com.jt.config; import javax.annotation.PreDestroy; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.pool.PoolStats; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component //交给spring容器管理 public class HttpClientClose extends Thread{ @Autowired private PoolingHttpClientConnectionManager manage; private volatile boolean shutdown; //开关 volatitle表示多线程可变数据,一个线程修改,其他线程立即修改 public HttpClientClose() { ///System.out.println("执行构造方法,实例化对象"); //线程开启启动 this.start(); } @Override public void run() { try { //如果服务没有关闭,执行线程 while(!shutdown) { synchronized (this) { wait(5000); //等待5秒 //System.out.println("线程开始执行,关闭超时链接"); //关闭超时的链接 PoolStats stats = manage.getTotalStats(); int av = stats.getAvailable(); //获取可用的线程数量 int pend = stats.getPending(); //获取阻塞的线程数量 int lea = stats.getLeased(); //获取当前正在使用的链接数量 int max = stats.getMax(); //System.out.println("max/"+max+": av/"+av+": pend/"+pend+": lea/"+lea); manage.closeExpiredConnections(); } } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(); } super.run(); } //关闭清理无效连接的线程 @PreDestroy //容器关闭时执行该方法. public void shutdown() { shutdown = true; synchronized (this) { //System.out.println("关闭全部链接!!"); notifyAll(); //全部从等待中唤醒.执行关闭操作; } } }
封装,相当于一个util:
package com.jt.util; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.io.IOException; import java.util.Iterator; import java.util.Map; import java.util.Set; @Service public class HttpClientService {//通过java代码模拟客户端给服务器端发起请求 @Autowired private CloseableHttpClient htClient; //超时时间 @Autowired private RequestConfig requestConfig; public String doGet(String url, Map<String,String> params,String charset) { if (StringUtils.isEmpty(charset)){ charset="UTF-8"; } if (params!=null){ url +="?"; Set<Map.Entry<String, String>> entries = params.entrySet(); Iterator<Map.Entry<String, String>> iterator = entries.iterator(); while (iterator.hasNext()){ Map.Entry<String, String> entry = iterator.next(); String key = entry.getKey(); String value = entry.getValue(); url +=key+"="+value+"&"; } url = url.substring(0, url.length() - 1);//包含所有请求信息 } String result=null; HttpGet get=new HttpGet(url);//将所用请求信息封装在这个对象里面 get.setConfig(requestConfig);//设置超时时间 try { //System.out.println(htClient); CloseableHttpResponse response = htClient.execute(get);//执行请求 if (200==response.getStatusLine().getStatusCode()) { System.out.println("手动java请求的结果"+response.getEntity());//跨域后返回的结果 result= EntityUtils.toString(response.getEntity(),charset); System.out.println("result结果:"+result); } } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } return result; } public String doGet(String url){ return doGet(url,null,null); } public String doGet(String url,Map<String,String> params){ return doGet(url,params,null); } public <T> T doGet(String url,Map<String,String> params,Class<T> targetClass,String charset) { String result = doGet(url,params); return ObjectMapperUtil.toObject(result, targetClass); } public <T> T doGet(String url,Class<T> targetClass) { String result = doGet(url); return ObjectMapperUtil.toObject(result, targetClass); } }
最终整合测试:
@Autowired
private CloseableHttpClient htClient;//bean池里面拿对象
//超时时间
@Autowired
private RequestConfig requestConfig;
@Test public void test04(){ String url = "http://manage.jt.com/web/item/findItemDescById"; Map<String,String> params = new HashMap<String, String>(); params.put("itemId", "536563"); ItemDesc itemDesc = httpClint.doGet(url, params, ItemDesc.class,null); System.out.println(itemDesc); }
小点:使用model来向前端页面传递数据
户枢不蠹,流水不腐