Java HttpClient技術(shù)詳解
一、HttpClient
1.1、 前臺(tái)系統(tǒng)訪問(wèn)后臺(tái)接口的方式
兩個(gè)系統(tǒng)間如何互相訪問(wèn)??jī)蓚€(gè)tomcat上的項(xiàng)目如何互相訪問(wèn)
采用HttpClient實(shí)現(xiàn)跨系統(tǒng)的接口調(diào)用。
1.2、 什么是HttpClient

官網(wǎng):http://hc.apache.org/index.html
現(xiàn)在也叫:HttpComponents

特點(diǎn):
- HttpClient別名:HttpComponents
- HttpClient可以發(fā)送get、post、put、delete、…等請(qǐng)求
1.3、 HttpClient入門案例
導(dǎo)入maven坐標(biāo)
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4</version>
</dependency>
1.3.1、 發(fā)起Get請(qǐng)求
- 1創(chuàng)建一個(gè)客戶端 CloseableHttpClient
- 2創(chuàng)建一個(gè)get方法請(qǐng)求實(shí)例 HttpGet
- 3發(fā)送請(qǐng)求 execute
- 4獲取響應(yīng)的頭信息
- 5獲取響應(yīng)的主題內(nèi)容
- 6關(guān)閉響應(yīng)對(duì)象
使用HttpClient發(fā)起Get請(qǐng)求的案例代碼:
public class DoGET {
public static void main(String[] args) throws Exception {
// 創(chuàng)建Httpclient對(duì)象,相當(dāng)于打開(kāi)了瀏覽器
CloseableHttpClient httpclient = HttpClients.createDefault();
// 創(chuàng)建HttpGet請(qǐng)求,相當(dāng)于在瀏覽器輸入地址
HttpGet httpGet = new HttpGet("http://www.baidu.com/");
CloseableHttpResponse response = null;
try {
// 執(zhí)行請(qǐng)求,相當(dāng)于敲完地址后按下回車。獲取響應(yīng)
response = httpclient.execute(httpGet);
// 判斷返回狀態(tài)是否為200
if (response.getStatusLine().getStatusCode() == 200) {
// 解析響應(yīng),獲取數(shù)據(jù)
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
}
} finally {
if (response != null) {
// 關(guān)閉資源
response.close();
}
// 關(guān)閉瀏覽器
httpclient.close();
}
}
}
執(zhí)行日志:
請(qǐng)求頭:

響應(yīng)頭:

數(shù)據(jù):

1.3.2、 帶參數(shù)的Get請(qǐng)求
- 1創(chuàng)建一個(gè)客戶端 CloseableHttpClient
- 2通過(guò)URIBuilder傳遞參數(shù)
- 3創(chuàng)建一個(gè)get方法請(qǐng)求實(shí)例 HttpGet
- 4發(fā)送請(qǐng)求 execute
- 5獲取響應(yīng)的頭信息
- 6獲取響應(yīng)的主題內(nèi)容
- 7關(guān)閉響應(yīng)對(duì)象
訪問(wèn)網(wǎng)站的爬蟲(chóng)協(xié)議:

public class DoGETParam {
public static void main(String[] args) throws Exception {
// 創(chuàng)建Httpclient對(duì)象
CloseableHttpClient httpclient = HttpClients.createDefault();
// 創(chuàng)建URI對(duì)象,并且設(shè)置請(qǐng)求參數(shù)
URI uri = new URIBuilder("http://www.baidu.com/s").setParameter("wd", "java").build();
// 創(chuàng)建http GET請(qǐng)求
HttpGet httpGet = new HttpGet(uri);
// HttpGet get = new HttpGet("http://www.baidu.com/s?wd=java");
CloseableHttpResponse response = null;
try {
// 執(zhí)行請(qǐng)求
response = httpclient.execute(httpGet);
// 判斷返回狀態(tài)是否為200
if (response.getStatusLine().getStatusCode() == 200) {
// 解析響應(yīng)數(shù)據(jù)
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
}
} finally {
if (response != null) {
response.close();
}
httpclient.close();
}
}
}
1.3.3、 發(fā)起POST請(qǐng)求
/*
* 演示:使用HttpClient發(fā)起POST請(qǐng)求
*/
public class DoPOST {
public static void main(String[] args) throws Exception {
// 創(chuàng)建Httpclient對(duì)象
CloseableHttpClient httpclient = HttpClients.createDefault();
// 創(chuàng)建http POST請(qǐng)求
HttpPost httpPost = new HttpPost("http://www.oschina.net/");
// 把自己偽裝成瀏覽器。否則開(kāi)源中國(guó)會(huì)攔截訪問(wèn)
httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
CloseableHttpResponse response = null;
try {
// 執(zhí)行請(qǐng)求
response = httpclient.execute(httpPost);
// 判斷返回狀態(tài)是否為200
if (response.getStatusLine().getStatusCode() == 200) {
// 解析響應(yīng)數(shù)據(jù)
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
}
} finally {
if (response != null) {
response.close();
}
// 關(guān)閉瀏覽器
httpclient.close();
}
}
}
1.3.4、 帶參數(shù)POST請(qǐng)求
/*
* 演示:使用HttpClient發(fā)起帶有參數(shù)的POST請(qǐng)求
*/
public class DoPOSTParam {
public static void main(String[] args) throws Exception {
// 創(chuàng)建Httpclient對(duì)象
CloseableHttpClient httpclient = HttpClients.createDefault();
// 創(chuàng)建http POST請(qǐng)求,訪問(wèn)開(kāi)源中國(guó)
HttpPost httpPost = new HttpPost("http://www.oschina.net/search");
// 根據(jù)開(kāi)源中國(guó)的請(qǐng)求需要,設(shè)置post請(qǐng)求參數(shù)
List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
parameters.add(new BasicNameValuePair("scope", "project"));
parameters.add(new BasicNameValuePair("q", "java"));
parameters.add(new BasicNameValuePair("fromerr", "8bDnUWwC"));
// 構(gòu)造一個(gè)form表單式的實(shí)體
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
// 將請(qǐng)求實(shí)體設(shè)置到httpPost對(duì)象中
httpPost.setEntity(formEntity);
CloseableHttpResponse response = null;
try {
// 執(zhí)行請(qǐng)求
response = httpclient.execute(httpPost);
// 判斷返回狀態(tài)是否為200
if (response.getStatusLine().getStatusCode() == 200) {
// 解析響應(yīng)體
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
}
} finally {
if (response != null) {
response.close();
}
// 關(guān)閉瀏覽器
httpclient.close();
}
}
}
二、項(xiàng)目整合HttpClient—與SpringBoot整合
SpringBoot官方并沒(méi)有對(duì)HttpClient的啟動(dòng)器。所以我們需要自己完成配置,還好,我們剛才在測(cè)試案例中已經(jīng)寫過(guò)了。
不過(guò),SpringBoot雖然沒(méi)有提供啟動(dòng)器,但是卻提供了一個(gè)統(tǒng)一的對(duì)Restful服務(wù)進(jìn)行調(diào)用的模板類:RestTemplate,底層可以使用HttpClient來(lái)實(shí)現(xiàn)。有了這個(gè)我們就無(wú)需自己定義APIService了。
1、導(dǎo)入maven坐標(biāo)
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2、在項(xiàng)目中創(chuàng)建HttpClientConfig類–類似util

3、在application.properties添加如下配置:
#The config for HttpClient http.maxTotal=300 http.defaultMaxPerRoute=50 http.connectTimeout=1000 http.connectionRequestTimeout=500 http.socketTimeout=5000 http.staleConnectionCheckEnabled=true
4、在類中編寫代碼
/**
* HttpClient的配置類
*
*/
@Configuration
@ConfigurationProperties(prefix = "http", ignoreUnknownFields = true)
public class HttpClientConfig {
private Integer maxTotal;// 最大連接
private Integer defaultMaxPerRoute;// 每個(gè)host的最大連接
private Integer connectTimeout;// 連接超時(shí)時(shí)間
private Integer connectionRequestTimeout;// 請(qǐng)求超時(shí)時(shí)間
private Integer socketTimeout;// 響應(yīng)超時(shí)時(shí)間
/**
* HttpClient連接池
* @return
*/
@Bean
public HttpClientConnectionManager httpClientConnectionManager() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(maxTotal);
connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
return connectionManager;
}
/**
* 注冊(cè)RequestConfig
* @return
*/
@Bean
public RequestConfig requestConfig() {
return RequestConfig.custom().setConnectTimeout(connectTimeout)
.setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout)
.build();
}
/**
* 注冊(cè)HttpClient
* @param manager
* @param config
* @return
*/
@Bean
public HttpClient httpClient(HttpClientConnectionManager manager, RequestConfig config) {
return HttpClientBuilder.create().setConnectionManager(manager).setDefaultRequestConfig(config)
.build();
}
/**
* 使用連接池管理連接
* @param httpClient
* @return
*/
@Bean
public ClientHttpRequestFactory requestFactory(HttpClient httpClient) {
return new HttpComponentsClientHttpRequestFactory(httpClient);
}
/**
* 使用HttpClient來(lái)初始化一個(gè)RestTemplate
* @param requestFactory
* @return
*/
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory requestFactory) {
RestTemplate template = new RestTemplate(requestFactory);
List<HttpMessageConverter<?>> list = template.getMessageConverters();
for (HttpMessageConverter<?> mc : list) {
if (mc instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) mc).setDefaultCharset(Charset.forName("UTF-8"));
}
}
return template;
}
public Integer getMaxTotal() {
return maxTotal;
}
public void setMaxTotal(Integer maxTotal) {
this.maxTotal = maxTotal;
}
public Integer getDefaultMaxPerRoute() {
return defaultMaxPerRoute;
}
public void setDefaultMaxPerRoute(Integer defaultMaxPerRoute) {
this.defaultMaxPerRoute = defaultMaxPerRoute;
}
public Integer getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(Integer connectTimeout) {
this.connectTimeout = connectTimeout;
}
public Integer getConnectionRequestTimeout() {
return connectionRequestTimeout;
}
public void setConnectionRequestTimeout(Integer connectionRequestTimeout) {
this.connectionRequestTimeout = connectionRequestTimeout;
}
public Integer getSocketTimeout() {
return socketTimeout;
}
public void setSocketTimeout(Integer socketTimeout) {
this.socketTimeout = socketTimeout;
}
}
三、RestTemplate使用詳解
1、概述:
RestTemplate是Spring提供的用于訪問(wèn)Rest服務(wù)的客戶端,RestTemplate提供了多種便捷訪問(wèn)遠(yuǎn)程Http服務(wù)的方法,能夠大大提高客戶端的編寫效率。
之前的HTTP開(kāi)發(fā)是用apache的HttpClient開(kāi)發(fā),代碼復(fù)雜,還得操心資源回收等。代碼很復(fù)雜,冗余代碼多。
導(dǎo)入坐標(biāo):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2、創(chuàng)建RestTemplate對(duì)象

第一步:創(chuàng)建RestTemplate類,在類中創(chuàng)建RestTemplate對(duì)象
/**
* Created by yxq on 2020/08/05.
* RestTemplate工具類,主要用來(lái)提供RestTemplate對(duì)象
*/
@Configuration//加上這個(gè)注解作用,可以被Spring掃描
public class RestTemplateConfig {
/**
* 創(chuàng)建RestTemplate對(duì)象,將RestTemplate對(duì)象的生命周期的管理交給Spring
* @return
*/
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
第二步:創(chuàng)建RestTempController,注入RestTemplate
/**
* Created by yxq on 2019/11/29.
* 本項(xiàng)目不連接數(shù)據(jù)庫(kù),通過(guò)RestTemplate發(fā)出get、post、put、delete請(qǐng)求,請(qǐng)求admin-project項(xiàng)目中controller的方法
*
*
*/
@RestController
@RequestMapping("/rest")
public class RestTempController {
// 從Spring的容器中獲取restTemplate
@Autowired
private RestTemplate restTemplate;
}
3、get請(qǐng)求
第一步:在RestTempController中編寫代碼,發(fā)起get請(qǐng)求:
/**
* 發(fā)起get請(qǐng)求,請(qǐng)求admin-project
* http://localhost:8088/admin -->分頁(yè)查找
*/
@GetMapping
public ResponseEntity<String> findByPage(){
/**
* 第一個(gè)參數(shù):url
* 第二個(gè)參數(shù):返回值類型
*/
ResponseEntity<String> entity = restTemplate.getForEntity("http://localhost:8088/admin?page=1&rows=3", String.class);
System.out.println("狀態(tài)碼:"+entity.getStatusCode());
System.out.println("響應(yīng)體"+entity.getBody());
return ResponseEntity.ok(entity.getBody());
}
測(cè)試結(jié)果:

4、post請(qǐng)求
第一步:創(chuàng)建實(shí)體類Admin
public class Admin {
/**
* 編號(hào)
*/
private Integer id;
/**
* 管理員名
*/
private String adminname;
/**
* 密碼
*/
private String password;
/**
* 郵箱
*/
private String email;
/**
* 手機(jī)號(hào)
*/
private String phone;
/**
* 狀態(tài),0禁用,1啟用
*/
private Integer state;
/**
* 時(shí)間
*/
private Date time;
/**
* 角色id
*/
private String rid;
// 省略getter和setter方法
}
第二步:在RestTempController中編寫方法,發(fā)送post請(qǐng)求
@PostMapping
public ResponseEntity<String> addAdmin(@RequestBody Admin admin){
/**
* 第一個(gè)參數(shù):url
* 第二個(gè)參數(shù):數(shù)據(jù)
* 第三個(gè)參數(shù):返回值類型
*/
ResponseEntity<String> entity = restTemplate.postForEntity("http://localhost:8088/admin", admin, String.class);
return entity;
}
第三步:采用postman測(cè)試


5、post請(qǐng)求的中文亂碼bug
在RestTemplateConfig中編寫處理亂碼的問(wèn)題:
/**
* Created by yxq on 2020/08/05.
* RestTemplate工具類,主要用來(lái)提供RestTemplate對(duì)象
*/
@Configuration//加上這個(gè)注解作用,可以被Spring掃描
public class RestTemplateConfig {
/**
* 創(chuàng)建RestTemplate對(duì)象,將RestTemplate對(duì)象的生命周期的管理交給Spring
* @return
*/
@Bean
public RestTemplate restTemplate(){
RestTemplate restTemplate = new RestTemplate();
// 設(shè)置中文亂碼問(wèn)題方式一
restTemplate.getMessageConverters().add(1,new StringHttpMessageConverter(Charset.forName("UTF-8")));
// 設(shè)置中文亂碼問(wèn)題方式二
// restTemplate.getMessageConverters().set(1,
// new StringHttpMessageConverter(StandardCharsets.UTF_8)); // 支持中文編碼
return restTemplate;
}
}
6、put請(qǐng)求
第一步:在RestTempController中編寫方法,發(fā)送put請(qǐng)求
/**
* 修改數(shù)據(jù)
*
*/
@PutMapping
public ResponseEntity<String> updateAdmin(@RequestBody Admin admin){
// 第一個(gè)參數(shù):url
// 第二個(gè)參數(shù):對(duì)象,數(shù)據(jù)
restTemplate.put("http://localhost:8088/admin",admin);
return ResponseEntity.ok("修改成功");
}
7、delete請(qǐng)求
第一步:在RestTempController中編寫方法,發(fā)送delete請(qǐng)求
@DeleteMapping("/{id}")
public ResponseEntity<String> deleteAdmin(@PathVariable("id") Integer id){
restTemplate.delete("http://localhost:8088/admin/"+id);
return ResponseEntity.ok("刪除成功");
}
到此這篇關(guān)于Java HttpClient技術(shù)詳解的文章就介紹到這了,更多相關(guān)Java HttpClient內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合Swagger3生成接口文檔的示例代碼
Swagger 是一個(gè) RESTful API 的開(kāi)源框架,它的主要目的是幫助開(kāi)發(fā)者設(shè)計(jì)、構(gòu)建、文檔化和測(cè)試 Web API,本文給大家介紹了SpringBoot整合Swagger3生成接口文檔的流程,并通過(guò)代碼講解的非常詳細(xì),需要的朋友可以參考下2024-04-04
基于list stream: reduce的使用實(shí)例
這篇文章主要介紹了list stream: reduce的使用實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Java多線程使用阻塞隊(duì)列實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模型詳解
這篇文章主要介紹了Java多線程使用阻塞隊(duì)列實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模型詳解,主要講解阻塞隊(duì)列的特性、實(shí)際開(kāi)發(fā)中常用的到的生產(chǎn)者消費(fèi)者模型,以及生產(chǎn)者消費(fèi)者模型解耦合、削峰填谷的好處,需要的朋友可以參考下2023-07-07
xxl-job如何濫用netty導(dǎo)致的問(wèn)題及解決方案
本篇文章講解xxl-job作為一款分布式任務(wù)調(diào)度系統(tǒng)是如何濫用netty的,導(dǎo)致了怎樣的后果以及如何修改源碼解決這些問(wèn)題,netty作為一種高性能的網(wǎng)絡(luò)編程框架,十分受大家喜愛(ài),今天就xxl-job濫用netty這一問(wèn)題給大家詳細(xì)下,感興趣的朋友一起看看吧2021-05-05
Java批量從svn導(dǎo)出多個(gè)項(xiàng)目代碼實(shí)例
這篇文章主要介紹了java批量從svn導(dǎo)出多個(gè)項(xiàng)目代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
解決tk.mybatis中寫自定義的mapper的問(wèn)題
這篇文章主要介紹了使用tk.mybatis中寫自定義的mapper的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
IntelliJ IDEA自定義代碼提示模板Live Templates的圖文教程
這篇文章主要介紹了IntelliJ IDEA自定義代碼提示模板Live Templates,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03

