访问接口服务的方式有两种:
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在页面上返回