高效 SDK 集成
学习目标
在这里,你将系统学习了解 高效 SDK 集成
的具体代码实现
我们将以最简单直接
的方式为您呈现内容!
# 🍚 需求分析
# 问题所在
我们已成功自主研发并实现了
随机诗词查询
、随机壁纸下载
、城市天气查询
以及IP 归属地查询
等多种功能接口,并取得了显著的成果。我们的设计理念始终以
用户需求
为导向,目前我们仅完成了接口实现和基础测试,尚未向外界开放。那么,若要实现外部请求调用
我们自主实现的接口资源,应如何操作呢?我们的愿景是让用户不仅能在我们的平台上使用接口,更希望他们能在自己的代码中
轻松调用
。因此,我们需要开发一个服务,使用户能更便捷地在本地代码
中调用我们的接口资源。
# 开发 SDK 接口调用服务
- 我们已明确未来的开发路径:借助
Spring Boot 框架
,定制开发一个 Starter,以构建SDK 接口调用服务
。该服务将提供 SDK 的下载链接
以及作为项目依赖的导入指南,从而确保用户能够便捷
地调用我们的接口。
# 🍺 高效 SDK 集成
- 接下来,我们尝试在 Spring Boot 中自定义一个 Starter,简要介绍下开发流程
# 新建项目
- 新建
Spring Boot
项目memory-client-spring-boot-starter
:
<groupId>com.memory</groupId>
<artifactId>memory-client-spring-boot-starter</artifactId>
<version>0.0.1</version>
# 依赖配置
- 在该项目下的
pom.xml
文件下,新增如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
spring-boot-configuration-processor
在自定义 Spring Boot Starter 时的作用主要是生成配置元数据、提供代码提示和自动补全,以及确保配置属性的正确解析:生成配置元数据
:该依赖会根据在项目中定义的带有@ConfigurationProperties
注解的类,在META-INF
文件夹下生spring-configuration-metadata.json
文件。这个文件是一种元数据文件,其中包含了关于配置属性的信息,如属性名称、类型、默认值等。这些信息可以用于在 IDE 中编辑配置文件时提供代码提示和自动补全等功能。提供代码提示和自动补全
:当你在 IDE 中编辑配置文件时,由于spring-boot-configuration-processor
生成的元数据,IDE 会提供代码提示和自动补全功能。这使得在编写配置文件时更加方便,降低了因拼写错误或配置项不正确而导致的错误。确保配置属性的正确解析
:spring-boot-configuration-processor
在编译时会对带有@ConfigurationProperties
注解的类进行处理,确保配置属性能够被正确地解析和绑定。这对于自定义的 Starter 来说非常重要,因为正确的解析和绑定配置属性是保证 Starter 功能正常的前提。
注意,新建的 Spring Boot 项目的
pom.xml
文件下,都会有build标签
,记得移除 👇:
<!-- 移除该内容 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
# 新增配置文件类
- 在
properties
目录下,新增配置文件类MemoryClientProperties
:
@ConfigurationProperties(prefix = "memory.client")
public class MemoryClientProperties {
private String accessKey;
private String secretKey;
// 省略 Getter()、Setter() 方法
..............................
}
@ConfigurationProperties
注解能够自动获取 application.properties 配置文件中前缀为spring.girlfriend
节点下message
属性的内容
# 新增功能接口
- 在
service
目录下,新增功能接口MemoryClientService
,用来实现对各个接口发起调用:
@Service
public interface MemoryClientService {
/**
* 获取随机名言
*
* @param words 名言类型
* @return 随机名言
*/
String getRandomWord(Words words);
/**
* 获取随机壁纸
*
* @param picture 壁纸类型
* @return 壁纸名言
*/
String getPictureListByType(Picture picture);
}
# 新增功能接口实现类
- 在
service/impl
目录下,新增功能接口实现类MemoryClientServiceImpl
,用来实现对各个接口发起调用:
/**
* 获取随机名言
*
* @param words 名言类型
* @return 随机名言
*/
@Override
public String getRandomWord(Words words) {
String json = JSONUtil.toJsonStr(words);
return HttpRequest.post(GATEWAY_HOST + "/api/words/one/random")
.addHeaders(getHeaderMap(json))
.body(json)
.execute()
.body();
}
/**
* 获取随机壁纸
*
* @param picture 壁纸类型
* @return 壁纸名言
*/
@Override
public String getPictureListByType(Picture picture) {
String json = JSONUtil.toJsonStr(picture);
return HttpRequest.post(GATEWAY_HOST + "/api/wallpaper/list/page/vo")
.addHeaders(getHeaderMap(json))
.body(json)
.execute()
.body();
}
// 省略其他接口调用方法
.................................
- 在
MemoryClientServiceImpl
这个类中,我们也将封装一系列与API 签名认证
相关的功能,包括生成请求头的getHeaderMap()
方法等,以及用于发送请求的方法:
@Data
public class MemoryClientServiceImpl implements MemoryClientService {
@Resource
private MemoryClientProperties memoryClientProperties;
/**
* Gateway 网关地址
*/
private static final String GATEWAY_HOST = "http://localhost:8090";
// 省略构造器
/**
* 构建一个包含签名的头部信息映射
*
* @param body 请求体
* @return 包含特定键值对的 HashMap
*/
public Map<String, String> getHeaderMap(String body) {
Map<String, String> hashMap = new HashMap<>();
hashMap.put("accessKey", accessKey);
hashMap.put("nonce", RandomUtil.randomNumbers(4));
hashMap.put("body", body);
hashMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
hashMap.put("sign", getSign(body, secretKey));
return hashMap;
}
// 省略接口调用方法
...................................
}
- 在
utils
目录下,新增SignUtils
类,在这个类中,封装生成签名的getSign()
方法
/**
* 签名工具
*
* @author 邓哈哈
*/
public class SignUtils {
/**
* 生成签名
*
* @param body 请求体
* @param secretKey 私钥
* @return 签名
*/
public static String getSign(String body, String secretKey) {
Digester md5 = new Digester(DigestAlgorithm.SHA256);
String content = body + "." + secretKey;
// 使用 SHA256 摘要算法生成签名
return md5.digestHex(content);
}
}
# 新增自动配置类
- 新增自动配置类 MemoryClientAutoConfiguration,实现自动化配置功能:
@Configuration
@ConditionalOnClass(MemoryClientService.class)
@EnableConfigurationProperties(MemoryClientProperties.class)
class MemoryClientAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MemoryClientService memoryClientService() {
return new MemoryClientServiceImpl();
}
}
简单介绍下这几个注解的作用:
@Configuration
: 标注类为一个配置类,让 spring 去扫描它;@ConditionalOnClass
:条件注解,只有在classpath
路径下存在指定 class 文件时,才会实例化 Bean;@EnableConfigurationProperties
:使指定配置类生效;@Bean
: 创建一个实例类注入到 Spring Ioc 容器中;@ConditionalOnMissingBean
:条件注解,意思是,仅当 Ioc 容器不存在指定类型的 Bean 时,才会创建 Bean。
# 配置自动装配类路径
配置自动装配的类的路径,用来
标记自动配置类
。这样 Spring Boot 会在启动时,自动会去查找指定文件/META-INF/spring.factories
,若有,就会根据配置的类的全路径去自动化配置:在
Spring Boot 2.x
中,在 resource/META-INF/spring.factories 文件下,添加如下配置:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.starter3.NameAutoConfiguration
- 而在
Spring Boot 3.x
中,在 resource/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件下,添加如下配置:
com.example.starter3.NameAutoConfiguration
# 打包
- 将
memory-client-sdk
打成 jar 包,放到本地的maven
仓库中去,在项目根路径下执行 maven 命令:
mvn clean install
# 导入 SDK 依赖包
- 在需要引入
memory-client-spring-boot-starter
接口调用功能的Spring Boot 项目
中的pom.xml
文件中,导入依赖:
<dependency>
<groupId>com.memory.client</groupId>
<artifactId>memory-backend-server-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
- 在
resouce
目录下的application.yaml
配置文件下,添加如下配置:
memory-api:
client:
access-key: memory
secret-key: 12345678
- 注入
MemoryClientService
,可以对任一接口服务发起调用:
@Resource
private MemoryClientService memoryClientService;
// 随机名言
com.memory.client.model.Words words = gson.fromJson(userRequestParams, com.memory.client.model.Words.class);
result = memoryClientService.getRandomWord(words);
// 随机壁纸
com.memory.client.model.Picture picture = gson.fromJson(userRequestParams, com.memory.client.model.Picture.class);
result = memoryClientService.getPictureListByType(picture);
............................
- 至此,我们实现了
高效 SDK 集成
,使用户能够便捷地在本地代码
中调用我们提供的接口服务。