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

前言

在我们开发过程中,经常会遇到调用一些第三方的请求与响应,如果只是简单的两种请求与响应那么我们只需要去简单的去封装请求头与请求体即可,并且拼接第三方调用的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);
}

总结

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

相关推荐
光而不耀@lgy4 分钟前
C++初登门槛
linux·开发语言·网络·c++·后端
方圆想当图灵23 分钟前
由 Mybatis 源码畅谈软件设计(七):SQL “染色” 拦截器实战
后端·mybatis·代码规范
毅航1 小时前
MyBatis 事务管理:一文掌握Mybatis事务管理核心逻辑
java·后端·mybatis
我的golang之路果然有问题1 小时前
速成GO访问sql,个人笔记
经验分享·笔记·后端·sql·golang·go·database
柏油1 小时前
MySql InnoDB 事务实现之 undo log 日志
数据库·后端·mysql
写bug写bug3 小时前
Java Streams 中的7个常见错误
java·后端
Luck小吕3 小时前
两天两夜!这个 GB28181 的坑让我差点卸载 VSCode
后端·网络协议
M1A13 小时前
全栈开发必备:Windows安装VS Code全流程
前端·后端·全栈
蜗牛快跑1233 小时前
github 源码阅读神器 deepwiki,自动生成源码架构图和知识库
前端·后端
嘻嘻嘻嘻嘻嘻ys3 小时前
《Vue 3.4响应式超级工厂:Script Setup工程化实战与性能跃迁》
前端·后端