高效 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 集成,使用户能够便捷地在本地代码中调用我们提供的接口服务。