【HttpClient】在 SpringBoot 中使用 HttpClient 实现 HTTP 请求
【HttpURLConnection】使用 HttpURLConnection 后台模拟实现 HTTP 请求
【HttpClient】在 SpringBoot 中使用 HttpClient 实现 HTTP 请求
【SpringBoot】使用 OkHttp 完成网络请求
越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。虽然在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。
HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
HttpClient 官网
新建一个 SpringBoot
工程,引入 httpclient
的 POM 依赖:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
总结:
public class HttpClientUtil {
// GET请求
public static String get(String url, JSONObject params) {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
String sendUrl = url;
// 拼接参数
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("调用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.拼接参数
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.设置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("调用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();
}
}
}
详细使用示例
GET 无参
调用接口:
http://localhost:8080/http/listUsers
没有入参。
HttpClientController#doGetNoParams()
:GET请求接口不带参数
@RestController
@RequestMapping("/httpClient")
public class HttpClientController {
@Autowired
private HttpClientService httpClientService;
// GET请求接口不带参数
@GetMapping("/doGetNoParams")
public String doGetNoParams() {
return httpClientService.doGetNoParams();
}
}
HttpClientServiceImpl#doGetNoParams()
:GET 请求接口不带参数
@Slf4j
@Service
public class HttpClientServiceImpl implements HttpClientService {
// GET请求接口不带参数
@Override
public String doGetNoParams() {
String result = HttpClientUtil.doGetNoParams();
log.info("【发送GET请求】返回结果为:{}", result);
if (!StringUtil.isBlank(result)) {
TaskCenterUtil taskCenterUtil = TaskCenterUtil.getTaskCenterUtil();
taskCenterUtil.submitTask(() -> {
log.info("【子线程】开启了一个新线程,当前线程名为:{}", Thread.currentThread().getName());
return null;
});
}
log.info("【主线程】当前线程名为:{}", Thread.currentThread().getName());
return result;
}
}
说明:
- 当 HTTP 调用成功后,通过线程池开一个子线程,去异步执行任务;主线程继续向下执行
HttpClientUtil#doGetNoParams()
:GET请求接口不带参数
@Slf4j
public class HttpClientUtil {
// 服务器ip
public static final String IP = "http://localhost";
// 端口
public static final String PORT = ":8080";
// GET请求接口不带参数
public static final String GET_URL_NO_PARAMS = IP + PORT + "/http/listUsers";
// GET请求接口不带参数
public static String doGetNoParams() {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
// 创建 GET 请求
HttpGet httpGet = new HttpGet(GET_URL_NO_PARAMS);
httpGet.setHeader("Accept-Encoding", "identity");
log.info("【发送GET请求】请求地址为:{}", GET_URL_NO_PARAMS);
CloseableHttpResponse httpResponse = null;
try {
httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
log.info("【发送GET请求】成功,相应状态为:{}", httpResponse.getStatusLine());
if (HttpStatus.SC_OK == httpResponse.getStatusLine().getStatusCode() && null != httpEntity) {
String result = EntityUtils.toString(httpEntity);
log.info("【发送GET请求】成功,响应内容为:{}", result);
return result;
}
} catch (IOException e) {
log.error("【发送GET请求】失败,执行发送请求时,出现IO异常,异常信息为:{}", e);
return null;
} finally {
try {
close(httpClient, httpResponse);
} catch (IOException e) {
log.error("【发送GET请求】失败,关闭流时,出现IO异常,异常信息为:{}", e);
}
}
return null;
}
}
说明:
- 通过类
HttpGet
发起 GET 请求。
HttpGet
:有 3 个构造方法
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);
方式来构造 HttpGet
实例。
HttpClientUtil#close()
:关闭流
// 关闭流
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;
}
// 提交任务
public void submitTask(Callable task) {
poolExecutor.submit(task);
}
}
POSTMAN 调用:
控制台打印日志:
GET 有参
方式一:使用 public HttpGet(String uri);
方式来构造 HttpGet
实例。即:使用 url 字符串来拼接参数。
方式二:使用 public HttpGet(URI uri);
方式来构造 HttpGet
实例。
调用接口:
http://localhost:8080/http/getUserById?id=1
入参:
id=1
HttpClientController#doGetParams()
:GET请求接口带参数
@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("【发送GET请求】返回结果为:{}", result);
return result;
}
HttpClientUtil#doGetParams()
:GET请求接口带参数
@Slf4j
public class HttpClientUtil {
// GET请求接口带参数
public static final String GET_URL_PARAMS = IP + PORT + "/http/getUserById";
// 入参名称
public static final String URL_PARAMS_ID = "id";
// http 协议
public static final String SCHEME_HTTP = "http";
// 主机
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请求接口带参数
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("【发送GET请求】成功,相应状态为:{}", response.getStatusLine());
if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) {
String result = EntityUtils.toString(httpEntity);
log.info("【发送GET请求】成功,响应内容为:{}", result);
return result;
}
} catch (IOException e) {
log.error("【发送GET请求】失败,执行发送请求时,出现IO异常,异常信息为:{}", e);
return null;
} finally {
try {
close(httpClient, response);
} catch (IOException e) {
log.error("【发送GET请求】失败,关闭流时,出现IO异常,异常信息为:{}", e);
}
}
return null;
}
}
getStrHttpGet()
:方式一:url拼接参数
public static HttpGet getStrHttpGet(String url, String id) {
StringBuilder builder = new StringBuilder();
// url 拼接参数 /http/getUserById?id=1
String strUrl = builder.append(url).append("?").append(URL_PARAMS_ID).append("=").append(id).toString();
log.info("【发送GET请求】请求地址为:{}", strUrl);
HttpGet httpGet = new HttpGet(strUrl);
return httpGet;
}
getUrlHttpGet()
:方式二:URI对象
public static HttpGet getUrlHttpGet(String id) {
// 将参数键值对放入集合中
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("【发送GET请求】构建URI失败,失败信息为:{}", e);
}
return null;
}
说明:
- 方式一是使用
public HttpGet(String uri);
方式来构造HttpGet
实例 - 方式二是使用
public HttpGet(URL uri);
方式来构造HttpGet
实例。即:使用 url 字符串来拼接参数。
POSTMAN 调用:
POST 无参
调用接口:
http://localhost:8080/http/listUserList
入参:无
HttpClientController#doPostNoParams()
:POST请求接口不带参数
@PostMapping("/doPostNoParams")
public String doPostNoParams() {
return httpClientService.doPostNoParams();
}
HttpClientServiceImpl#doPostNoParams()
:
@Override
public String doPostNoParams() {
String result = HttpClientUtil.doPostNoParams();
log.info("【发送POST请求】返回结果为:{}", result);
return result;
}
HttpClientUtil
:
public class HttpClientUtil {
// POST请求接口不带参数
public static final String POST_URL_NO_PARAMS = IP + PORT + "/http/listUserList";
// POST请求接口带参数
public static final String POST_URL_PARAMS = IP + PORT + "/http/getUserVoById";
// POST请求接口带参数 -- 对象参数
public static final String POST_URL_PARAMS_OBJECT = IP + PORT + "/http/listUsers";
// POST请求接口不带参数
public static String doPostNoParams() {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpPost httpPost = new HttpPost(POST_URL_NO_PARAMS);
log.info("【发送POST请求】请求地址为:{}", POST_URL_NO_PARAMS);
CloseableHttpResponse response = null;
try {
response = httpClient.execute(httpPost);
HttpEntity httpEntity = response.getEntity();
log.info("【发送POST请求】成功,相应状态为:{}", response.getStatusLine());
if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) {
String result = EntityUtils.toString(httpEntity);
log.info("【发送POST请求】成功,响应内容为:{}", result);
return result;
}
} catch (IOException e) {
log.error("【发送POST请求】失败,执行发送请求时,出现IO异常,异常信息为:{}", e);
return null;
} finally {
try {
close(httpClient, response);
} catch (IOException e) {
log.error("【发送POST请求】失败,关闭流时,出现IO异常,异常信息为:{}", e);
}
}
return null;
}
}
POST 有参
参数是:普通参数。方式与GET一样即可,直接在 url 后缀上拼接参数
参数是:对象。将参数以请求体 request-body 的方式进行请求
参数是:普通参数+对象。普通参数 直接在 url 后缀上拼接参数;对象 以请求体 request-body 的方式进行请求
普通参数
请求接口:
http://localhost:8080/http/getUserVoById?id=1
对象参数
请求接口:
http://localhost:8080/http/listUsers
入参 UserVo:
{
"id": 1
}
即:这个接口可以随便写
@PostMapping("/listUsers")
public List<UserVo> listUsers(@RequestBody UserVo userVo) {
return httpService.listUsers();
}
HttpClientController#doPostParams()
:POST请求接口带参数
@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("【发送POST请求】返回结果为:{}", result);
return result;
}
HttpClientUtil#doPostParams()
:
public static String doPostParams(String id) {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
// 参数是普通参数
HttpPost httpPost = getStrHttpPost(POST_URL_PARAMS, id);
// 参数是对象
//HttpPost httpPost = getObjectHttpPost(id);
// 设置ContentType(注:如果只是传普通参数的话,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("【发送POST请求】成功,相应状态为:{}", response.getStatusLine());
if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode() && null != httpEntity) {
String result = EntityUtils.toString(httpEntity);
log.info("【发送POST请求】成功,响应内容为:{}", result);
return result;
}
} catch (IOException e) {
log.error("【发送POST请求】失败,执行发送请求时,出现IO异常,异常信息为:{}", e);
return null;
} finally {
try {
close(httpClient, response);
} catch (IOException e) {
log.error("【发送POST请求】失败,关闭流时,出现IO异常,异常信息为:{}", e);
}
}
return null;
}
getStrHttpPost()
:POST请求有参:普通参数
public static HttpPost getStrHttpPost(String url, String id) {
StringBuilder builder = new StringBuilder();
// url 拼接参数 /http/getUserVoById?id=1
String strUrl = builder.append(url).append("?").append(URL_PARAMS_ID).append("=").append(id).toString();
log.info("【发送POST请求】请求地址为:{}", strUrl);
HttpPost httpPost = new HttpPost(strUrl);
return httpPost;
}
getObjectHttpPost()
:POST请求有参:对象参数
public static HttpPost getObjectHttpPost(String id) {
HttpPost httpPost = new HttpPost(POST_URL_PARAMS_OBJECT);
log.info("【发送POST请求】请求地址为:{}", POST_URL_PARAMS_OBJECT);
UserVo userVo = new UserVo();
userVo.setId(id);
// 将JAVA对象转换为Json字符串
String jsonString = JSON.toJSONString(userVo);
StringEntity stringEntity = new StringEntity(jsonString, "UTF-8");
// post请求是将参数放在请求体里面传过去的
httpPost.setEntity(stringEntity);
return httpPost;
}
普通参数 + 对象
// 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 {
// 设置 requst-body 参数
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");
// 参数
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("调用accessToken API失败");
}
还没有评论,来说两句吧...