在SpringBoot中如何使用HttpClient實現(xiàn)HTTP請求
SpringBoot使用HttpClient實現(xiàn)HTTP請求
越來越多的 Java 應(yīng)用程序需要直接通過 HTTP 協(xié)議來訪問網(wǎng)絡(luò)資源。雖然在 JDK 的 java.net 包中已經(jīng)提供了訪問 HTTP 協(xié)議的基本功能,但是對于大部分應(yīng)用程序來說,JDK 庫本身提供的功能還不夠豐富和靈活。
HttpClient 是 Apache Jakarta Common 下的子項目,用來提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。
新建一個 SpringBoot
工程,引入 httpclient
的 POM 依賴:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version> </dependency>
總結(jié):
public class HttpClientUtil { // GET請求 public static String get(String url, JSONObject params) { CloseableHttpClient httpClient = HttpClientBuilder.create().build(); String sendUrl = url; // 拼接參數(shù) if (Objects.nonNull(params) && params.size() > 0) { sendUrl = connectParams(url, params); } HttpGet httpGet = new HttpGet(sendUrl); CloseableHttpResponse response = null; try { response = httpClient.execute(httpGet); HttpEntity httpEntity = response.getEntity(); if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) { return EntityUtils.toString(httpEntity); } } catch (IOException e) { e.printStackTrace(); } finally { try { close(httpClient, response); } catch (IOException e) { e.printStackTrace(); } } throw new JeecgBootException("調(diào)用GET請求失敗!"); } /** * @Description: POST 請求 * @Author: zzc * @Date: 2022-12-16 16:48 * @param url: * @param params: * @param requestBody: json 串 * @return: java.lang.String **/ public static String post(String url, JSONObject params, String requestBody) { CloseableHttpClient httpClient = HttpClientBuilder.create().build(); String sendUrl = url; // 1.拼接參數(shù) if (Objects.nonNull(params) && params.size() > 0) { sendUrl = connectParams(url, params); } HttpPost httpPost = new HttpPost(sendUrl); httpPost.setHeader("Content-Type", "application/json;charset=utf8"); CloseableHttpResponse response = null; try { // 2.設(shè)置request-body if (StringUtils.isNotBlank(requestBody)) { ByteArrayEntity entity = new ByteArrayEntity(requestBody.getBytes(StandardCharsets.UTF_8)); entity.setContentType("application/json"); httpPost.setEntity(entity); } response = httpClient.execute(httpPost); HttpEntity httpEntity = response.getEntity(); if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) { return EntityUtils.toString(httpEntity); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { close(httpClient, response); } catch (IOException e) { e.printStackTrace(); } } throw new JeecgBootException("調(diào)用POST請求失敗!"); } private static String connectParams(String url, JSONObject params) { StringBuffer buffer = new StringBuffer(); buffer.append(url).append("?"); params.forEach((x, y) -> buffer.append(x).append("=").append(y).append("&")); buffer.deleteCharAt(buffer.length() - 1); return buffer.toString(); } public static void close(CloseableHttpClient httpClient, CloseableHttpResponse httpResponse) throws IOException{ if (null != httpClient) { httpClient.close(); } if (null != httpResponse) { httpResponse.close(); } } }
詳細(xì)使用示例
GET 無參
調(diào)用接口:
http://localhost:8080/http/listUsers
沒有入?yún)ⅰ?/p>
HttpClientController#doGetNoParams()
:GET請求接口不帶參數(shù)
@RestController @RequestMapping("/httpClient") public class HttpClientController { @Autowired private HttpClientService httpClientService; // GET請求接口不帶參數(shù) @GetMapping("/doGetNoParams") public String doGetNoParams() { return httpClientService.doGetNoParams(); } }
HttpClientServiceImpl#doGetNoParams()
:GET 請求接口不帶參數(shù)
@Slf4j @Service public class HttpClientServiceImpl implements HttpClientService { // GET請求接口不帶參數(shù) @Override public String doGetNoParams() { String result = HttpClientUtil.doGetNoParams(); log.info("【發(fā)送GET請求】返回結(jié)果為:{}", result); if (!StringUtil.isBlank(result)) { TaskCenterUtil taskCenterUtil = TaskCenterUtil.getTaskCenterUtil(); taskCenterUtil.submitTask(() -> { log.info("【子線程】開啟了一個新線程,當(dāng)前線程名為:{}", Thread.currentThread().getName()); return null; }); } log.info("【主線程】當(dāng)前線程名為:{}", Thread.currentThread().getName()); return result; } }
說明:
- 當(dāng) HTTP 調(diào)用成功后,通過線程池開一個子線程,去異步執(zhí)行任務(wù);主線程繼續(xù)向下執(zhí)行
HttpClientUtil#doGetNoParams()
:GET請求接口不帶參數(shù)
@Slf4j public class HttpClientUtil { // 服務(wù)器ip public static final String IP = "http://localhost"; // 端口 public static final String PORT = ":8080"; // GET請求接口不帶參數(shù) public static final String GET_URL_NO_PARAMS = IP + PORT + "/http/listUsers"; // GET請求接口不帶參數(shù) public static String doGetNoParams() { CloseableHttpClient httpClient = HttpClientBuilder.create().build(); // 創(chuàng)建 GET 請求 HttpGet httpGet = new HttpGet(GET_URL_NO_PARAMS); httpGet.setHeader("Accept-Encoding", "identity"); log.info("【發(fā)送GET請求】請求地址為:{}", GET_URL_NO_PARAMS); CloseableHttpResponse httpResponse = null; try { httpResponse = httpClient.execute(httpGet); HttpEntity httpEntity = httpResponse.getEntity(); log.info("【發(fā)送GET請求】成功,相應(yīng)狀態(tài)為:{}", httpResponse.getStatusLine()); if (HttpStatus.SC_OK == httpResponse.getStatusLine().getStatusCode() && null != httpEntity) { String result = EntityUtils.toString(httpEntity); log.info("【發(fā)送GET請求】成功,響應(yīng)內(nèi)容為:{}", result); return result; } } catch (IOException e) { log.error("【發(fā)送GET請求】失敗,執(zhí)行發(fā)送請求時,出現(xiàn)IO異常,異常信息為:{}", e); return null; } finally { try { close(httpClient, httpResponse); } catch (IOException e) { log.error("【發(fā)送GET請求】失敗,關(guān)閉流時,出現(xiàn)IO異常,異常信息為:{}", e); } } return null; } }
說明:
- 通過類
HttpGet
發(fā)起 GET 請求。
HttpGet
:有 3 個構(gòu)造方法
public class HttpGet extends HttpRequestBase { public HttpGet() { } public HttpGet(URI uri) { this.setURI(uri); } public HttpGet(String uri) { this.setURI(URI.create(uri)); } ... }
這里使用了 public HttpGet(String uri);
方式來構(gòu)造 HttpGet
實例。
HttpClientUtil#close()
:關(guān)閉流
// 關(guān)閉流 public static void close(CloseableHttpClient httpClient, CloseableHttpResponse httpResponse) throws IOException{ if (null != httpClient) { httpClient.close(); } if (null != httpResponse) { httpResponse.close(); } }
TaskCenterUtil
:線程池工具類
public class TaskCenterUtil { public static Integer CORE_POOL_SIZE = 10; public static Integer MAX_NUM_POOL_SIZE = 10; public static Integer MAX_MESSAGE_SIZE = 100; public static Long KEEP_ALIVE_TIME = 60L; private ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_NUM_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new LinkedBlockingQueue<>(MAX_MESSAGE_SIZE), new ThreadPoolExecutor.CallerRunsPolicy()); private TaskCenterUtil() {} private static TaskCenterUtil taskCenterUtil = new TaskCenterUtil(); public static TaskCenterUtil getTaskCenterUtil() { return taskCenterUtil; } // 提交任務(wù) public void submitTask(Callable task) { poolExecutor.submit(task); } }
POSTMAN 調(diào)用:
控制臺打印日志:
GET 有參
- 方式一:使用
public HttpGet(String uri);
方式來構(gòu)造HttpGet
實例。即:使用 url 字符串來拼接參數(shù)。 - 方式二:使用
public HttpGet(URI uri);
方式來構(gòu)造HttpGet
實例。
調(diào)用接口:
http://localhost:8080/http/getUserById?id=1
入?yún)ⅲ?/p>
id=1
HttpClientController#doGetParams()
:GET請求接口帶參數(shù)
@GetMapping("/doGetParams") public String doGetParams(String id) { return httpClientService.doGetParams(id); }
HttpClientServiceImpl
:
@Override public String doGetParams(String id) { String result = HttpClientUtil.doGetParams(id); log.info("【發(fā)送GET請求】返回結(jié)果為:{}", result); return result; }
HttpClientUtil#doGetParams()
:GET請求接口帶參數(shù)
@Slf4j public class HttpClientUtil { // GET請求接口帶參數(shù) public static final String GET_URL_PARAMS = IP + PORT + "/http/getUserById"; // 入?yún)⒚Q public static final String URL_PARAMS_ID = "id"; // http 協(xié)議 public static final String SCHEME_HTTP = "http"; // 主機(jī) public static final String LOCAL_HOST = "localhost"; // 請求接口路徑 public static final String GET_URL_PARAMS_PATH = "/http/getUserById"; // 端口 public static final Integer LOCAL_PORT = 8080; // GET請求接口帶參數(shù) public static String doGetParams(String id) { CloseableHttpClient httpClient = HttpClientBuilder.create().build(); // 不同方式獲取 HttpGet // 方式一: HttpGet httpGet = getStrHttpGet(GET_URL_PARAMS, id); // 方式二: //HttpGet httpGet = getUrlHttpGet(id); // 獲取請求頭配置信息 RequestConfig requestConfig = HttpClientConfig.getRequestConfig(); httpGet.setConfig(requestConfig); CloseableHttpResponse response = null; try { response = httpClient.execute(httpGet); HttpEntity httpEntity = response.getEntity(); log.info("【發(fā)送GET請求】成功,相應(yīng)狀態(tài)為:{}", response.getStatusLine()); if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) { String result = EntityUtils.toString(httpEntity); log.info("【發(fā)送GET請求】成功,響應(yīng)內(nèi)容為:{}", result); return result; } } catch (IOException e) { log.error("【發(fā)送GET請求】失敗,執(zhí)行發(fā)送請求時,出現(xiàn)IO異常,異常信息為:{}", e); return null; } finally { try { close(httpClient, response); } catch (IOException e) { log.error("【發(fā)送GET請求】失敗,關(guān)閉流時,出現(xiàn)IO異常,異常信息為:{}", e); } } return null; } }
getStrHttpGet()
:方式一:url拼接參數(shù)
public static HttpGet getStrHttpGet(String url, String id) { StringBuilder builder = new StringBuilder(); // url 拼接參數(shù) /http/getUserById?id=1 String strUrl = builder.append(url).append("?").append(URL_PARAMS_ID).append("=").append(id).toString(); log.info("【發(fā)送GET請求】請求地址為:{}", strUrl); HttpGet httpGet = new HttpGet(strUrl); return httpGet; }
getUrlHttpGet()
:方式二:URI對象
public static HttpGet getUrlHttpGet(String id) { // 將參數(shù)鍵值對放入集合中 List<NameValuePair> params = new ArrayList<>(); params.add(new BasicNameValuePair(URL_PARAMS_ID, id)); try { URI uri = new URIBuilder() .setScheme(SCHEME_HTTP) .setHost(LOCAL_HOST) .setPort(LOCAL_PORT) .setPath(GET_URL_PARAMS_PATH) .setParameters(params).build(); return new HttpGet(uri); } catch (URISyntaxException e) { log.error("【發(fā)送GET請求】構(gòu)建URI失敗,失敗信息為:{}", e); } return null; }
說明:
- 方式一是使用
public HttpGet(String uri);
方式來構(gòu)造HttpGet
實例 - 方式二是使用
public HttpGet(URL uri);
方式來構(gòu)造HttpGet
實例。即:使用 url 字符串來拼接參數(shù)。
POSTMAN 調(diào)用:
POST 無參
調(diào)用接口:
http://localhost:8080/http/listUserList
入?yún)ⅲ簾o
HttpClientController#doPostNoParams()
:POST請求接口不帶參數(shù)
@PostMapping("/doPostNoParams") public String doPostNoParams() { return httpClientService.doPostNoParams(); }
HttpClientServiceImpl#doPostNoParams()
:
@Override public String doPostNoParams() { String result = HttpClientUtil.doPostNoParams(); log.info("【發(fā)送POST請求】返回結(jié)果為:{}", result); return result; }
HttpClientUtil
:
public class HttpClientUtil { // POST請求接口不帶參數(shù) public static final String POST_URL_NO_PARAMS = IP + PORT + "/http/listUserList"; // POST請求接口帶參數(shù) public static final String POST_URL_PARAMS = IP + PORT + "/http/getUserVoById"; // POST請求接口帶參數(shù) -- 對象參數(shù) public static final String POST_URL_PARAMS_OBJECT = IP + PORT + "/http/listUsers"; // POST請求接口不帶參數(shù) public static String doPostNoParams() { CloseableHttpClient httpClient = HttpClientBuilder.create().build(); HttpPost httpPost = new HttpPost(POST_URL_NO_PARAMS); log.info("【發(fā)送POST請求】請求地址為:{}", POST_URL_NO_PARAMS); CloseableHttpResponse response = null; try { response = httpClient.execute(httpPost); HttpEntity httpEntity = response.getEntity(); log.info("【發(fā)送POST請求】成功,相應(yīng)狀態(tài)為:{}", response.getStatusLine()); if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) { String result = EntityUtils.toString(httpEntity); log.info("【發(fā)送POST請求】成功,響應(yīng)內(nèi)容為:{}", result); return result; } } catch (IOException e) { log.error("【發(fā)送POST請求】失敗,執(zhí)行發(fā)送請求時,出現(xiàn)IO異常,異常信息為:{}", e); return null; } finally { try { close(httpClient, response); } catch (IOException e) { log.error("【發(fā)送POST請求】失敗,關(guān)閉流時,出現(xiàn)IO異常,異常信息為:{}", e); } } return null; } }
POST 有參
- 參數(shù)是:普通參數(shù)。方式與GET一樣即可,直接在 url 后綴上拼接參數(shù)
- 參數(shù)是:對象。將參數(shù)以請求體 request-body 的方式進(jìn)行請求
- 參數(shù)是:普通參數(shù)+對象。普通參數(shù) 直接在 url 后綴上拼接參數(shù);對象 以請求體 request-body 的方式進(jìn)行請求
普通參數(shù)
請求接口:
http://localhost:8080/http/getUserVoById?id=1
對象參數(shù)
請求接口:
http://localhost:8080/http/listUsers
入?yún)?UserVo:
{ "id": 1 }
即:這個接口可以隨便寫
@PostMapping("/listUsers") public List<UserVo> listUsers(@RequestBody UserVo userVo) { return httpService.listUsers(); }
HttpClientController#doPostParams()
:POST請求接口帶參數(shù)
@PostMapping("/doPostParams") public String doPostParams(String id) { return httpClientService.doPostParams(id); }
HttpClientServiceImpl#doPostParams()
:
@Override public String doPostParams(String id) { String result = HttpClientUtil.doPostParams(id); log.info("【發(fā)送POST請求】返回結(jié)果為:{}", result); return result; }
HttpClientUtil#doPostParams()
:
public static String doPostParams(String id) { CloseableHttpClient httpClient = HttpClientBuilder.create().build(); // 參數(shù)是普通參數(shù) HttpPost httpPost = getStrHttpPost(POST_URL_PARAMS, id); // 參數(shù)是對象 //HttpPost httpPost = getObjectHttpPost(id); // 設(shè)置ContentType(注:如果只是傳普通參數(shù)的話,ContentType不一定非要用application/json) httpPost.setHeader("Content-Type", "application/json;charset=utf8"); CloseableHttpResponse response = null; try { response = httpClient.execute(httpPost); HttpEntity httpEntity = response.getEntity(); log.info("【發(fā)送POST請求】成功,相應(yīng)狀態(tài)為:{}", response.getStatusLine()); if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) { String result = EntityUtils.toString(httpEntity); log.info("【發(fā)送POST請求】成功,響應(yīng)內(nèi)容為:{}", result); return result; } } catch (IOException e) { log.error("【發(fā)送POST請求】失敗,執(zhí)行發(fā)送請求時,出現(xiàn)IO異常,異常信息為:{}", e); return null; } finally { try { close(httpClient, response); } catch (IOException e) { log.error("【發(fā)送POST請求】失敗,關(guān)閉流時,出現(xiàn)IO異常,異常信息為:{}", e); } } return null; }
getStrHttpPost()
:POST請求有參:普通參數(shù)
public static HttpPost getStrHttpPost(String url, String id) { StringBuilder builder = new StringBuilder(); // url 拼接參數(shù) /http/getUserVoById?id=1 String strUrl = builder.append(url).append("?").append(URL_PARAMS_ID).append("=").append(id).toString(); log.info("【發(fā)送POST請求】請求地址為:{}", strUrl); HttpPost httpPost = new HttpPost(strUrl); return httpPost; }
getObjectHttpPost()
:POST請求有參:對象參數(shù)
public static HttpPost getObjectHttpPost(String id) { HttpPost httpPost = new HttpPost(POST_URL_PARAMS_OBJECT); log.info("【發(fā)送POST請求】請求地址為:{}", POST_URL_PARAMS_OBJECT); UserVo userVo = new UserVo(); userVo.setId(id); // 將JAVA對象轉(zhuǎn)換為Json字符串 String jsonString = JSON.toJSONString(userVo); StringEntity stringEntity = new StringEntity(jsonString, "UTF-8"); // post請求是將參數(shù)放在請求體里面?zhèn)鬟^去的 httpPost.setEntity(stringEntity); return httpPost; }
普通參數(shù) + 對象
// params:name=zzc&age=17 marshal:json 串 public static String post(String url, String params, String marshal) { CloseableHttpClient httpClient = HttpClientBuilder.create().build(); String strUrl = url + "?" + params; HttpPost httpPost = new HttpPost(strUrl); httpPost.setHeader("Content-Type", "application/json;charset=utf8"); CloseableHttpResponse response = null; try { // 設(shè)置 requst-body 參數(shù) ByteArrayEntity entity = new ByteArrayEntity(marshal.getBytes("UTF-8")); entity.setContentType("application/json"); httpPost.setEntity(entity); response = httpClient.execute(httpPost); HttpEntity httpEntity = response.getEntity(); if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) { String result = EntityUtils.toString(httpEntity); return result; } } catch (Exception e) { e.printStackTrace(); } finally { try { close(httpClient, response); } catch (IOException e) { e.printStackTrace(); } } return null; }
表單提交
public static String post(String url, Map<String, String> params) { CloseableHttpClient httpClient = HttpClientBuilder.create().build(); HttpPost httpPost = new HttpPost(url); httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded"); // 參數(shù) List<NameValuePair> nameValuePairs = new ArrayList<>(); if (MapUtils.isNotEmpty(params)) { params.forEach((x, y) -> { nameValuePairs.add(new BasicNameValuePair(x, y)); }); } CloseableHttpResponse response = null; try { httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); response = httpClient.execute(httpPost); HttpEntity httpEntity = response.getEntity(); if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) { return EntityUtils.toString(httpEntity); } } catch (IOException e) { e.printStackTrace(); } finally { try { close(httpClient, response); } catch (IOException e) { e.printStackTrace(); } } throw new JeecgBootException("調(diào)用accessToken API失敗"); }
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
HTTP 415錯誤-Unsupported media type詳解
這篇文章主要介紹了HTTP 415錯誤-Unsupported media type詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08常用數(shù)字簽名算法RSA與DSA的Java程序內(nèi)實現(xiàn)示例
這篇文章主要介紹了常用數(shù)字簽名算法RSA與DSA的Java程序內(nèi)實現(xiàn)示例,一般來說DSA算法用于簽名的效率會比RSA要快,需要的朋友可以參考下2016-04-04詳解Maven settings.xml配置(指定本地倉庫、阿里云鏡像設(shè)置)
這篇文章主要介紹了詳解Maven settings.xml配置(指定本地倉庫、阿里云鏡像設(shè)置),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12關(guān)于@MapperScan和@ComponentScan的使用問題
文章介紹了在使用`@MapperScan`和`@ComponentScan`時可能會遇到的包掃描沖突問題,并提供了解決方法,同時,還詳細(xì)解釋了`@MapperScan`和`@ComponentScan`的功能和使用場景2025-01-01