HttpClient与Spring的整合

1、HttpClient的用法简介

     关于JavaScript跨域的请求,可以在后台使用HttpClient去请求,再把请求结果发回给前台。已解决JavaScript跨域访问的问题。

2、HttpClient与Spring的整合文件

     2.1 httpclient.properties的配置

#设置最大连接数
http.maxTotal=200
#设置每个主机的并发数
http.defaultMaxPerRoute=20

#创建连接的最长时间
http.connectTimeout=1000
#从连接池中获取到连接的最长时间
http.connectionRequestTimeout=500
#数据传输的最长时间
http.socketTimeout=10000
#提交请求前测试连接是否可用
http.staleConnectionCheckEnabled=true

     2.2 log4j.properties的配置

log4j.rootLogger=DEBUG,A1
log4j.logger.com.taotao = DEBUG
log4j.logger.org.mybatis = DEBUG

log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

     2.3 bean-properties.xml的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans  
         http://www.springframework.org/schema/beans/spring-beans.xsd  
         http://www.springframework.org/schema/context  
         http://www.springframework.org/schema/context/spring-context.xsd  
         http://www.springframework.org/schema/aop  
         http://www.springframework.org/schema/aop/spring-aop.xsd  
         http://www.springframework.org/schema/tx  
         http://www.springframework.org/schema/tx/spring-tx.xsd">
	<!-- 使用spring自带的占位符替换功能 -->
	<bean
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<!-- 允许JVM参数覆盖 -->
		<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
		<!-- 忽略没有找到的资源文件 -->
		<property name="ignoreResourceNotFound" value="true" />
		<!-- 配置资源文件 -->
		<property name="locations">
			<list>
				<value>classpath:httpclient.properties</value>
			</list>
		</property>
	</bean>
	<!--需要扫描的package -->
	<context:component-scan base-package="com.web.service" />
</beans>       

     2.4 bean-httpclient.xml的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans  
         http://www.springframework.org/schema/beans/spring-beans.xsd  
         http://www.springframework.org/schema/context  
         http://www.springframework.org/schema/context/spring-context.xsd  
         http://www.springframework.org/schema/aop  
         http://www.springframework.org/schema/aop/spring-aop.xsd  
         http://www.springframework.org/schema/tx  
         http://www.springframework.org/schema/tx/spring-tx.xsd">

	<!--创建httpclient的连接池 -->
	<bean id="httpClientConnectionManager"
		class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager"
		destroy-method="shutdown">
		<!-- 设置最大连接数 -->
		<property name="maxTotal" value="${http.maxTotal}" />
		<!-- 设置每个主机的并发数 -->
		<property name="defaultMaxPerRoute" value="${http.defaultMaxPerRoute}" />
	</bean>

	<!-- 创建httpClient对象 -->
	<!-- httpClient是由HttpClientBuilder通过build方法创建,这个可以设置连接池 -->
	<!-- 1.创建HttpClientBuilder -->
	<bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder">
		<!--设置连接池 -->
		<property name="connectionManager" ref="httpClientConnectionManager"></property>
	</bean>
	<!-- 2.创建httpClient -->
	<!-- 通过httpClientBulider得到httpClient对象,并且设置httpClient为多利模式 -->
	<!-- 要保证httpClient为多利,以为每次都是新的http请求 -->
	<bean id="httpClient" class="org.apache.http.impl.client.CloseableHttpClient"
		factory-bean="httpClientBuilder" factory-method="build" scope="prototype" />

	<!-- 构造请求参数 -->
	<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 id="requestConfig" class="org.apache.http.client.config.RequestConfig"
		factory-bean="requestConfigBuilder" factory-method="build" />


	<!--清理无效的http连接 -->
	<bean class="com.web.service.IdleConnectionEvictor"
		destroy-method="shutdown">
		<constructor-arg index="0" ref="httpClientConnectionManager"></constructor-arg>
	</bean>
</beans>       

3、 封装了HttpClient操作的HttpService.java的实现

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
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.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class HttpService {

	// 创建Httpclient对象
	@Autowired(required = false)
	private CloseableHttpClient httpClient;

	// 请求信息的配置
	@Autowired(required = false)
	private RequestConfig requestConfig;

	/**
	 * 执行Get请求
	 * 
	 * @param url
	 * @return 请求到的内容
	 * @throws URISyntaxException
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	public String doGet(String url) throws URISyntaxException,
			ClientProtocolException, IOException {
		return doGet(url, null);
	}

	/**
	 * 执行Get请求
	 * 
	 * @param url
	 * @param params
	 *            请求中的参数
	 * @return 请求到的内容
	 * @throws URISyntaxException
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	public String doGet(String url, Map<String, Object> params)
			throws URISyntaxException, ClientProtocolException, IOException {
		// 定义请求的参数
		URI uri = null;
		if (params != null) {
			URIBuilder builder = new URIBuilder(url);
			for (Map.Entry<String, Object> entry : params.entrySet()) {
				builder.addParameter(entry.getKey(),
						String.valueOf(entry.getValue()));
			}
			uri = builder.build();
		}

		// 创建http GET请求
		HttpGet httpGet = null;
		if (uri != null) {
			httpGet = new HttpGet(uri);
		} else {
			httpGet = new HttpGet(url);
		}
		// 设置请求参数
		httpGet.setConfig(this.requestConfig);

		// 请求的结果
		CloseableHttpResponse response = null;
		try {
			// 执行请求
			response = httpClient.execute(httpGet);
			// 判断返回状态是否为200
			if (response.getStatusLine().getStatusCode() == 200) {
				// 获取服务端返回的数据,并返回
				return EntityUtils.toString(response.getEntity(), "UTF-8");
			}
		} finally {
			if (response != null) {
				response.close();
			}
		}
		return null;
	}

	/**
	 * 
	 * @param url
	 * @param params
	 *            请求中的参数
	 * @return 请求到的内容
	 * @throws URISyntaxException
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public String doPost(String url, Map<String, Object> params)
			throws URISyntaxException, ClientProtocolException, IOException {
		// 设置post参数
		List<NameValuePair> parameters = null;
		// 构造一个form表单式的实体
		UrlEncodedFormEntity formEntity = null;

		// 定义请求的参数
		if (params != null) {
			// 设置post参数
			parameters = new ArrayList<NameValuePair>();
			for (Map.Entry<String, Object> entry : params.entrySet()) {
				// 添加参数
				parameters.add(new BasicNameValuePair(entry.getKey(), String
						.valueOf(entry.getValue())));
			}
			// 构造一个form表单式的实体
			formEntity = new UrlEncodedFormEntity(parameters);
		}

		// 创建http GET请求
		HttpPost httpPost = null;
		if (formEntity != null) {
			httpPost = new HttpPost(url);
			// 将请求实体设置到httpPost对象中
			httpPost.setEntity(formEntity);
			// 伪装浏览器请求
			httpPost.setHeader(
					"User-Agent",
					"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36");
		} else {
			httpPost = new HttpPost(url);
			// 伪装浏览器请求
			httpPost.setHeader(
					"User-Agent",
					"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36");
		}
		// 设置请求参数
		httpPost.setConfig(this.requestConfig);

		// 请求的结果
		CloseableHttpResponse response = null;
		try {
			// 执行请求
			response = httpClient.execute(httpPost);
			// 判断返回状态是否为200
			if (response.getStatusLine().getStatusCode() == 200) {
				// 获取服务端返回的数据,并返回
				return EntityUtils.toString(response.getEntity(), "UTF-8");
			}
		} finally {
			if (response != null) {
				response.close();
			}
		}
		return null;
	}

	/**
	 * 
	 * @param url
	 * @param params
	 *            请求中的参数
	 * @return 请求到的内容
	 * @throws URISyntaxException
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public String doPost(String url) throws URISyntaxException,
			ClientProtocolException, IOException {
		return doPost(url, null);
	}
}
@Autowired(required = false)表示的含义是,spring容器里面有这个bean就注入,没有就不注入。

4、 用于清除无效请求IdleConnectionEvictor.java的实现

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) {
					// 每隔5秒执行一个,关闭失效的http连接
					wait(5000);
					// 关闭失效的连接
					connMgr.closeExpiredConnections();
				}
			}
		} catch (InterruptedException ex) {
			// 结束
		}
	}

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

}

5、 测试代码

public class TestApp {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"classpath:spring/bean-*.xml");
		System.out.println(context);

		HttpService httpService = context.getBean("httpService",
				HttpService.class);
		System.out.println(httpService);
		try {
			// Map<String, String> maps = new HashMap<String, String>();
			// maps.put("wd", "java");
			// String string = httpService.doGet("http://www.baidu.com/s");
			// System.out.println(string);

			Map<String, Object> maps = new HashMap<String, Object>();
			maps.put("wd", "java");
			String string = httpService.doPost(
					"http://localhost:8080/ssss/HaHaServlet", maps);
			System.out.println(string);

		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}

6、源码下载


RestTemplate是Spring框架中的一个客户端类,它用于简化HTTP请求的操作,如GET、POST等。而HttpURLConnection和HttpClient是Java的标准库提供的用于处理网络连接和HTTP协议的组件。 如果你想要将`RestTemplate`整合到较新的HttpClient 5.x版本,Spring 5及更高版本已经不再直接支持HttpClient作为底层HTTP客户端。不过,你可以选择第三方库,比如Spring's `spring-ws-client`或者`spring-cloud-netflix-eureka-client`中的`HystrixCommandExecutor`,它们会自动切换到OkHttp或Retrofit(如果使用了Netflix OSS stack的话),这两个库底层就是基于Apache HttpClient。 如果你想自己手动替换,可以按照以下步骤操作: 1. 配置:移除Spring对内置`HttpComponentsClientHttpRequestFactory`的依赖,转而引入HttpClient 5.x的依赖,例如: ```xml <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>5.1.3</version> </dependency> ``` 2. 创建自定义工厂:创建一个实现了`ClientHttpRequestFactory`接口的类,然后在其中注入HttpClient 5.x实例: ```java import org.apache.http.client.methods.CloseableHttpResponse; import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.HttpRequestException; import org.springframework.http.client.RequestCallback; import org.springframework.http.client.ResponseExtractor; public class HttpClient5ClientHttpRequestFactory implements ClientHttpRequestFactory { private final CloseableHttpClient httpClient; public HttpClient5ClientHttpRequestFactory(CloseableHttpClient httpClient) { this.httpClient = httpClient; } // 实现相应方法... } ``` 3. 将自定义工厂配置给RestTemplate: ```java RestTemplate restTemplate = new RestTemplate(); restTemplate.setRequestFactory(new HttpClient5ClientHttpRequestFactory(client)); ``` 注意,虽然可以直接这样做,但在生产环境中,建议还是使用Spring官方推荐的方式,即使用Spring WebClient或者集成如OkHttp这样的现代HTTP客户端库。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值