HttpClient

访问接口服务的方式有两种:
1.js访问,有跨域,使用jsonp解决,无跨域,使用ajax。
2.使用java代码访问:通过httpclient

HttpClient简介

HttpClient可以用来提供高效的,最新的,功能丰富的支持Http协议的客户端编程工具包。

使用HttpClient

1.导入依赖
这里写图片描述
2.使用步骤(DoGet)
1.创建CloseableHttpClient对象。通过使用HttpClients的createDefault()方法创建
2.使用有参构造方法创建HttpGet对象,参数为请求的url
3.通过httpclient对象的execute方法执行httpget,返回值为CloseableHttpResponse
4.判断状态是否为200,如果是则返回响应内容。
5.关闭响应
6.关闭httpclient对象
这里写图片描述
如果需要使用带参数的get,那么首先需要定义一个uri,然后使用setParameter设置参数,最后将uri作为参数传入httpget对象中
这里写图片描述
post请求和get请求类似。
这里写图片描述
带有参数的post需要创建一个urlEncodedFormEntity模拟表单的对象,对象的构造方法的参数为一个包含表单中数据的list集合

 public static void main(String[] args) throws Exception {

        // 创建Httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();

        // 创建http POST请求
        HttpPost httpPost = new HttpPost("http://www.oschina.net/search");

     // 伪装成浏览器
        httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36");

        // 设置2个post参数,一个是scope、一个是q
        List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
        parameters.add(new BasicNameValuePair("scope", "project"));
        parameters.add(new BasicNameValuePair("q", "java"));
        parameters.add(new BasicNameValuePair("fromerr", "7nXH76r7"));
        // 构造一个form表单式的实体
        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
        // 将请求实体设置到httpPost对象中
        httpPost.setEntity(formEntity); 

        CloseableHttpResponse response = null;
        try {
            // 执行请求
            response = httpclient.execute(httpPost);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                System.out.println(content);
            }
        } finally {
            if (response != null) {
                response.close();
            }
            httpclient.close();
        }

    }

对于HttpClient的连接,我们也可以使用连接池创建httpClient
这里写图片描述
这里不能关闭连接池
这里写图片描述
使用新线程定期关闭无用的连接

public class ClientEvictExpiredConnections {

    public static void main(String[] args) throws Exception {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        // 设置最大连接数
        cm.setMaxTotal(200);
        // 设置每个主机地址的并发数
        cm.setDefaultMaxPerRoute(20);

        new IdleConnectionEvictor(cm).start();
    }

    public static class IdleConnectionEvictor extends Thread {

        private final HttpClientConnectionManager connMgr;

        private volatile boolean shutdown;

        public IdleConnectionEvictor(HttpClientConnectionManager connMgr) {
            this.connMgr = connMgr;
        }

        @Override
        public void run() {
            try {
                while (!shutdown) {
                    synchronized (this) {
                        wait(5000);
                        // 关闭失效的连接
                        connMgr.closeExpiredConnections();
                    }
                }
            } catch (InterruptedException ex) {
                // 结束
            }
        }

        public void shutdown() {
            shutdown = true;
            synchronized (this) {
                notifyAll();
            }
        }
    }

}

设置请求参数
这里写图片描述

HttpClient与Spring的整合

1.创建applicationContext-httpClient.xml文件
2.创建httpClient.properties配置文件
3.编写applicationContext-httpClient.xml文件

为了将连接的创建交给Spring管理,需要创建连接池的bean,设置连接属性

    <!-- 定义连接管理器 -->
    <bean id="httpClientConnectionManager"
        class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager">
        <property name="maxTotal" value="${http.maxTotal}" />
        <property name="defaultMaxPerRoute" value="${http.defaultMaxPerRoute}" />
    </bean>

使用连接池创建连接时会有这段代码:

CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();

httpClients.custom()的底层实现是通过HttpBuilder

    public static HttpClientBuilder custom() {
        return HttpClientBuilder.create();
    }

HttpClientBuilder的create方法的底层是用过new一个HttpClientBuilder来实现的。
所以需要创建HttpClientBuilder的bean,并设置setConnectionManager属性为连接池对象。

    <!-- httpclient的构建器 -->
    <bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder">
        <property name="connectionManager" ref="httpClientConnectionManager" />
    </bean>

创建HttpClient连接对象,通过HttpBuilder的build方法实现,Spring默认创建的bean都是单例的,因为每个连接对象不可能都相同,所以需要将这个连接对象改为多例。

    <!-- 定义Httpclient对象 -->
    <!-- 该对象是多例的 -->
    <bean class="org.apache.http.impl.client.CloseableHttpClient"
        factory-bean="httpClientBuilder" factory-method="build" scope="prototype">
    </bean>

创建请求参数构造器的bean

<!-- 请求参数的构建器 -->
    <bean id="requestConfigBuilder" class="org.apache.http.client.config.RequestConfig.Builder">
        <!-- 创建连接的最长时间 -->
        <property name="connectTimeout" value="${http.connectTimeout}" />
        <!-- 从连接池中获取到连接的最长时间 -->
        <property name="connectionRequestTimeout" value="${http.connectionRequestTimeout}" />
        <!-- 数据传输的最长时间 -->
        <property name="socketTimeout" value="${http.socketTimeout}" />
        <!-- 提交请求前测试连接是否可用 -->
        <property name="staleConnectionCheckEnabled" value="${http.staleConnectionCheckEnabled}" />
    </bean>

定义请求参数

<!-- 定义请求参数对象 -->
    <bean class="org.apache.http.client.config.RequestConfig"
        factory-bean="requestConfigBuilder" factory-method="build" />

定期关闭无效的连接

<!-- 定期关闭无效连接 -->
    <bean class="com.taotao.web.httpclient.IdleConnectionEvictor">
        <constructor-arg index="0" ref="httpClientConnectionManager" />
    </bean>

整个xml文件

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <!-- 定义连接管理器 -->
    <bean id="httpClientConnectionManager"
        class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager">
        <property name="maxTotal" value="${http.maxTotal}" />
        <property name="defaultMaxPerRoute" value="${http.defaultMaxPerRoute}" />
    </bean>

    <!-- httpclient的构建器 -->
    <bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder">
        <property name="connectionManager" ref="httpClientConnectionManager" />
    </bean>

    <!-- 定义Httpclient对象 -->
    <!-- 该对象是多例的 -->
    <bean class="org.apache.http.impl.client.CloseableHttpClient"
        factory-bean="httpClientBuilder" factory-method="build" scope="prototype">
    </bean>

    <!-- 请求参数的构建器 -->
    <bean id="requestConfigBuilder" class="org.apache.http.client.config.RequestConfig.Builder">
        <!-- 创建连接的最长时间 -->
        <property name="connectTimeout" value="${http.connectTimeout}" />
        <!-- 从连接池中获取到连接的最长时间 -->
        <property name="connectionRequestTimeout" value="${http.connectionRequestTimeout}" />
        <!-- 数据传输的最长时间 -->
        <property name="socketTimeout" value="${http.socketTimeout}" />
        <!-- 提交请求前测试连接是否可用 -->
        <property name="staleConnectionCheckEnabled" value="${http.staleConnectionCheckEnabled}" />
    </bean>

    <!-- 定义请求参数对象 -->
    <bean class="org.apache.http.client.config.RequestConfig"
        factory-bean="requestConfigBuilder" factory-method="build" />

    <!-- 定期关闭无效连接 -->
    <bean class="com.taotao.web.httpclient.IdleConnectionEvictor">
        <constructor-arg index="0" ref="httpClientConnectionManager" />
    </bean>

</beans>

封装ApiService

@Service
public class ApiService {
    @Autowired
    private RequestConfig requestConfig;
    @Autowired
    private CloseableHttpClient httpClient;

    public String doGet(String url) throws ClientProtocolException, IOException
    {
        HttpGet httpGet=new HttpGet(url);
        httpGet.setConfig(requestConfig);
        CloseableHttpResponse response=null;
        try {
            response=this.httpClient.execute(httpGet);
            if(response.getStatusLine().getStatusCode()==200)
            {
                return EntityUtils.toString(response.getEntity(),"UTF-8");
            }
        }finally {
            if(response!=null)
            {
                response.close();
            }
        }
        return null;
    }
    /**
     * 带有参数的doGet
     * @param url
     * @param params
     * @return
     * @throws URISyntaxException 
     * @throws IOException 
     * @throws ClientProtocolException 
     */
    public String doGet(String url,Map<String,String> params) throws URISyntaxException, ClientProtocolException, IOException
    {
        URIBuilder builder=new URIBuilder(url);
        for(Map.Entry<String,String> entry:params.entrySet())
        {
            builder.setParameter(entry.getKey(),entry.getValue());
        }
        return this.doGet(builder.build().toString());
    }
    /**
     * 带参数的doPost
     * @param url
     * @param params
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public HttpResult doPost(String url,Map<String,String> params) throws ClientProtocolException, IOException
    {
        HttpPost httpPost=new HttpPost(url);
        httpPost.setConfig(requestConfig);
        List<NameValuePair> list=new ArrayList<NameValuePair>();
        if(params!=null)
        {
            for(Map.Entry<String,String> entry:params.entrySet())
            {
                list.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));
            }
            //构造form表单的实体
            UrlEncodedFormEntity form=new UrlEncodedFormEntity(list);
            httpPost.setEntity(form);
        }
        CloseableHttpResponse response=null;
        try {
            response=this.httpClient.execute(httpPost);
            return new HttpResult(response.getStatusLine().getStatusCode(),EntityUtils.toString(response.getEntity(),"UTF-8"));
        } finally {
            if(response!=null)
            {
                response.close();
            }
        }

    }
    public HttpResult doPost(String url) throws ClientProtocolException, IOException
    {
        return this.doPost(url,null);
    }
}

但是这里有一个问题,ApiService是单例的,但是CloseableHttpClient是多例的,这里就需要在单例类中使用多例的对象。需要使用BeanFactoryAware

@Service
public class ApiService implements BeanFactoryAware{
    @Autowired
    private RequestConfig requestConfig;
    private BeanFactory beanFactoty;

    public String doGet(String url) throws ClientProtocolException, IOException
    {
        HttpGet httpGet=new HttpGet(url);
        httpGet.setConfig(requestConfig);
        CloseableHttpResponse response=null;
        try {
            response=this.getHttpClient().execute(httpGet);
            if(response.getStatusLine().getStatusCode()==200)
            {
                return EntityUtils.toString(response.getEntity(),"UTF-8");
            }
        }finally {
            if(response!=null)
            {
                response.close();
            }
        }
        return null;
    }
    /**
     * 带有参数的doGet
     * @param url
     * @param params
     * @return
     * @throws URISyntaxException 
     * @throws IOException 
     * @throws ClientProtocolException 
     */
    public String doGet(String url,Map<String,String> params) throws URISyntaxException, ClientProtocolException, IOException
    {
        URIBuilder builder=new URIBuilder(url);
        for(Map.Entry<String,String> entry:params.entrySet())
        {
            builder.setParameter(entry.getKey(),entry.getValue());
        }
        return this.doGet(builder.build().toString());
    }
    /**
     * 带参数的doPost
     * @param url
     * @param params
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public HttpResult doPost(String url,Map<String,String> params) throws ClientProtocolException, IOException
    {
        HttpPost httpPost=new HttpPost(url);
        httpPost.setConfig(requestConfig);
        List<NameValuePair> list=new ArrayList<NameValuePair>();
        if(params!=null)
        {
            for(Map.Entry<String,String> entry:params.entrySet())
            {
                list.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));
            }
            //构造form表单的实体
            UrlEncodedFormEntity form=new UrlEncodedFormEntity(list);
            httpPost.setEntity(form);
        }
        CloseableHttpResponse response=null;
        try {
            response=this.getHttpClient().execute(httpPost);
            return new HttpResult(response.getStatusLine().getStatusCode(),EntityUtils.toString(response.getEntity(),"UTF-8"));
        } finally {
            if(response!=null)
            {
                response.close();
            }
        }

    }
    public HttpResult doPost(String url) throws ClientProtocolException, IOException
    {
        return this.doPost(url,null);
    }
    public CloseableHttpClient getHttpClient()
    {
        return this.beanFactoty.getBean(CloseableHttpClient.class);
    }
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        // TODO Auto-generated method stub
        this.beanFactoty=beanFactory;
    }
}

使用HttpClient实现首页大广告位

//首页提供的格式
[
  {
    "srcB": "http://image.taotao.com/images/2015/03/03/2015030304360302109345.jpg",
    "height": 240,
    "alt": "",
    "width": 670,
    "src": "http://image.taotao.com/images/2015/03/03/2015030304360302109345.jpg",
    "widthB": 550,
    "href": "http://sale.jd.com/act/e0FMkuDhJz35CNt.html?cpdad=1DLSUE",
    "heightB": 240
  },
  {
    "srcB": "http://image.taotao.com/images/2015/03/03/2015030304353109508500.jpg",
    "height": 240,
    "alt": "",
    "width": 670,
    "src": "http://image.taotao.com/images/2015/03/03/2015030304353109508500.jpg",
    "widthB": 550,
    "href": "http://sale.jd.com/act/UMJaAPD2VIXkZn.html?cpdad=1DLSUE",
    "heightB": 240
  },
  {
    "srcB": "http://image.taotao.com/images/2015/03/03/2015030304345761102862.jpg",
    "height": 240,
    "alt": "",
    "width": 670,
    "src": "http://image.taotao.com/images/2015/03/03/2015030304345761102862.jpg",
    "widthB": 550,
    "href": "http://sale.jd.com/act/UMJaAPD2VIXkZn.html?cpdad=1DLSUE",
    "heightB": 240
  },
  {
    "srcB": "http://image.taotao.com/images/2015/03/03/201503030434200950530.jpg",
    "height": 240,
    "alt": "",
    "width": 670,
    "src": "http://image.taotao.com/images/2015/03/03/201503030434200950530.jpg",
    "widthB": 550,
    "href": "http://sale.jd.com/act/kj2pmwMuYCrGsK3g.html?cpdad=1DLSUE",
    "heightB": 240
  },
  {
    "srcB": "http://image.taotao.com/images/2015/03/03/2015030304333327002286.jpg",
    "height": 240,
    "alt": "",
    "width": 670,
    "src": "http://image.taotao.com/images/2015/03/03/2015030304333327002286.jpg",
    "widthB": 550,
    "href": "http://sale.jd.com/act/xcDvNbzAqK0CoG7I.html?cpdad=1DLSUE",
    "heightB": 240
  },
  {
    "srcB": "http://image.taotao.com/images/2015/03/03/2015030304324649807137.jpg",
    "height": 240,
    "alt": "",
    "width": 670,
    "src": "http://image.taotao.com/images/2015/03/03/2015030304324649807137.jpg",
    "widthB": 550,
    "href": "http://sale.jd.com/act/eDpBF1s8KcTOYM.html?cpdad=1DLSUE",
    "heightB": 240
  }
];

后台返回的数据:

{
  "total": 6,
  "rows": [
    {
      "created": 1524471975000,
      "updated": 1524471975000,
      "id": 8,
      "categoryId": null,
      "title": "Ad6",
      "subTitle": null,
      "titleDesc": null,
      "url": "",
      "pic": "http://image.jShop.com/images/2018/04/23/2018042304261396107160.jpg",
      "pic2": "",
      "content": ""
    },
    {
      "created": 1524471965000,
      "updated": 1524471965000,
      "id": 7,
      "categoryId": null,
      "title": "Ad5",
      "subTitle": null,
      "titleDesc": null,
      "url": "",
      "pic": "http://image.jShop.com/images/2018/04/23/2018042304260459104267.jpg",
      "pic2": "",
      "content": ""
    },
    {
      "created": 1524471950000,
      "updated": 1524471950000,
      "id": 6,
      "categoryId": null,
      "title": "Ad4",
      "subTitle": null,
      "titleDesc": null,
      "url": "",
      "pic": "http://image.jShop.com/images/2018/04/23/2018042304254883507713.jpg",
      "pic2": "",
      "content": ""
    },
    {
      "created": 1524471933000,
      "updated": 1524471933000,
      "id": 5,
      "categoryId": null,
      "title": "Ad3",
      "subTitle": null,
      "titleDesc": null,
      "url": "",
      "pic": "http://image.jShop.com/images/2018/04/23/2018042304253144601177.jpg",
      "pic2": "",
      "content": ""
    },
    {
      "created": 1524471921000,
      "updated": 1524471921000,
      "id": 4,
      "categoryId": null,
      "title": "Ad2",
      "subTitle": null,
      "titleDesc": null,
      "url": "www.taobao.com",
      "pic": "http://image.jShop.com/images/2018/04/23/2018042304251892709839.jpg",
      "pic2": "",
      "content": ""
    },
    {
      "created": 1524471899000,
      "updated": 1524471899000,
      "id": 3,
      "categoryId": null,
      "title": "Ad1",
      "subTitle": null,
      "titleDesc": null,
      "url": "www,aa.com",
      "pic": "http://image.jShop.com/images/2018/04/23/2018042304245513805482.jpg",
      "pic2": "",
      "content": ""
    }
  ]
}

解决思路:
通过httpget从后台读取数据然后转换成json格式,提取rows作为json数组,遍历json数组,定义一个list集合,集合中的数据类型位map,将json数组中遍历出来的数据存入map中然后存入list集合中。

@Service
public class IndexService {
    @Autowired
    private ApiService apiService;
    private static final ObjectMapper MAPPER=new ObjectMapper();
    public String queryIndexAd1() {
        // TODO Auto-generated method stub
        String url="http://localhost:8081/rest/api/contentlist?categoryId=36&rows=6&page=1";
        try {
            String jsonDate=this.apiService.doGet(url);
            if(StringUtils.isEmpty(jsonDate))
            {
                return null;
            }
            //解析json数据,封装成前端需要的格式
            JsonNode jsonNode=MAPPER.readTree(jsonDate);
            ArrayNode arrayNode=(ArrayNode) jsonNode.get("rows");
            List<Map<String,Object>> result=new ArrayList<Map<String,Object>>();
            for(JsonNode data:arrayNode)
            {
                Map<String,Object> map=new LinkedHashMap<String,Object>();
                map.put("srcB",data.get("pic").asText());
                map.put("height","240");
                map.put("alt",data.get("title").asText());
                map.put("width",670);
                map.put("src",data.get("pic").asText());
                map.put("widthB",550);
                map.put("href",data.get("url").asText());
                map.put("heightB",240);
                result.add(map);
            }
            return MAPPER.writeValueAsString(result);
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JsonProcessingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

}

通过controller在页面上返回

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值