Spring集成HttpClient实现跨域请求

在配置spring集成httpclient之前我们先说一下Jsonp,这是一种基于页面script标签的src属性实现的跨域请求,相比于httpclient,jsonp有两点很大的缺点,首先,它只能发送get请求,如果发送post请求会造成请求无法解析获取不到数据的问题,再者,如果返回的数据你没有经过配置相应的编码文件来处理你拿到的则会是一堆乱码,这中问题对于httpclient则没那么多约束,他是一个封装了http协议的jar包,基本的请求方法get post put delete他都能实现,当然你得在web.xml文件中配置相应的filter拦截器拦截请求后再设好编码,一般返回的参数都是json字符串,而我们只需要导入jackson或者flexjson或者别的jar包来解析这对象把他转换成你所需要的数据即可。下面来说说httpclient和spring整合的具体配置,不多说直接上代码:

导依赖

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.2</version>
</dependency>

applicationContext.xml文件导入HttpClient.properties

<?xml version="1.0" encoding="UTF-8"?>
<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">

    <!-- 配置注解扫描器 -->
    <context:component-scan base-package="com.lyt.usermanage.service"/>

    <!-- 加载资源文件 -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <!-- 配置资源文件 -->
        <property name="locations">
            <list>
                <value>classpath:jdbc.properties</value>
                <value>classpath:httpclient.properties</value>
            </list>
        </property>
    </bean>
    <!-- 配置连接池,数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">
        <property name="driverClass" value="${driver}"></property>
        <property name="jdbcUrl" value="${url}"></property>
        <property name="user" value="${username}"></property>
        <property name="password" value="${password}"></property>
    </bean>
</beans>

spring-httpclient.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<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-3.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <!-- 定义httpclient连接池 -->
    <bean id="httpClientConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager" destroy-method="close">
        <!-- 设置连接总数 -->
        <property name="maxTotal" value="${http.pool.maxTotal}"></property>
        <!-- 设置每个地址的并发数 -->
        <property name="defaultMaxPerRoute" value="${http.pool.defaultMaxPerRoute}"></property>
    </bean>

    <!-- 定义 HttpClient工厂,这里使用HttpClientBuilder构建-->
    <bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">
        <property name="connectionManager" ref="httpClientConnectionManager"></property>
    </bean>

    <!-- 得到httpClient的实例 -->
    <bean id="httpClient" factory-bean="httpClientBuilder" factory-method="build"/>

    <!-- 定期清理无效的连接 -->
    <bean class="com.lyt.usermanage.thread.IdleConnectionEvictor" destroy-method="shutdown">
        <constructor-arg index="0" ref="httpClientConnectionManager"/>
        <constructor-arg index="1" value="${http.maxIdleTime}"/>
        <constructor-arg index="2" value="MINUTES"/>
    </bean>

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

    <!-- 得到requestConfig实例 -->
    <bean id="requestConfig" factory-bean="requestConfigBuilder" factory-method="build" />


</beans>


</beans>

httpclient.properties文件配置

#从连接池中获取到连接的最长时间
http.request.connectionRequestTimeout=500
#设置链接超时
http.request.connectTimeout=5000
#数据传输的最长时间
http.request.socketTimeout=30000
#提交请求前测试连接是否可用
http.request.staleConnectionCheckEnabled=true
#设置连接总数
http.pool.maxTotal=200
#设置每个地址的并发数
http.pool.defaultMaxPerRoute=100
#设置定时清除无效链接时间
http.maxIdleTime=1

清除无效链接线程类

package com.lyt.common.httpclient;

import org.apache.http.conn.HttpClientConnectionManager;

public class IdleConnectionEvictor extends Thread {

    private final HttpClientConnectionManager connMgr;

    private volatile boolean shutdown;

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

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

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

}

具体的标签属性都做了备注,设置成你需要的即可。还有本人遇到一个问题那就是我自己写的清除无效链接的线程类无法已bean文件的方式配置在整合文件里面不知道为什么?求大神解答,报的错误是:

这里写图片描述

最后则是对doGet()和doPost()请求方法的httpclient工具类的封装,直接上码:

package com.lyt.usermanage.service;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.lyt.usermanage.model.HttpResult;

/**
 * 专门发送http请求的
 * @author Administrator
 *
 */
@Service
public class ApiService implements BeanFactoryAware{

/*  @Autowired
    private  CloseableHttpClient httpclient;

*/  
    @Autowired(required=false)
    private RequestConfig requestConfig;
    /**
     * 
     * @return 响应体的内容
     * @throws IOException 
     * @throws ClientProtocolException 
     */
    public String doGet(String url) throws ClientProtocolException, IOException{

        // 创建http GET请求
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(requestConfig);//设置请求参数
        CloseableHttpResponse response = null;
        try {
            // 执行请求
            response = this.getHttpClient().execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                String content = EntityUtils.toString(response.getEntity(), "UTF-8");
//                System.out.println("内容长度:"+content.length());
                return content;
            }
        } finally {
            if (response != null) {
                response.close();
            }
            //httpclient.close();
        }
        return null;
    }

    /**
     * 带有参数的get请求
     * @param url
     * @return
     * @throws URISyntaxException 
     * @throws IOException 
     * @throws ClientProtocolException 
     */
    public String doGet(String url , Map<String, String> params) throws URISyntaxException, ClientProtocolException, IOException{
        URIBuilder uriBuilder = new URIBuilder(url);
        if(params != null){
            for(String key : params.keySet()){
                uriBuilder.setParameter(key, params.get(key));
            }
        }//http://xxx?ss=ss
        return this.doGet(uriBuilder.build().toString());
    }
    /**
     * 带有参数的post请求
     * @param url
     * @param params
     * @return
     * @throws IOException 
     * @throws ClientProtocolException 
     */
    public HttpResult doPost(String url , Map<String, String> params) throws ClientProtocolException, IOException{


        // 创建http POST请求
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        if(params != null){

            // 设置2个post参数,一个是scope、一个是q
            List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);

            for(String key : params.keySet()){
                parameters.add(new BasicNameValuePair(key, params.get(key)));
            }
            // 构造一个form表单式的实体
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
            // 将请求实体设置到httpPost对象中
            httpPost.setEntity(formEntity);
        }

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

    public HttpResult doPostJson(String url , String json) throws ClientProtocolException, IOException{
         // 创建http POST请求
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        if(StringUtils.isNotBlank(json)){
            //标识出传递的参数是 application/json
            StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(stringEntity);
        }

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

    /**
     * 没有参数的post请求
     * @throws IOException 
     * @throws ClientProtocolException 
     */
    public HttpResult doPost(String url) throws ClientProtocolException, IOException{
        return this.doPost(url, null);
    }

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    private CloseableHttpClient getHttpClient(){
        return this.beanFactory.getBean(CloseableHttpClient.class);
    }
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值