zoukankan      html  css  js  c++  java
  • 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来向前端页面传递数据

    户枢不蠹,流水不腐

  • 相关阅读:
    类的继承
    垃圾回收GC
    网络层
    数据链路层
    TCP/IP协议分层模型
    OSI参考模型
    浏览器访问一个域名的过程
    Thread&ThreadLocal
    设计模式---单例模式
    内存泄漏和内存溢出
  • 原文地址:https://www.cnblogs.com/yunianzeng/p/12051383.html
Copyright © 2011-2022 走看看