一、基于httpclient实现的远程调用
开发中遇到服务间通过restful接口进行远程调用的情况,可以使用如下的方式进行实现:
maven依赖如下:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
代码实现如下(POST和GET请求):
package com.shencai.xf.common.util;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* @Description: 描述
* @Author: xuyahui
* @Date: 2019/8/13 17:17
* @Version 1.0
*/
public class HttpUtil {
private static Logger logger = LoggerFactory.getLogger(HttpUtil.class.getName());
private static HttpClient httpClient = HttpClientBuilder.create().build();
public static String httpPost(String url, String json) {
HttpPost post = new HttpPost(url);
post.addHeader(HTTP.CONTENT_TYPE, "application/json");
StringEntity entity = new StringEntity(json, "UTF-8");
post.setEntity(entity);
try {
HttpResponse response = httpClient.execute(post);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
if (response.getEntity() != null) {
return EntityUtils.toString(response.getEntity(), "UTF-8");
}
}
throw new IOException("请求出错");
} catch (IOException e) {
e.printStackTrace();
logger.error(e.getMessage());
}
return null;
}
public static JSONObject httpGet(String url){
JSONObject jsonObject = null;
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet get = new HttpGet(url);
try {
HttpResponse response = httpClient.execute(get);
HttpEntity entity = response.getEntity();
String returnString= EntityUtils.toString(entity, "UTF-8");
EntityUtils.consume(entity);
jsonObject = JSONObject.parseObject(returnString);
} catch (IOException e) {
LOG.error("http请求失败", e);
}
return jsonObject;
}
}
二、基于spring 的 RestTemplate 实现
1. service 类注入
@Autowired
private RestTemplate restTemplate;
2. url 和 参数拼接与调用
String url = String.format("%s?page_size=%d&page_num=%d", UPSTREAM_URL, PAGE_SIZE, pageNum);
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
备注:使用的spring版本是 org.springframework:spring-web:5.3.13
三、基于cn.hutool.http实现的远程调用
版本:cn.hutool:hutool-all:5.7.16
1.GET请求
分别是参数在url和参数在body
public static String sendGetRequest(String url, Map<String, String> param){
log.info("[请求参数]: {}",JSON.toJSONString(param));
HttpHeaders headers = new HttpHeaders();
String body = null;
StringBuffer sb = new StringBuffer(url+"?");
if(CollectionUtil.isNotEmpty(param)){
param.entrySet().stream().forEach(v -> sb.append(v.getKey()).append("=").append(v.getValue()).append("&"));
}
url = sb.substring(0,sb.toString().length()-1);
try{
body = HttpRequest.get(url)
.header("Accept", "text/html;charset=UTF-8;")
.contentType("application/json")
.execute().body();
}catch (Exception e){
log.error("sendGetRequest 请求失败!");
}
log.info("sendGetRequest结果:{}", body);
// return JSONObject.parseObject(body,DingTalkTokenVo.class);
return body;
}
public static String sendGetBodyRequest(String url, Object dto){
log.info("[sendPostRequest参数入参]: {}", JSON.toJSONString(dto));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// log.info("sendPostRequest请求参数下发]url: {}, header:{}", url, JSON.toJSONString(headers));
String body = null;
try {
body = HttpRequest.get(url)
.header(headers)
.body(JSON.toJSONString(dto))
.execute().body();
} catch (Exception e) {
log.error("[POST请求]", e);
}
log.info("[sendPostRequest返回值]: {}", body);
return body;
}
2.POST请求
public static String sendPostRequest(String url , Object dto){
log.info("[sendPostRequest参数入参]: {}", JSON.toJSONString(dto));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// log.info("sendPostRequest请求参数下发]url: {}, header:{}", url, JSON.toJSONString(headers));
String body = null;
try {
body = HttpRequest.post(url)
.header(headers)
.body(JSON.toJSONString(dto))
.execute().body();
} catch (Exception e) {
log.error("[POST请求]", e);
}
log.info("[sendPostRequest返回值]: {}", body);
// return JSONObject.parseObject(body, DingTalkRespVo.class);
return body;
}
3.PUT请求
public String sendPutRequest(String url, Object paramVo) {
log.info("[sendPutRequest]: {}", JSON.toJSONString(paramVo));
HttpHeaders headers = new HttpHeaders();
// String url = mesUpdateProductAttributeUrl + paramVo.getId();
headers.setContentType(MediaType.APPLICATION_JSON);
log.info("sendPutRequest]url: {}, header:{}", url, JSON.toJSONString(headers));
String body = null;
try {
body = HttpRequest.put(url)
.header(headers)
.body(JSON.toJSONString(paramVo))
.execute().body();
} catch (Exception e) {
log.error("[sendPutRequest]", e);
}
log.info("[sendPutRequest]: {}", body);
return body;
}
4.DELETE请求
public String sendDeleteRequest(String url, Object data) {
log.info("[sendDeleteRequest]: {}", JSON.toJSONString(data));
HttpHeaders headers = new HttpHeaders();
// String url = mesUpdateProductAttributeUrl + id;
headers.setContentType(MediaType.APPLICATION_JSON);
log.info("sendDeleteRequest]url: {}, header:{}", url, JSON.toJSONString(headers));
String body = null;
try {
body = HttpRequest.delete(url)
.header(headers)
.execute().body();
} catch (Exception e) {
log.error("[sendDeleteRequest]", e);
}
log.info("[sendDeleteRequest]: {}", body);
// return JSONObject.parseObject(body, DingTalkRespVo.class);
return body;
}
这里远程调用的方法默认返回值都是String类型,具体调用的Service类里面根据需要把数据进行转换。具体转换如下:
// 转为对象
JSONObject.parseObject(body, DingTalkRespVo.class);
// 转为对象集合
List<ExtProjectCompletePlan> plans = JSONArray.parseArray(dataJson, ExtProjectCompletePlan.class);
// 解析响应
DigitalTwinApiResponse apiResponse = JSON.parseObject(response.getBody(), DigitalTwinApiResponse.class);
四、大数据量情况下的分页远程调用和存储实现方案
整体思路:首先被调用的接口要支持分页查询,然后传入分页参数基于for循环调用,查询到数据之后就进行存储或进行缓存,退出循环的条件就是当前调用获取到数据为空。
具体实现代码如下:
public void syncDataFromHWCloud(String apiUrl) {
int totalSynced = 0;
int pageNum = 1;
int offsetValue = 0;
try {
// 1. 清空旧数据(根据业务需求决定是否保留)
// planService.truncateTable();
this.removeAll();
// 2. 循环获取所有分页数据
boolean hasMoreData = true;
List<ExtProjectCompletePlan> plans;
while (hasMoreData) {
offsetValue = PageUtils.calculateOffset(pageNum,PAGE_SIZE);
String url = String.format("%s?limitValue=%d&offsetValue=%d", apiUrl, PAGE_SIZE, offsetValue);
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
// 3. 解析响应
UpstreamApiResponse apiResponse = JSON.parseObject(response.getBody(), UpstreamApiResponse.class);
if (apiResponse.getData() == null || !apiResponse.getData().getSuccess()) {
hasMoreData = false;
break;
}
// 4. 解析实际数据
String dataJson = apiResponse.getData().getData();
plans = JSONArray.parseArray(dataJson, ExtProjectCompletePlan.class);
if (plans == null || plans.isEmpty()) {
hasMoreData = false;
break;
}
this.saveBatch(plans);
// 5. 保存当前页数据
totalSynced += plans.size();
pageNum++;
// 6. 简单限流,避免请求过快(可根据实际情况调整)
Thread.sleep(200);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
本文介绍了一种在开发中实现服务间通过RESTful接口进行远程调用的方法,包括使用Apache HttpClient库的Maven依赖及具体代码实现,适用于Java开发者理解和实现跨服务通信。
915

被折叠的 条评论
为什么被折叠?



