ApiBoot Resource Load是一款资源与业务完全分离的基础框架,可以整合微服务(Feign、OpenFeign)进行负载均衡读取固定类型、固定所属业务的资源信息,遵循一定的资源存储规则完成自动化资源读取、添加、更新、删除、缓存等。

使用场景

  • 业务图片存储
  • 业务音频、视频文件存储
  • 业务文件
  • 其他资源文件…

引入 ApiBoot Resource Load

pom.xml配置文件内添加如下依赖:

  1. <!--ApiBoot Resource Load-->
  2. <dependency>
  3. <groupId>org.minbox.framework</groupId>
  4. <artifactId>api-boot-starter-resource-load</artifactId>
  5. </dependency>

如果对ApiBoot使用不了解,可查看快速接入ApiBoot

了解ApiBootResourceStoreDelegate

ApiBootResourceStoreDelegate是一个资源数据读取的委托驱动接口,在使用ApiBoot Resource Load时,需要实现该接口完成资源的读取方法loadResourceUrl(),该方法的参数如下所示:

  • 第一个参数sourceFieldValue,是查询资源的业务编号,具体的配置详见下面的示例。
  • 第二个参数resourceType,是查询资源的类型,相同的业务编号下很有可能存在多种类型,比如:用户编号对应用户头像、用户封面等。ApiBootResourceStoreDelegate示例:
  1. // 示例
  2. @Service
  3. public class ResourceLoadService implements ApiBootResourceStoreDelegate {
  4. /**
  5. * logger instance
  6. */
  7. static Logger logger = LoggerFactory.getLogger(ResourceLoadService.class);
  8. @Override
  9. public List<String> loadResourceUrl(String sourceFieldValue, String resourceType) throws ApiBootException {
  10. logger.info("查询资源的业务逻辑字段值:{}", sourceFieldValue);
  11. logger.info("资源类型:{}", resourceType);
  12. return Arrays.asList(new String[]{"http://test.oss.com/111.png"});
  13. }
  14. }

loadResourceUrl方法需要返回根据resourceFieldValueresourceType字段查询到的资源列表。

内置注解

  • @ResourceLoad

标注方法需要进行ApiBoot Resource Load自动化读取资源信息,该注解必须添加,且只能添加在方法上。

  • @ResourceFields

@ResourceField注解的集合

  • @ResourceField

配置@ResourceLoad标注的方法具体有哪些字段需要进行资源的自动映射,参数解释如下所示:

  • name:查询资源后设置到类内Field的名称
  • source:查询资源所需的业务逻辑编号类内Field的名称
  • type:资源类型,自行定义
  • isArray:接收查询后资源的Field类型是否为array,true:array
  • isList:接收查询后资源的Field类型是否为list,true:list

单对象资源加载

资源加载一般都是实体类的方式进行返回的,下面我们先来创建一个实体类方便示例测试,如下所示:

  1. /**
  2. * 示例对象
  3. */
  4. @Data
  5. class SampleUserInfo {
  6. public SampleUserInfo(String userId, int age) {
  7. this.userId = userId;
  8. this.age = age;
  9. }
  10. private String userId;
  11. private String headImage;
  12. private String shortImage;
  13. private int age;
  14. }

返回值为单对象资源加载示例:

  1. /**
  2. * 返回值为单个对象的示例
  3. *
  4. * @return
  5. */
  6. @ResourceLoad
  7. @ResourceFields({
  8. @ResourceField(name = "headImage", source = "userId", type = "HEAD_IMAGE"),
  9. @ResourceField(name = "shortImage", source = "userId", type = "SHORT_IMAGE")
  10. })
  11. public SampleUserInfo singleObjectSample() {
  12. return new SampleUserInfo("yuqiyu", 24);
  13. }

在上面,我们配置读取两种类型的资源,分别是:HEAD_IMAGESHORT_IMAGE,而且配置的业务资源编号都是userId字段,这两个字段也就是会传递给ApiBootResourceStoreDelegate#loadResourceUrl方法作为参数。

其中HEAD_IMAGE读取到的资源路径设置到SampleUserInfo类内的headImageSHORT_IMAGE读取到的资源路径设置到SampleUserInfo类内的shortImage字段。

注意:如果你的方法返回对象只有一个资源对象需要映射,可以单独配置使用@ResourceField注解。

List集合资源加载

  1. /**
  2. * 返回值为list集合的示例
  3. *
  4. * @return
  5. */
  6. @ResourceLoad
  7. @ResourceFields({
  8. @ResourceField(name = "headImage", source = "userId", type = "HEAD_IMAGE"),
  9. @ResourceField(name = "shortImage", source = "userId", type = "SHORT_IMAGE")
  10. })
  11. public List<SampleUserInfo> listSample() {
  12. List<SampleUserInfo> users = new ArrayList();
  13. users.add(new SampleUserInfo("yuqiyu", 24));
  14. users.add(new SampleUserInfo("hengboy", 24));
  15. return users;
  16. }

在上面,会为返回值list内的每一个SampleUserInfo对象进行设置查询的资源信息。

Map集合资源加载

  1. /**
  2. * 返回值为map集合的示例
  3. *
  4. * @return
  5. */
  6. @ResourceLoad
  7. @ResourceFields({
  8. @ResourceField(name = "headImage", source = "userId", type = "HEAD_IMAGE"),
  9. @ResourceField(name = "shortImage", source = "userId", type = "SHORT_IMAGE")
  10. })
  11. public Map<String, SampleUserInfo> mapSample() {
  12. Map<String, SampleUserInfo> users = new HashMap<>(2);
  13. users.put("yuqiyu", new SampleUserInfo("yuqiyu", 24));
  14. users.put("hengboy", new SampleUserInfo("hengboy", 24));
  15. return users;
  16. }

Map类型作为返回值时,其中注意map -> value必须是对象类型。

内存方式缓存资源

ApiBoot Resource Load提供了内存缓存的支持,相同类型、相同业务逻辑的资源数据只会从数据库内读取一次,除非执行资源的删除、更新,否则只能等到下次重启项目时进行更新。

Redis方式缓存资源

ApiBoot Resource Load支持使用redis进行自动缓存资源数据,尽可能减轻数据库的读取压力。

添加redis集成

使用spring-boot-starter-data-redis依赖来完成集成redis,在pom.xml添加依赖如下所示:

  1. <!--Spring Boot Redis Starter-->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-data-redis</artifactId>
  5. </dependency>

添加依赖后需要进行相应的配置,在application.yml配置文件内,如下所示:

  1. spring:
  2. redis:
  3. password: 123456

在上面仅仅配置了连接密码,spring-boot-starter-data-redis配置文件提供了大多数的默认配置,可自行修改。

ApiBoot Resource Load自动通过RedisTemplate来完成资源缓存,无需额外配置

表达式使用

@ResourceField注解的namesource属性都支持表达式使用,如下示例:

  1. @ResourceLoad(event = ResourceStoreEvent.INSERT)
  2. @ResourceFields({
  3. @ResourceField(name = "#p2", source = "#p1.userId", type = ResourceConstant.SHORT_IMAGE),
  4. @ResourceField(name = "#p3", source = "#p0", type = ResourceConstant.HEAD_IMAGE)
  5. })
  6. public void insertResource(String userId, UserInfo userInfo, List<String> shortImage, String headImage) {
  7. //...
  8. }

在上面代码中,#p是正则表达式所匹配的规则,#p0为第一个参数,#p1则为第二个参数,以此类推。

如果参数是对象类型,可以通过#p1.userId来指定source对应业务编号的字段。

#p1.userId则对应参数userInfo对象内的userId字段。

自动添加资源

配置资源的自动添加,是通过方法的参数值来进行实现,如下所示:

  1. @ResourceLoad(event = ResourceStoreEvent.INSERT)
  2. @ResourceFields({
  3. @ResourceField(name = "#p1", source = "#p0.userId", type = ResourceConstant.SHORT_IMAGE),
  4. @ResourceField(name = "#p2", source = "#p0.userId", type = ResourceConstant.HEAD_IMAGE)
  5. })
  6. public void insertUser(UserInfo userInfo, List<String> shortImage, String headImage) {
  7. //..
  8. }

在上面添加资源示例中,要注意,@ResourceLoadevent属性需要修改为ResourceStoreEvent.INSERT

  1. @ResourceField(name = "#p2", source = "#p1.userId", type = ResourceConstant.SHORT_IMAGE)
  • name:配置使用第二个参数作为SHORT_IMAGE类型的资源列表。
  • source:注意#p索引是从0开始,所以这里#p1是第二个参数,#p0.userId配置使用第一个参数的userId作为业务逻辑编号字段。
  • type:常量,自定义

解释:

当调用配置以上注解的方法时,会自动调用ApiBootResourceStoreDelegate#addResource方法完成资源的添加,在调用之前,需要从#p0.userId标注的参数对象中拿到userId的值作为资源编号,然后拿到#p1标注的参数值作为资源列表,最终拿到type的值一并传递给ApiBootResourceStoreDelegate#addResource方法,做自行保存处理。

  1. @ResourceField(name = "#p2", source = "#p0.userId", type = ResourceConstant.HEAD_IMAGE)

解释:

调用方法之前,需要拿到#p0.userId第一个参数作为业务逻辑编号,然后拿到#p2第三个参数作为资源列表,最后拿到type的值一并传递给ApiBootResourceStoreDelegate#addResource方法。

注意:insertResource方法配置了两个@ResourceField所以在执行时,会调用两次ApiBootResourceStoreDelegate#addResource方法。

自动更新资源

配置资源的自动更新,同样是通过方法的参数值来进行实现,如下所示:

  1. @ResourceLoad(event = ResourceStoreEvent.UPDATE)
  2. @ResourceFields({
  3. @ResourceField(name = "#p1", source = "#p0", type = ResourceConstant.SHORT_IMAGE)
  4. })
  5. public void updateUserImage(String userId, List<String> shortImage) {
  6. //...
  7. }

在上面示例中,配置@ResourceField注解则会完成,类型为SHORT_IMAGE且业务逻辑编号为第一个参数值的资源更新,而更新的资源列表则是第二个参数,也就是List集合。

具体解释与自动添加资源一致。

自动删除资源

配置资源的自动删除,同样是通过方法的参数值来进行实现,如下所示:

  1. @ResourceLoad(event = ResourceStoreEvent.DELETE)
  2. @ResourceFields({
  3. @ResourceField(name = "shortImage", source = "#p0", type = ResourceConstant.SHORT_IMAGE),
  4. @ResourceField(name = "headImage", source = "#p0", type = ResourceConstant.HEAD_IMAGE)
  5. })
  6. public void deleteUser(String userId) {
  7. //删除用户逻辑
  8. }

在上面代码中,删除用户时,会自动删除userId业务编号下的SHORT_IMAGEHEAD_IMAGE等资源列表。

资源字段是List或者Array?

如果查询资源时,返回值对象接收资源的字段为List或者Array,可以通过@ResourceField字段的属性来配置,如下所示:

  1. // isList
  2. @ResourceField(name = "shortImage", source = "userId", type = ResourceConstant.SHORT_IMAGE, isList = true)
  3. // isArray
  4. @ResourceField(name = "shortImage", source = "userId", type = ResourceConstant.SHORT_IMAGE, isArray = true)