httpclient工具类
1、网上搜到的httpclient工具类的问题:
1.1、如下图我们都能够发现这种封装的问题:
- 代码繁杂、充斥了很多重复性代码
- 返回值单一,无法拿到对应的Java Bean对象、List、Page对象集合
- 实际场景中会对接大量第三方的OPEN API,下述方法的扩展性差
1.2、简洁调用方式演示
本文基于上述问题,通过设计模式、泛型、JSON工具类的方式进行了封装,得到了下述更方便、更简洁的http请求调用方式
Entity params = new Entity();
params.setUrl("/common/postJson");
Map<String, Object> map = new HashMap<>();
map.put("userId", "13277887788");
map.put("companyId", "87037827534cf");
params.setParams(map);
// 返回对象集合
List<AppEntity> appEntity = thirdHttpProcessorFactory
.doGetReturnList(ThirdSystemEnum.ION, params, AppEntity.class, false);
// 返回分页对象
IPage<AppEntity> appEntity = thirdHttpProcessorFactory
.doGetReturnPage(ThirdSystemEnum.ION, params, AppEntity.class, false);
// 返回String类型
String result = thirdHttpProcessorFactory
.doGetReturnBean(ThirdSystemEnum.ION, params, String.class, false);
// 返回指定的对象
AppEntity appEntity = thirdHttpProcessorFactory
.doGetReturnBean(ThirdSystemEnum.ION, params, AppEntity.class, false);
/**
* 查询资产详情列表
*/
@GetMapping("/detailList")
public AjaxResult detailList(AssetDetailInfoVo vo) throws Exception {
Entity entity = new Entity("/assetInfo/detailList", BeanUtil.beanToMap(vo));
IPage<AssetDetailInfoRsp> list = thirdHttpProcessorFactory
.doGetReturnPage(ThirdSystemEnum.ION, entity, AssetDetailInfoRsp.class, false);
return AjaxResult.success(list);
}
1.3、 目录结构
2、引入的maven仓库
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.16</version>
</dependency>
- ThirdHttpProcessorFactory:存储不同三方平台的处理期
- ThirdHttpProcessor:定义通用的接口
- AbstractThirdHttpProcessor:定义公共的处理逻辑
- IonHttpProcessor:定义各对接平台的差异性逻辑
- CommonResponse:调用第三方通用返回值处理
- Entity:入参
- PageEntity:分页实体
- ThirdSystemEnum:定义三方平台的枚举
3、代码实现
3.1、获取不同第三方处理器的工厂ThirdHttpProcessorFactory
3.1.1、获取单例处理器的工厂实现
import lombok.experimental.Accessors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author ke
* Created by on 2023-10-27 15:23
*/
@Component
@Accessors(chain = true)
public class ThirdHttpProcessorFactory {
@Autowired
private List<ThirdHttpProcessor> thirdHttpProcessors;
private Map<String, ThirdHttpProcessor> thirdHttpProcessorMap;
@PostConstruct
public void init() {
if (CollectionUtils.isEmpty(thirdHttpProcessors)) {
return;
}
thirdHttpProcessorMap = new HashMap<>(8);
for (ThirdHttpProcessor processor : thirdHttpProcessors) {
thirdHttpProcessorMap.put(processor.getType().getCode(), processor);
}
}
private ThirdHttpProcessor getThirdHttpProcessor(String type) {
ThirdSystemEnum thirdSystemEnum = ThirdSystemEnum.getByCode(type);
if (null == thirdSystemEnum) {
throw new ServiceException("三方OpenApi尚未配置,无法进行请求");
}
return thirdHttpProcessorMap.get(type);
}
/**
* http get请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return T 返回数据对象
* @throws Exception 业务执行异常
*/
public <T> T doGetReturnBean(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doGetReturnBean(entity, tClass);
} catch (Exception e) {
throwException(e, isThrow);
}
return null;
}
private void throwException(Exception e, boolean isThrow) throws Exception {
if (isThrow) {
throw e;
}
}
/**
* http post请求,入参支持application/x-www-form-urlencoded 请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return T 返回数据对象
* @throws Exception 业务执行异常
*/
public <T> T doPostReturnBean(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doPostReturnBean(entity, tClass);
} catch (Exception e) {
throwException(e, Boolean.TRUE.equals(isThrow));
}
return null;
}
/**
* http post请求,入参支持application/json请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return T 返回数据对象
* @throws Exception 业务执行异常
*/
public <T> T doPostJsonReturnBean(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doPostJsonReturnBean(entity, tClass);
} catch (Exception e) {
throwException(e, Boolean.TRUE.equals(isThrow));
}
return null;
}
/**
* http get请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return List<T> 返回数据集合
* @throws Exception 业务执行异常
*/
public <T> List<T> doGetReturnList(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doGetReturnList(entity, tClass);
} catch (Exception e) {
throwException(e, Boolean.TRUE.equals(isThrow));
}
return Lists.newArrayList();
}
/**
* http get请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return IPage<T> 返回数据集合
* @throws Exception 业务执行异常
*/
public <T> IPage<T> doGetReturnPage(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doGetReturnPage(entity, tClass);
} catch (Exception e) {
throwException(e, Boolean.TRUE.equals(isThrow));
}
return new Page<T>(entity.getPageNum(), entity.getPageSize(), 0);
}
/**
* http post请求,入参支持application/x-www-form-urlencoded 请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return List<T> 返回数据集合
* @throws Exception 业务执行异常
*/
public <T> List<T> doPostReturnList(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doPostReturnList(entity, tClass);
} catch (Exception e) {
throwException(e, Boolean.TRUE.equals(isThrow));
}
return Lists.newArrayList();
}
/**
* http post请求,入参支持application/json请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return List<T> 返回数据集合
* @throws Exception 业务执行异常
*/
public <T> List<T> doPostJsonReturnList(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doPostJsonReturnList(entity, tClass);
} catch (Exception e) {
throwException(e, Boolean.TRUE.equals(isThrow));
}
return Lists.newArrayList();
}
}
3.1.2、获取多实例处理器的工厂实现
/**
* Dans.com Inc. Copyright (c) 2011-2020 All Rights Reserved
*/
package com.ionrocking.platform.tripartite;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import lombok.experimental.Accessors;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author ke
* Created by on 2023-10-27 15:23
*/
@Component
@Accessors(chain = true)
public class ThirdHttpProcessorFactory implements ApplicationContextAware {
@Autowired
private List<ThirdHttpProcessor> thirdHttpProcessors;
private Map<String, ThirdHttpProcessor> thirdHttpProcessorMap;
private ApplicationContext context = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
private ThirdHttpProcessor getThirdHttpProcessor(String type) {
Map<String, ThirdHttpProcessor> map = context.getBeansOfType(ThirdHttpProcessor.class);
ThirdSystemEnum thirdSystemEnum = ThirdSystemEnum.getByCode(type);
if (null == thirdSystemEnum) {
throw new ServiceException("三方OpenApi尚未配置,无法进行请求");
}
for (Map.Entry<String, ThirdHttpProcessor> httpProcessorEntry : map.entrySet()) {
if (thirdSystemEnum == httpProcessorEntry.getValue().getType()) {
return httpProcessorEntry.getValue();
}
}
throw new ServiceException("三方OpenApi尚未配置,无法进行请求");
}
/**
* http get请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return T 返回数据对象
* @throws Exception 业务执行异常
*/
public <T> T doGetReturnBean(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doGetReturnBean(entity, tClass);
} catch (Exception e) {
throwException(e, isThrow);
}
return null;
}
private void throwException(Exception e, boolean isThrow) throws Exception {
if (isThrow) {
throw e;
}
}
/**
* http post请求,入参支持application/x-www-form-urlencoded 请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return T 返回数据对象
* @throws Exception 业务执行异常
*/
public <T> T doPostReturnBean(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doPostReturnBean(entity, tClass);
} catch (Exception e) {
throwException(e, Boolean.TRUE.equals(isThrow));
}
return null;
}
/**
* http post请求,入参支持application/json请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return T 返回数据对象
* @throws Exception 业务执行异常
*/
public <T> T doPostJsonReturnBean(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doPostJsonReturnBean(entity, tClass);
} catch (Exception e) {
throwException(e, Boolean.TRUE.equals(isThrow));
}
return null;
}
/**
* http get请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return List<T> 返回数据集合
* @throws Exception 业务执行异常
*/
public <T> List<T> doGetReturnList(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doGetReturnList(entity, tClass);
} catch (Exception e) {
throwException(e, Boolean.TRUE.equals(isThrow));
}
return Lists.newArrayList();
}
/**
* http get请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return IPage<T> 返回数据集合
* @throws Exception 业务执行异常
*/
public <T> IPage<T> doGetReturnPage(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doGetReturnPage(entity, tClass);
} catch (Exception e) {
throwException(e, Boolean.TRUE.equals(isThrow));
}
return new Page<T>(entity.getPageNum(), entity.getPageSize(), 0);
}
/**
* http post请求,入参支持application/x-www-form-urlencoded 请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return List<T> 返回数据集合
* @throws Exception 业务执行异常
*/
public <T> List<T> doPostReturnList(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doPostReturnList(entity, tClass);
} catch (Exception e) {
throwException(e, Boolean.TRUE.equals(isThrow));
}
return Lists.newArrayList();
}
/**
* http post请求,入参支持application/json请求
*
* @param thirdSystemEnum 三方系统类型枚举
* @param entity 参数
* @param tClass 返回参数类型
* @return List<T> 返回数据集合
* @throws Exception 业务执行异常
*/
public <T> List<T> doPostJsonReturnList(ThirdSystemEnum thirdSystemEnum, Entity entity, Class<T> tClass, boolean isThrow) throws Exception {
try {
return getThirdHttpProcessor(thirdSystemEnum.getCode()).doPostJsonReturnList(entity, tClass);
} catch (Exception e) {
throwException(e, Boolean.TRUE.equals(isThrow));
}
return Lists.newArrayList();
}
}
3.2、http请求处理的接口ThirdHttpProcessor
import java.util.List;
/**
* 追踪事件处理器
*
* @author ke
* Created by on 2023-06-20 15:23
*/
public interface ThirdHttpProcessor {
/**
* 业务执行
*
* @param entity
* @param tClass
* @return T
* @throws Exception 业务执行异常
*/
<T> T doGetReturnBean(Entity entity, Class<T> tClass) throws Exception;
/**
* 业务执行
*
* @param entity
* @param tClass
* @return
* @throws Exception 业务执行异常
*/
<T> T doPostReturnBean(Entity entity, Class<T> tClass) throws Exception;
/**
* 业务执行
*
* @param entity
* @param tClass
* @return
* @throws Exception 业务执行异常
*/
<T> T doPostJsonReturnBean(Entity entity, Class<T> tClass) throws Exception;
/**
* 业务执行
*
* @param entity
* @param tClass
* @return T
* @throws Exception 业务执行异常
*/
<T> List<T> doGetReturnList(Entity entity, Class<T> tClass) throws Exception;
/**
* 业务执行
*
* @param entity
* @param tClass
* @return
* @throws Exception 业务执行异常
*/
<T> List<T> doPostReturnList(Entity entity, Class<T> tClass) throws Exception;
/**
* 业务执行
*
* @param entity
* @param tClass
* @return
* @throws Exception 业务执行异常
*/
<T> List<T> doPostJsonReturnList(Entity entity, Class<T> tClass) throws Exception;
/**
* 获取事件类型
*
* @return
*/
ThirdSystemEnum getType();
}
3.3、通用逻辑处理的抽象类AbstractThirdHttpProcessor
- 如在通过http client发起HTTP请求时,除了请求头requestHeader、请求入参requestBody不同,其他逻辑都是一样的,则可以进行公共代码的抽取
- 如果存在特殊的逻辑处理,则可以在子类中重写父类的方法
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.nacos.shaded.org.checkerframework.checker.units.qual.K;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author ke
* @Date 2023/10/27
*/
@Slf4j
@Component
public abstract class AbstractThirdHttpProcessor implements ThirdHttpProcessor {
@Resource
protected RedisService redisService;
@Override
public <T> List<T> doGetReturnList(Entity entity, Class<T> tClass) throws Exception {
// 构造请求头
Map<String, String> requestHead = constructRequestHead(entity);
log.info("domainName:{},requestParameter:{},requestHead:{}", sysNacosConfig.getIonRequestUrl(), JSONUtil.toJsonStr(entity), JSONUtil.toJsonStr(requestHead));
// 构造请求数据
Map<String, Object> requestBody = constructRequestBody(entity);
String result = HttpUtil.createGet(sysNacosConfig.getIonRequestUrl() + entity.getUrl())
.addHeaders(requestHead)
.form(requestBody)
.execute()
.body();
return toList(result, tClass, entity);
}
@Override
public <T> List<T> doPostReturnList(Entity entity, Class<T> tClass) throws Exception {
// 构造请求头
Map<String, String> requestHead = constructRequestHead(entity);
// 构造请求数据
Map<String, Object> requestBody = constructRequestBody(entity);
String result = HttpUtil.createPost(sysNacosConfig.getIonRequestUrl() + entity.getUrl())
.addHeaders(requestHead)
.form(requestBody)
.execute()
.body();
return toList(result, tClass, entity);
}
@Override
public <T> List<T> doPostJsonReturnList(Entity entity, Class<T> tClass) throws Exception {
// 构造请求头
Map<String, String> requestHead = constructRequestHead(entity);
// 构造请求数据
Map<String, Object> requestBody = constructRequestBody(entity);
String result = HttpUtil.createPost(sysNacosConfig.getIonRequestUrl() + entity.getUrl())
.addHeaders(requestHead)
.body(JSONUtil.toJsonStr(requestBody))
.execute()
.body();
return toList(result, tClass, entity);
}
/**
* 转换http请求查询结果,不同也无妨返回的结构不一样
* 此处可以拿到调用三方返回的结果集转成通用的返回结果
* @param httpResult
* @param entity
* @param <T>
* @return
*/
public abstract <T> CommonResponse<T> covertHttpResult(String httpResult, Entity entity);
public <T> T toBean(String result, Class<T> tClass, Entity entity) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
CommonResponse<Object> response = covertHttpResult(result, entity);
return objectMapper.readValue(response.getData().toString(), tClass);
}
public <T> List<T> toList(String httpResult, Class<T> tClass, Entity entity) throws JsonProcessingException {
List<T> data = new ArrayList<>();
CommonResponse<List<Object>> response = covertHttpResult(httpResult, entity);
for (Object o : response.getData()) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
data.add(objectMapper.readValue(o.toString(), tClass));
}
return data;
}
public <T> IPage<T> toPage(String httpResult, Class<T> tClass, Entity entity) throws JsonProcessingException {
List<T> data = new ArrayList<>();
IPage<T> page = new Page<>();
CommonResponse<List<Object>> response = covertHttpResult(httpResult, entity);
if (CollUtil.isNotEmpty(response.getData())) {
for (Object o : response.getData()) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
data.add(objectMapper.readValue(o.toString(), tClass));
}
}
page.setTotal(response.getTotal());
page.setRecords(data);
return page;
}
@Resource
protected SysNacosConfig sysNacosConfig;
protected static final int CODE = 200;
@Override
public <T> T doGetReturnBean(Entity entity, Class<T> tClass) throws Exception {
// 构造请求头
Map<String, String> requestHead = constructRequestHead(entity);
// 构造请求数据
Map<String, Object> requestBody = constructRequestBody(entity);
String result = HttpUtil.createGet(sysNacosConfig.getIonRequestUrl() + entity.getUrl())
.addHeaders(requestHead)
.form(requestBody)
.execute()
.body();
return toBean(result, tClass, entity);
}
/**
* 执行
*
* @return
*/
@Override
public <T> T doPostReturnBean(Entity entity, Class<T> tClass) throws Exception {
// 构造请求头
Map<String, String> requestHead = constructRequestHead(entity);
// 构造请求数据
Map<String, Object> requestBody = constructRequestBody(entity);
String result = HttpUtil.createPost(sysNacosConfig.getIonRequestUrl() + entity.getUrl())
.addHeaders(requestHead)
.form(requestBody)
.execute()
.body();
return toBean(result, tClass, entity);
}
@Override
public <T> T doPostJsonReturnBean(Entity entity, Class<T> tClass) throws Exception {
// 构造请求头
Map<String, String> requestHead = constructRequestHead(entity);
// 构造请求数据
Map<String, Object> requestBody = constructRequestBody(entity);
String result = HttpUtil.createPost(sysNacosConfig.getIonRequestUrl() + entity.getUrl())
.addHeaders(requestHead)
.body(JSONUtil.toJsonStr(requestBody))
.execute()
.body();
return toBean(result, tClass, entity);
}
@Override
public <T> IPage<T> doGetReturnPage(Entity entity, Class<T> tClass) throws Exception {
// 构造请求头
Map<String, String> requestHead = constructRequestHead(entity);
// 构造请求数据
Map<String, Object> requestBody = constructRequestBody(entity);
String result = HttpUtil.createGet(sysNacosConfig.getIonRequestUrl() + entity.getUrl())
.addHeaders(requestHead)
.form(requestBody)
.execute()
.body();
return toPage(result, tClass, entity);
}
/**
* 构造请求头
*
* @param entity
* @return
*/
public abstract Map<String, String> constructRequestHead(Entity entity);
/**
* 构造请求体
*
* @param entity
* @return
*/
public Map<String, Object> constructRequestBody(Entity entity) {
if (CharSequenceUtil.isBlank(entity.getUrl())) {
throw new ServiceException("请求路径不能为空");
}
if (null == entity) {
return null;
}
return entity.getParams();
}
/**
* 生成错误信息日志
*
* @param thirdSystemEnum
* @param msg
* @return
*/
public String generalErrorLog(ThirdSystemEnum thirdSystemEnum, String url, String params, String msg) {
String errorMsg = StrUtil.format("调用{}开发平台接口:{},入参:{} 失败,失败原因:{}", thirdSystemEnum.getName(), url, params, msg);
log.error(errorMsg);
return errorMsg;
}
/**
* 生成错误信息日志
*
* @param thirdSystemEnum
* @param msg
* @return
*/
public String generalErrorLogNoParams(ThirdSystemEnum thirdSystemEnum, String url, String msg) {
String errorMsg = StrUtil.format("调用{}开发平台接口:{} 失败,失败原因:{}", thirdSystemEnum.getName(), url, msg);
log.error(errorMsg);
return errorMsg;
}
}
3.4、第三方非通用逻辑处理类IonHttpProcessor
- 比如此处对接的xx公司需要进行access_token获取及验证,然后将access_token放在请求头中
package com.ionrocking.platform.tripartite.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author ke
* @Date 2023/10/27
*/
@Slf4j
@Component
public class IonHttpProcessor extends AbstractThirdHttpProcessor {
private static final String ACCESS_TOKEN_URL = "/token/getAccessToken";
@Override
public <R> CommonResponse<R> covertHttpResult(String httpResult, Entity entity) {
IonResponse<R> response = JSONUtil.toBean(httpResult, IonResponse.class);
if (CODE != response.getCode()) {
generalErrorLog(getType(), entity.getUrl(), JSONUtil.toJsonStr(entity), response.getMsg());
throw new ServiceException(generalErrorLogNoParams(getType(), entity.getUrl(), response.getMsg()));
}
if (null == response.getData()) {
return new CommonResponse<>(response.getRows(), response.getTotal());
}
return new CommonResponse<>(response.getData(), 0);
}
@Override
public Map<String, String> constructRequestHead(Entity entity) {
Map<String, String> header = new HashMap<>(2);
// 存储ION的access_token,降低获取频率
String key = SysConstants.ION_ACCESS_TOKEN_PREFIX + sysNacosConfig.getIonRequestAppId();
Boolean hasKey = redisService.hasKey(key);
if (Boolean.TRUE.equals(hasKey)) {
String accessToken = redisService.getCacheObject(key).toString();
header.put(SysConstants.ACCESS_TOKEN_KEY, accessToken);
} else {
Map<String, Object> params = new HashMap<>(4);
params.put("appId", sysNacosConfig.getIonRequestAppId());
params.put("appSecret", sysNacosConfig.getIonRequestAppSecret());
String result = HttpUtil.get(sysNacosConfig.getIonRequestUrl() + ACCESS_TOKEN_URL, params);
log.info("/token/getAccessToken ==> params:{}, result:{}", JSONUtil.toJsonStr(params), result);
if (CharSequenceUtil.isEmpty(result)) {
return null;
}
TypeReference<IonResponse<Map<String, Object>>> typeRef = new TypeReference<IonResponse<Map<String, Object>>>() {
};
IonResponse<Map<String, Object>> response = JSONUtil.toBean(result, typeRef, false);
if (CODE == response.getCode() && null != response.getData()) {
if (response.getData().containsKey(SysConstants.ACCESS_TOKEN_KEY)) {
String accessToken = response.getData().get(SysConstants.ACCESS_TOKEN_KEY).toString();
Long expireTime = Long.parseLong(response.getData().get(SysConstants.ACCESS_TOKEN_EXPIRE_TIME).toString());
header.put(SysConstants.ACCESS_TOKEN_KEY, accessToken);
redisService.setCacheObject(key, accessToken, expireTime, TimeUnit.SECONDS);
}
} else {
throw new ServiceException(super.generalErrorLogNoParams(getType(), ACCESS_TOKEN_URL, response.getMsg()));
}
}
return header;
}
@Override
public ThirdSystemEnum getType() {
return ThirdSystemEnum.ION;
}
}
如果需要获取多例处理器对象,需要在类上添加注解 @Scope(“prototype”)
3.5、枚举类ThirdSystemEnum
- 区分不同的平台,根据枚举获取不同的实现类
import org.apache.commons.lang3.StringUtils;
/**
* @author ke
* @Date 2023/10/27
*/
public enum ThirdSystemEnum {
/**
* XX科技公司
*/
ION("ion", "xx科技");
private final String code;
private final String name;
public String getName() {
return this.name;
}
public String getCode() {
return this.code;
}
ThirdSystemEnum(String code, String name) {
this.code = code;
this.name = name;
}
public static ThirdSystemEnum getByCode(String code) {
if (StringUtils.isEmpty(code)) {
return null;
}
for (ThirdSystemEnum codeEnum : values()) {
if (code.equals(codeEnum.getCode())) {
return codeEnum;
}
}
return null;
}
}
3.6、第三方返回格式对象IonResponse
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author ke
* @Date 2023/10/27
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class IonResponse<T> implements Serializable {
private static final long serialVersionUID = -8741972144218822267L;
private int code;
/**
* 消息
*/
private String msg;
/**
* 数据
*/
private T data;
/**
* 总记录数
*/
private long total;
}
3.7、处理器入参对象Entity
- 此处定义请求的URL和请求的参数
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Map;
/**
* @author ke
* @Date 2023/10/27
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Entity extends PageEntity{
private static final long serialVersionUID = -6083780287057302816L;
private String url;
/**
* 参数
*/
private Map<String, Object> params;
}
/**
* 分页实体基类
* @author ke
* @Date 2023/11/6
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageEntity implements Serializable {
private Integer pageNum = 1;
private Integer pageSize = 10;
}
3.8 通用三方接口调用返回值接收对象
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 调用第三方通用返回结果处理接收对象
* @author ke
* @Date 2023/11/24
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommonResponse<T> implements Serializable {
private static final long serialVersionUID = 5955491924347403636L;
private T data;
private long total;
}
3.9、Nacos配置
- Nacos中一般存放一些第三方的请求域名、鉴权的appId、appSecret等
tripartite-platform:
ion:
request:
url: http://localhost:8080/api/
appId: YodeqWwp
appSecret: 87037827534cf848a570fae3c93a2469fa0262935af531dddfe7a52ae7f98f41
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* nacos配置信息
* @author ke
* @Date 2023/9/20
*/
@Component
public class SysNacosConfig {
@Value("${upload.path}")
private String uploadPath;
@Value("${tripartite-platform.ion.request.url}")
private String ionRequestUrl;
@Value("${tripartite-platform.ion.request.appId}")
private String ionRequestAppId;
@Value("${tripartite-platform.ion.request.appSecret}")
private String ionRequestAppSecret;
public String getUploadPath() {
return uploadPath;
}
public String getIonRequestUrl() {
return ionRequestUrl;
}
public String getIonRequestAppId() {
return ionRequestAppId;
}
public String getIonRequestAppSecret() {
return ionRequestAppSecret;
}
}
测试
调用三方定义的返回值对象
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
/**
* @author ke
* @Date 2023/10/26
*/
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class AppEntity {
private long id;
private String appId;
@NotBlank(message = "应用名称不能为空")
private String appName;
private String appSecret;
private String accessToken;
private Integer isFlag;
}
测试Controller
@RestController
@RequestMapping("/test")
public class Test {
@Resource
private SysNacosConfig sysNacosConfig;
@Resource
private ThirdHttpProcessorFactory thirdHttpProcessorFactory;
@ResponseBody
@RequestMapping(value = "/get")
public AjaxResult get() throws Exception extends BaseController {
Entity params = new Entity();
params.setUrl("/common/get");
String result = thirdHttpProcessorFactory.doGetReturnBean(ThirdSystemEnum.ION, params, String.class);
return AjaxResult.success(result);
}
@ResponseBody
@RequestMapping(value = "/list")
public AjaxResult list() throws Exception {
Entity params = new Entity();
params.setUrl("/common/list");
List<AppEntity> appEntity = thirdHttpProcessorFactory.doGetReturnList(ThirdSystemEnum.ION, params, AppEntity.class);
return AjaxResult.success(appEntity);
}
@ResponseBody
@RequestMapping(value = "/postJson")
public AjaxResult postJson() throws Exception {
Entity params = new Entity();
params.setUrl("/common/postJson");
Map<String, Object> map = new HashMap<>();
map.put("appId", "YodeqWwp");
map.put("appSecret", "87037827534cf848a570fae3c93a2469fa0262935af531dddfe7a52ae7f98f41");
params.setParams(map);
List<AppEntity> list = thirdHttpProcessorFactory.doPostJsonReturnList(ThirdSystemEnum.ION, params, AppEntity.class);
return AjaxResult.success(list);
}
/**
* 分页查询
*/
@GetMapping("/pageAppInfo")
public AjaxResult pageAppInfo(AppageVo vo) throws Exception {
Entity entity = new Entity("/common/pageAppInfo", BeanUtil.beanToMap(vo));
IPage<AppEntity> list = thirdHttpProcessorFactory.doGetReturnPage(ThirdSystemEnum.ION, entity, AppEntity.class, false);
return AjaxResult.success(list);
}
}