前言
在我们开发过程中,经常会遇到调用一些第三方的请求与响应,如果只是简单的两种请求与响应那么我们只需要去简单的去封装请求头与请求体即可,并且拼接第三方调用的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);
}
总结
通过这些方法,我们可以高效、安全且优雅地与第三方服务交互,从而提升整个应用程序的质量和可靠性。