调用第三方服务如何优雅的封装请求响应?

前言

在我们开发过程中,经常会遇到调用一些第三方的请求与响应,如果只是简单的两种请求与响应那么我们只需要去简单的去封装请求头与请求体即可,并且拼接第三方调用的key即可,但是遇到一些流程比较繁琐的调用就显得非常的麻烦了。

而高效的去封装这些服务的请求与响应实体不仅能提高代码的可维护性,还能提升整体的开发效率。在这篇博客中,我们将探讨如何有效地实现这一目标。

目标实现

这里我推荐使用第三方的发送请求的工具就是okhttp,下面是在项目中引入的pom文件

xml 复制代码
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.3</version>
</dependency>

还有就是在请求和响应中需要序列化文件

xml 复制代码
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.5</version>
</dependency>

创建请求方法

这里我们一般会将统一请求的参数(例如:appId,key)等参数统一的封装到这个里面

java 复制代码
private static final String CONTENT_TYPE = "application/json; charset=UTF-8";
/**
 * 发起请求
 * @param path 请求拼接路径
 * @param method 请求类型
 * @param payload 请求体
 * @return 响应体
 */
@NotNull
@SneakyThrows
protected String request(String path, String method, String payload) {
    //获取统一的请求前缀
    String url = getUrl(path);
    String pathAndParameters = url.replace(getUrl(""), "");

    Request.Builder builder = new Request.Builder()
            .url(url)
            .header("X-Tsign-Open-App-Id", appId)
            .header("X-Tsign-Open-Auth-Mode", "Signature")
            .header("X-Tsign-Open-Ca-Timestamp", String.valueOf(System.currentTimeMillis()))
            .header("Date", "")
            .header("Accept", "*/*")
            .header("Content-MD5", contentMD5)
            .header("Content-Type", CONTENT_TYPE);



    RequestBody body = null;
    if (StringUtils.isNotBlank(payload)) {
        body = RequestBody.create(payload.getBytes(), MediaType.parse(CONTENT_TYPE));
    }
    builder.method(method, body);

    Request httpRequest = builder.build();
    Response r = httpClient.newCall(httpRequest).execute();
    if (!r.isSuccessful()) {
        System.err.println("请求异常: r=" + r);
        return null;
    }

    String text = r.body().string();
    return text;
}

通过这段代码我们就可以统一将填充的内容封装到请求当中了。

配置请求参数

我们的请求参数如果是微服务就可以配置参数到配置中心,然后供我们后续使用如下示例:

  • 添加yml配置
yml 复制代码
config:
  appId: 123
  secret: ***
  • 预设配置 创建一个类去接收这些配置
java 复制代码
@Data
@ConfigurationProperties("config")
public class PropertiesConfig{

    /**
     * appId
     */
    String appId;

    /**
     * 密钥
     */
    String secret;

}
  • 用bean的方式在项目启动的时候填充到这个类中
less 复制代码
@Configuration
@AllArgsConstructor
@EnableConfigurationProperties(PropertiesConfig.class)
public class UseAutoConfiguration {

    private final PropertiesConfig properties;

    @Bean
    @ConditionalOnProperty(value = "fastesign.appId")
    FastEsignService esignService() {
    //需要配置的config类
        UseConfig bean = new UseConfig();
        bean.setSecret(properties.getSecret());
        bean.setAppId(properties.getAppId());
        return bean;
    }
  • 预设类 让我们再来看看useConfig中要添加那些属性呢?
java 复制代码
public class UseConfig {
/**
 * appId
 */
@Setter
String appId;

/**
 * 密钥
 */
@Setter
String secret;

为需要注入的方法添加一个set方法,在项目启动的时候将属性注入到里面,然后供上面去调用

Json序列化

因为在服务之间传输基本都是使用的序列化,这里我也直接提供json序列化util工具了,后续我们使用直接调用这些工具类了

typescript 复制代码
//序列化
public static String toJson(Object object) {
    try {
        return objectMapper.writeValueAsString(object);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

//反序列化
public static <T> T parseObject(String text, Class<T> mainType, Class<?> clazz) {
    try {
        JavaType type = objectMapper.getTypeFactory().constructParametricType(mainType, clazz);
        return objectMapper.readValue(text, type);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

封装不同的请求

因为基本都是一些post和get请求所以这里我就拿这两个请求进行演示了,其他的请求都类似这两请求了

还是那上面已经封装好的请求,然后传入我们需要调用请求方法

vbnet 复制代码
@SuppressWarnings("ALL")
public <T> EsignResponse<T> post(String path, Object request, Class<T> clazz) {
    String text = request(path, "POST", JsonUtils.toJson(request));
    return JsonUtils.parseObject(text, EsignResponse.class, clazz);
}


@SuppressWarnings("ALL")
public <T> EsignResponse<T> get(String path, Class<T> clazz) {
    String text = request(path, "GET", null);
    return JsonUtils.parseObject(text, EsignResponse.class, clazz);
}

这里可以看到它的入参出参类都使用了范型,就是为了方便我们去更好的扩展接口

使用

上面基本就是我们封装的一些基本信息了,我们如何去使用呢?

我们只需要去定义好它的入参出参的类然后按照上面的方法给传入即可

typescript 复制代码
/**
 * post示例
 *
 * @param request
 * @return
 */
public EsignResponse<TestResponse> test(TestRequest request) {
    String path = "/v2/url";
    return UseConfig.post(path, request, TestResponse.class);
}

/**
 * get示例
 *
 * @param request
 * @return
 */
public EsignResponse<TestResponse> get(String request) {
    String path = "/v3/url" + request;
    return fastEsignService.get(path, TestResponse.class);
}

总结

通过这些方法,我们可以高效、安全且优雅地与第三方服务交互,从而提升整个应用程序的质量和可靠性。

相关推荐
XINGTECODE1 小时前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
程序猿进阶1 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺1 小时前
Spring Boot框架Starter组件整理
java·spring boot·后端
凡人的AI工具箱1 小时前
15分钟学 Go 第 60 天 :综合项目展示 - 构建微服务电商平台(完整示例25000字)
开发语言·后端·微服务·架构·golang
先天牛马圣体1 小时前
如何提升大型AI模型的智能水平
后端
java亮小白19971 小时前
Spring循环依赖如何解决的?
java·后端·spring
2301_811274312 小时前
大数据基于Spring Boot的化妆品推荐系统的设计与实现
大数据·spring boot·后端
草莓base2 小时前
【手写一个spring】spring源码的简单实现--容器启动
java·后端·spring
Ljw...3 小时前
表的增删改查(MySQL)
数据库·后端·mysql·表的增删查改
编程重生之路3 小时前
Springboot启动异常 错误: 找不到或无法加载主类 xxx.Application异常
java·spring boot·后端