crane:字典项与相关数据处理的新思路

前语

在咱们日常开发中,经常会遇到一些烦人的数据相关和转化问题,比方典型的:

  • 方针特点中个有字典 id,需求获取对应字典值并填充到方针中;
  • 方针特点中有个外键,需求相关查询对应的数据库表实体,并获取其间的指定特点填充到方针中appreciate
  • 方针特点中有个枚举,需求将枚举中的指定特点填充到方针中;

实践场景中这种联查的需求或许远远不止这些,这个问题的中心有三点:

  • 填充的数据源是不确认的:或许是来自于 RPC 接口,或许是枚举类,缓存视频变成本地视频也或许是数据库里的装备表,乃至是装备文件;
  • 填充APP方针是不确认的:或许是一般的方针,可是也或实体类图许是 Collection 调集,或许 Map 调集,乃至或许是个 JsonNode,或许有一个嵌套数据库有哪几种结构;
  • 填充的字段的不确认的:相同的数实体类是什么据源,可是或许这个接口回数据库原理来的方针只需求填其间的一个字段,可是另一个接口需求填别的的两个字段;

依据上述三点,咱们在日常场景中很数据库系统概论容易遇到下图的状况:

crane:字典项与相关数据处理的新思路

本文将推荐一个依据 spring 的工具类库 crane,它被规划用来经过相似 MapStruts 的注解装备,完结这种麻烦的相关数据填充/转化操作的处理。

库房地址:giteeappearance.com/CreateSeque…

文档:gitee.com/Create容器云Seque…

一、cAPPrane 是用来做什么的?

1、举个比方

在开始前,咱们先举个实体类是什么比方,假定咱们有一个实体类 PersonVOPersonDO

@Data
public class PersonVO {
  private Integer id;
  private String personName;
}
​
@Data
public class PersonDO {
  private Integer id;
  private String name;
}

然后手头有一批待处理的 PersonVO 方针,咱们需求从 PersonService 中依据 PersonVO.id 获取 PersonDO 调集,然后最后把 PersonDO.name 回填到 PersonVO.personName 中:

List<PersonVO> targets = new ArrayList<>;
​
// 对targets按id分组
Map<Integer, PersonVO> targetMap = new HashMap<>();
targets.forEach(t -> targetMap.put(t.getId(), t));
​
// 对sources按id分组
List<PersonDO> sources = personService.getByIds(targetMap.keySet());
Map<Integer, PersonDO> sourcesMap = new HashMap<>();
sources.forEach(s -> sourcesMap.put(s.getId(), s));
​
// 填充特点
targets.forEach((pid, target) -> {
  PersonDO source = sourcesMap.get(pid);
  if(source != null) {
    target.setPersonName(source.getName())
   }
})

总结一下,假定咱们要手动处理,则无论如何避免不了四个步骤:

  • 数据库软件方针方针中拿到 key 值;
  • 依据 key 值从接口或许办法取得 key 值对应的数据源实体类
  • 将数据源依据 key 值分组;
  • 遍历方针方针,依据 key 值获取到对应的数据源,然后依据依据需求挨个 set 数据源的特点值;

2、运用crane解决上述问题容器中有某种酒精含量的酒精溶液

针对上述的状况,假定运用 crane ,则咱们能够这么做:

第一步,为被填充的 PersonVO 增加注解,装缓存视频合并app备字段:

@Data
public class PersonVO {
  @AssembleMethodSource(namespace = "person", props = @Prop(src = "name", ref = "personName"))
  private Integer id;
  private String personName;
}

第二步,在供给数据源的 PersonService 中为 getByIds 办法也增加一个注解,装备数据源:

public class PersonService {
  @MethodSourceBean.Mehtod(namespace = "person", sourceType = PersonDO.class, sourceKey = "id")
  public List<PersonDO> getByIds(Set<Integer> ids) {
    // return somthing......
   }
}

第三步,运用 crane 供给的 OperateTemplate 辅佐类在代码里完结填充:

List<PersonVO> targets = new ArrayList<>;
operateTemplate.process(targets);

或许直接在办法注解上增加一个注解,回来值将在切面中主动填充:

@ProcessResult(PersonVO.class)
public List<PersonVO> getPersonVO() {
  // return PersonVO list......
}

相比起纯手工填充,cr容器的容积一定比它的体积小ane 带来的优点是显而易见容器所能容纳什么叫做容器的容积的,PersonService 顶用一个注解装备好了数据源后,就能够在任何需求的实体类上用一行注解搞定填充字段的需求。

当然,示例中原始的手动填充的写法依然有很多优化的余地。不过对application应的, crane 的功用也不只只要这些,crane 还支撑装备更多的数据库数据源,不缓存视频合并app只是接口,还缓存视频变成本地视频能是本地缓存,枚举;关于 key 的容器苗映射联系,不止供给示例中的一对一,还支撑一对多;而其间的字段映射,也支撑更多的玩法,这些都会在下文一一介绍。

二、如何引进

crane 依赖于 springboot 环缓存文件夹名称境,假定你是 springboot 项目,则只需求引进依赖:

<dependency>
  <groupId>top.xiajibagao</groupId>
  <artifactId>crane-spring-boot-starter</artifactId>
  <version>${last-version}</version>
</dependency>

las缓存文件夹名称t-version 则是 crane 的版别号,截止至本文发布时数据库查询语句,crane 的最新版别是 0.5.7

然后在发动类增加 @EnableCrane 注解启用装备:

@EnableCrane
@SpringBootApplication
public class Application {
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
   }
}

即可运用 crane 的悉数功用。

三、装备运用

容器是什么段装备是 crane 最中心的装备,它一般由三部分组成:

  • 指定的 key 值字段;
  • 要运用的数据源容器
  • 数据源与方针中字段的映射装备;

这对上述三点,crane 的最常见的写如下:

public class UserVO {
  @Assemble(
    container = UserContainer.class, // 依据userId的值去UserContainer获取数据源
    props = { @Prop(src = "name", ref = "userName") } // 获取到数据源方针后,再把数据源方针User的name字段值映射到UserVO的userName上
   )
  private Integer userId; // 注解在userId上,则userId便是key字段,他的值便是key值
  private String userName;
}

容器是数据库原理另一部分内容缓存视频在手机哪里找,将在后文具体的介绍,这儿咱们先简略理解为依据 key 值获取数据源实体类图的地方。

从注解的application字段取得 key 值,然后再将 key 值从 container 指定的容器中转化为对应数据源后,crane 会依据 props 装备主动的将数据源的字段映射到待处理方针上。

1、字段映射

Assemble#pr实体类图ops 中运用 @Prop 注解声明一对字段APP的映实体类的定义射联系。与 MapStruts@Mapping 注解很像,@Prop#src 用于指定数据源字段,@Prop#ref 指定引证字段,两者实践都答应为空。

不指定数据源字段

当不指定 src 时,即不指容器是什么定数据源字段,此刻填充运用的数据源便是数据源方针自身,比方:

public class UserVO {
  @Assemble(
    container = UserContainer.class, 
    props = @Prop(ref = "userInfo")
   )
  private Integer userId;
  private User userInfo;
}

该操作将直接把作为数据源方针的 User 实例直接填充至 UserVO.userInfo 中。

不指定引证字段

当不指定 ref 时,crane 会以为引证字段便是 key 字段,比方:

public class UserVO {
  @Assemble(
    container = UserContainer.class, 
    props = @Prop(src = "age")
   )
  private Integer userAge;
}

假定此刻 UserVO.userAge 实践对应的值是appointment User.id ,则依据 key 值从容器中获取了数据源方针 User 后,此处 userAge 将被替换为 User.age容器技术值。

不指定任何字段

不指定数据库系统工程师任何字段,作用等同于将 key 字段值替换为对应数据源方针。

比方,咱们有一个特定的容器 Ev实体类是什么aluationContainer,他答应将分数的转为点评,比方 90 =》优、80 =》 良…..实体类图.则咱们能够有:

public class UserVO {
  @Assemble(container = EvaluationContainer.class)
  private String score;
}

履行操作后,score 会被转为对应的“优”,“良”……点评。

2、特别容器类型的字段映射

crane 还支撑处理一些特别的数据类型的字段映射,比方调集、枚举或许一些根本数据源类型,这儿以常见的 Collection 调集为例:

比方,假定咱们现在有一个依据 部分 id 查询职appear工方针调集 EmpUser 的容器 EmpContainer,现在咱们需求依据 DeptVO数据库管理系统.id 填充该部分下数据库系统工程师悉数职工的姓名,则有装备appointment

public class DeptVO {
  @Assemble(container = EmpContainer.class, props = @prop(src = "name", ref = "userNames"))
  private Integer id;
  private List<String> userNames;
}

依据 DeptVO.deptId 从容器中取得了 List<E容器的容积一定比它的体积小mpUser>,然后 cra实体类ne 会遍历元素,尝试从元素中取出每一个 Emp缓存视频怎样转入相册User.n数据库系统工程师ame,然后组装成新的容器设计调集作为数据源。

crane:字典项与相关数据处理的新思路

实践上,这样的操作也适用于数组。

其余数据类型的处缓存视频合并理办法具体能够拜见文档。

3、将字段映射application装备抽离为模板approve

有时分,特别方针的字段大多都来自于相关查询时,咱们需求在 key 字段上装备的注解就会变得及其臃肿,特别是当有多appreciate个方针需求运用相同的装备时,这个状况会变得更加严重。

因而, c容器所能容纳什么叫做容器的容积rane 答应经过 @PropsTemplate将字段装备独自的分离到某个特定的类,然后数据库系统概论第五版课后答案再经过 @Assemble#prop容器是什么Templates特点引证模板装备。

比方,针对一个经过 idappstoreUser方针的 UserContainer 数据源容器,容器是什么咱们现在有这样一组装备:

public class UserVO {
  @Assemble(container = UserContainer.class, props = {
    @prop(src = "name", ref = "userName"),
    @prop(src = "age", ref = "userAge"),
    @prop(src = "sex", ref = "userSex")
   })
  private Integer id;
  private String userName;
  private Integer userAge;
  private Integer userSex;
}

咱们能够运用一个独自的装备类或许装备接口,去承担一部分繁琐的字段装备:

@PropsTemplate({
  @prop(src = "name", ref = "userName"),
  @prop(src = "age", ref = "userAge")
})
public interface UserPropTemplates {};

接着咱们经过引appstore进装备好的字段模板,即能够将本来缓存的注解简化为:

public class UserVO {
  @Assemble(container = UserContainer.class, propTemplates = { UserPropTemplates.class })
  private Integer id;
  private String userName;
  private Integer userAge;
  private Integer userSex;
}

一个操作装备答应引进多个模板,而且一起答应在模板的基础上持续经过 @Assemble#props实体类图 特点额外装备字段映射。

模板装备答应经过装备类的承继/完结联系传递,即在父类 A 经过 @PropTemplat数据库有哪几种e 装备了字段映射,则在装备操作时引进子类 B 作为装备模板,将一并引进父类 A 上的装备。

4、处理字段中的嵌套方针

根本运用

在实践场景中,很容易呈现这样的状况:

假定咱们有一个 UserContainer,答应依据 User.id取得对应的称号,

public class User {
  @Assemble(container = User.class, props = @Prop(ref = "userName"))
  private Integer Id;
  private String userName;
  // 需求填充的嵌套调集
  private List<User> subordinate;
}

咱们有一个职工从属联系的树结构,咱们手头持有一个根节点,可是实践上实例内部有一大堆嵌套的实例需求进行填充。

在 crane 中,经过 @Disassemble 注解符号嵌套字段,在处理时将容器是什么按广度优先主动把他展开铺平后一并处理:

public class User {
  @Assemble(container = User.class, props = @Prop(ref = "userName"))
  private Integer id;
  private String userName;
  @Disassemble(User.class)
  private List<User> subordinate;
}

crane 支撑处理恣意层级的单个方针、数组或Collection调集,也便是说,哪怕是这样的结构也是答应的:

private List<List<User[]>> subordinate;

crane:字典项与相关数据处理的新思路

动态类型

有时实体类是什么分不可避免的会存在无法确认字段类型的场景,比方典型的泛型:

public class ResultWrapper<T> {
  @Disassemble
  private T data;
}

在这种状况是无法直接确认 data 字段的类型appointment的,此刻运用 @Disassemble 注解能够不在 value 或许 targetClass 上直接指定具数据库有哪几种体的类型,crane 将在履行数据库有哪几种操作时经过反射取得 data 的实践类型,然后再经过指定的解析器去获取该类型的对应装备。

5、经过类注解装备

上述介绍都是依据类特点上的 @Assemble@Disassemble 注解完结的,实践上 crane 也支撑经过类上的 @Operations注解装备操作。

根本运用

比方,咱们现有如下状况:

Child 承继了 Parent,可是在运用 Chil实体类图d 实例时又需求依据 id 填充 us实体类erNameuserAge,此刻并不便利直接修改 Parent

public class Parent {
  private String id;
  private String userName;
  private Integer userAge;
}
​
public class Child extends Parent {}

因而,咱们答应在 Child 中如此装备容器英文

@Operations(
  assembles = @Assemble(key = "id", container = UserContainer.class, props = {
    @prop(src = "name", ref = "userName"), 
    @prop(src = "age", ref = "userAge")
   })
)
public class Child extends Parent {}

现在作用等同于appleParent 类中直接注解:

public class Parent {
  @Assemble(container = UserContainer.class, props = {
    @prop(src = "name", ref = "userName"),
    @prop(src = "age", ref = "userAge"),
    @prop("user") // 将user方针直接映射到待处理方针的user字段上
   })
  private String id;
  private String userName;
  private Integer userAge;
}

这个装备仅对 Child 有效,而不会影响到 Parent

key字段别号

因为装备答应经过承继父类或完结父接口取得,因而有或许会呈现 key 字段称号不共同的状况,比方:

现有装备接口 FooInterfa缓存清理ce,指定了一个以 id 为 key 字段的安装操作,可数据库系统概论第五版课后答案是别号答应为 userIduid

@Operations(
  assembles = @Assemble(key = "id", aliases = { "userId, uid" }, container = UserContainer.class, props = {
    @prop(src = "name", ref = "userName"), 
    @prop(src = "age", ref = "userAge")
   })
)
public interface FooInterface

现有 Chil缓存视频合并appd 完结了该接口,可是该类中只要 userId 字段而没有 id 字段,此刻装容器云备是照样收数据库设计效的:

public class Foo implements FooInterface {
  private Integer userId;
}

当一次操作中一起装备的 key 与多个别号数据库系统概论第五版课后答案,则将优先寻觅 key 字段,若不存在则再依据次序apple依据别号查找至少一个真实存在的别号字段。

装备承继与承继扫除

@Operations 注解数据库查询语句答应运用在一般类或许接口类上,而且答应经过数据库有哪几种容器英文结与承继的办法传递装备。

假定现在存在以下类承继结构:容器设计

crane:字典项与相关数据处理的新思路

且上述两实体类个接口与三个类上全都存在 @Operations 注解,此刻在默许状况下,咱们能够剖析以下类 E 的装备状况:

  • 不做任何特别装备,类 E 将承继 A,B,C,D 上的悉数注解装备;实体类的定义

  • 若将 E 的 @Op数据库系统的核心是erati实体类图ons#enablappleeExtend()数据库系统概论第五版课后答案点改为 false,则类 E 将不承继任何父类或完结的接口上的装备,仅保留类 E 上的装备;

  • 若在数据库设计 @Operation#extendExcludes数据库() 装备了扫除承继,则:

    1. 若扫除接口容器英文 B,且类 E 上的 @Operations#enableExtend() 特点为 true,此刻类 E 将承继除接口 B 以外的一切装备,即取得 A,C,D,E 的装备;
    2. 若扫除类 C,且类 E 上的 @Operations#enableExtend() 特点为 true,此刻类 E 将数据库原理不再承继类 C容器 上及其承继/完结树上的装备,可是依然能够经过接口 D 取得接口 B 的装备,此刻类 E 仅 B,D,E 三个类的装备;
    3. 若类 C 上的 @Operations#enableExtend() 特点为 false,且类 E 上的 @Operations#enableExtend() 特点为 true,则此刻 E 将不会经过类 C 取得 A 与 B 的装备,因为 C 并没有承继父类和父接口的装备,此刻 E 将具有 B,C,D,E 四组容器设计装备;

6、分组数据库软件填充

参照 Spring Validation 的分组校approve验,crane 也供给了操作分组的功用,它答应以与 Validati缓存视频变成本地视频on 相似的办法,对安装操作进行分组,然后在操作的时缓存视频怎样转入相册分仅处理指定分组中的操作,比方:

@Assemble(
  container = UserContainer.class, 
  groups = { UserGroup.class, AdminGroup.class }, // 当指定分组为 UserGroup 或 AdminGroup 时填充 userName 字段
  props = @prop(src = "name", ref = "userName")
)
@Assemble(
  container = UserContainer.class, 
  groups = { AdminGroup.class }, // 仅当指定分组为 AdminGroup 时填充 role 字段
  props = @prop(src = "role", ref = "role")
)
private Integer id;

然后能够在相缓存英文关的操作进口中指定本次操作的分组即可。

该功用一个比较典型的应用场景是一个接口一起对内对外实体类的作用,可是有些敏感的信息在对外的时分应该是不展示的,此刻即可经过分组完结。

7、排序填充

安装操作容器云答应经过 spring 供缓存视频合并app给的 @Order 注解对安装操作的履行次序实体类的定义进行排序,与 spring 排序规则相同,value 越小越靠前。

对字段装备排序

比方,现在咱们有一个组合操作,即先依据 userId 获取 deptId,然后再依据 deptId 获取 emp实体类图Users

public class UserVO {
  
  @Order(0)
  @Assemble(container = UserContainer.class, props = @Prop(src = "deptId", ref = "deptId"))
  private Integer userId;
  
  @Order(1)
  @Assemble(container = EmpContainer.class, props = @Prop(ref = "empUsers"))
  private Integer deptId;
  private List<User> empUsers;
}

按上述装备,依据 user容器的容积一定比它的体积小Id 填充 deptId 的操作将会优先履行,然后才会履行依据 deptId 填充 empUsers字段。

对类装备排序

当运用类注解 @Operations 装备操作时,数据库系统工程师@Order 注解只能加在所装备的类上,同一个类上声明的安装操作优先级都与该注解共同,数据库也就说,运用 @Operations时,只支撑不同类上的操作装备的排序,不支撑同一类上的操作排序。

比方:

@Order(0)
@Operations(assembles = @Assemble(container = UserContainer.class, props = @Prop(src = "deptId", ref = "deptId")))
public interface AssembleDeptConfig {}
​
@Order(1)
@Operations(assembles = @Assemble(container = EmpContainer.class, props = @Prop(ref = "empUsers")))
public interface AssembleEmpConfig {}
​
@Operations(enableExtend = true)
public class UserVO implements AssembleEmpConfig, AssembleDeptConfig {
  private Integer userId;
  private Integer deptId;
  private List<User> empUsers;
}

这种状况下,AssembleDeptConfig 上的操作装备就会优先于 AssembleEmpConfig 履行。

8、数据源预处理

crane 答应在经过 @Prop 注解装备字段映射时,运用 @Prop#exp@Prop#ex数据库系统的核心是pType 装备 SpEL 表达式,然后运用表达式从容器中获取的原始的数据源进行预处理。

appreciate方咱们在字段装备一章中提到过的内省容器。经过内省容器,咱们能够获取到待处理方针自身,然后咱们先获容器所能容纳什么叫做容器的容积取待处理方针的userName字段值,然后依据性别动态的将其替换为原值+“先生/女生”:

@Assemble(
  container = IntrospectContainer.class, props = @Prop(
    ref = "userName", 
    exp = "sex == 1 ? #source.name + '先生' : #source.name + '女士'", // 依据性别,在name后追加“先生”或许“女士”
    expType = String.class // 表达式回来值为String类型
   )
)
private String sex;
private String name;

依据 sex字段从容器中获取的数据源,将先经过表达式的处理,然后将回来指定类型的容器对桌面的压强怎么算结果,这个结果将作为新的数据源参加后续处理。

表达式上下文中默许注册了以下变量,答应直接在表达式中引证:

  • #source:原始数据源方针;
  • #target:待处理方approach针;
  • #key容器对桌面的压强怎么算key字段的值;
  • #srcappstore@Prop#src指定数据库系统概论数据库设计参数值;
  • #ref@Prop#ref指定的参数值;

若有需求,也能够自行注册 EapprovexpressionPreprocessingInterceptor.Con缓存视频合并textFactory,在 SpEL 表达式上下文中注册更多变量和缓存的视频在哪办法。

9、自定义注解

crane 深度结合的 spring 的供给的元注解机制,用户缓存视频合并能够依据已有注解,自由的 diy 新注解以更进一步的简化开发。

首要简略的介绍一下 spring 的元注解机制。在 java 中,元注解指能用在注解上的注解,因为 java 的注解自身不支撑承继,因而 spring 凭借 AnnotationElementUtils 等工具类对 java 的元注解机制进行了扩展,完结了一套相似承继的注解容器云组合机制,即 A 注解用在了注解 B 上时,注解 B 也能够被以为是一个特别的 A 注解。

在 crane 中,答应被这样作数据库查询语句为元注解运用的application注解皆以 @容器英文MateAnnotation 符号。

假定现在存实体类的作用在有如下字段装备:

@Assemble(container = UserContainer.class, props = {
  @prop(src = "name", ref = "userName"),
  @prop(src = "age", ref = "userAge")
})
private Integer id;

咱们能够上述 @Assemble缓存清理 装备作为元注解,创建一个 @AssembleUser 注解:

@Assemble(container = UserContainer.class, props = {
  @prop(src = "name", ref = "userName"),
  @prop(src = "age", ref = "userAge")
})
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AssembleUser {}

然后将本来的装备缓存清理替换为:

@AssembleUser
private Integer id;

即可完结与之前彻底相同的作用。

四、数据源

在 crane 中,任何将能够将 key 转化为对应的数据源的东西都能够作为容器,crane 供给了五个默许的appearance容器完结,它们能够掩盖绝大部分容器苗的场景下的数据源:

  • 键值对缓存:对应容器 KeyValueContainer,答应依据 namesapc数据库系统概论第五版课后答案e 和 key 注册和获取任何数据;
  • 枚举:对应容器 EnumDictContainer,答应向容器中注册枚举类,然后经过指定的 namesapce 和 key 取得对应的枚举实例;
  • 实例办法:对应容器 MethodContainer,答应经过注解简略装备,将恣意方针实例的办法作为数据源,数据库系统的核心是经过 namespace 和 key 直接调用办法获取填充数据。适用缓存清理于任何依据接口或本地办法数据库系统的核心是的回来值进行填充的场景;
  • 内省容器:对应容器 BeanIntrospectContainerKeyIntrospectContaineappstorer,答应直接将当前填充的方针作为数据源。适用于一些字段同步的场景;

接下来咱们看看数据库怎样运用。

1、将键值对缓存作实体类型为数据源

键值对容器KeyVa数据库有哪几种lueContainer依据一个两层 Map 调集完结,本质上是一个依据本地缓存的数据源。在运用前,咱们需求在容器中注册键值对,然后在字段注解上经过 namespace 与 kAPPey 进行引证。

比方,现有一个很典型的性别字典项:

Map<Integer, Object> gender = new HashMap<>();
gender.put(0, "女");
gender.put(1, "男");
keyValueContainer.register("sex", gender);

然后再在待处理方针中引证:

@Assemble(
  container = keyValueContainer.class, // 指定运用键值对容器
  namespace = "sex", // namespace为上文指定的sex
  props = @Prop("sexName") // 从命名空间sex中依据sex字段值获取对应的value,并填充到sexName字段
)
private Integer sex;
private String sexName;

也能够运用 @AssembleKV 简化写法:

@AssembleKV(namespace = "sex", props = @Prop("sexName"))
private Integer sex;
private String sexName;

2、将枚举作为数据源

枚举容器EnumDictContainer用于处理枚举类型的数据源。与键值对相同,运用前咱们需求先向容器注册要运用的枚举。

注册枚举

举个比方,咱们手头有个 Gender 枚举:

@Data
@RequiredArgsConstructor
public enum Gender {
  MALE(1, "男"),
  FEMALE(0, "女");
  private final Integer id;
  private final String desc;
}

则能够按如下办法注册:

// namespace为gender,而且以枚举项的id特点作为key值
enumDictContainer.register(Gender.class, "gender", Gender::id);
// namespace为Gender类的非全限定名Gender,而且以枚举项的 Enum#name() 回来值作为key值
enumDictContainer.register(Gender.class);

依据注解注册

当然,假定觉得手动指定 namespappstoreace 和 key 麻烦,也能够经过注解完结,现在咱们为 Gappointmentend缓存er 枚举类增加注解:

@EnumDict.Item(typeName = "gender", itemNameProperty = "id") // 指定namespace为gender,然后以id的值作为key
@Data
@RequiredArgsConstructor
public enum Gender {
  MALE(1, "男"),
  FEMALE(0, "女");
  private final Integer id;
  private final String desc;
}

然后再在容器中注册,就会主动依据类上的注解获取 namespace 和枚举实例的 key 值了:

enumDictContainer.register(Gender.class);

运用

当咱们将枚举注册到枚举容器后,运用时仅需在 @Assemble注解中引证即可:

@Assemble(
  container = EnumDictContainer.class, // 指定运用枚举容器
  namespace = "gender", // namespace为上文指定的gender
  props = @Prop(src = "name", ref = "genderName") // 获取Gender枚举中的name字段值,并填充到genderName字段
)
private Integer gender;
private String genderName;

注册后的枚举会被解析为 BeanM缓存视频在手机哪里找a缓存视频合并p数据库系统的核心是缓存,咱们能够像处理方针相同简略的经过特点名获取对应的值缓存视频合并

也能够用 @AssembleEnum 注解简化缓存清理写法:

@AssembleEnum(namespace = "gender", props = @Prop(src = "name", ref = "genderName"))
private Integer gender;
private String genderName;

3、将实例办法数据库设计作为数容器中有某种酒精含量的酒精溶液据源

办法容器MethodContainer是依据 namespace 隔离,将各个类实例中的办法作为数据源的容器。

在运用办缓存英文法容器之前,咱们需求先运用 @M数据库系统概论第五版课后答案ethodSou缓存英文rceBean.Method注解作为数据源的办法,然后再运用@MethodSourceBean注解该办法地点的类实例。

注册办法

比方,咱们需求将一个依据用户 id 批量查询用户方针的接口办实体类法作为数据源:

@MethodSourceBean
public class UserService {
  // 该办法对应的命名空间为user,然后指定回来值类型为User.class, key字段为id
  @MethodSourceBean.Mehtod(namespace = "user", sourceType = User.class, sourceKey = "id")
  public List<User> getByIds(List<Integer> ids) {
    // 回来user方针调集
   }
}

当然,假定这个办法来自父类,无法显式的运用注解声明数据源办法,也答应经过类注解声明:

@ContainerMethodBean(
  @ContainerMethodBean.Method(namespace = "user", name = "getByIds", sourceType = User.class, sourceKey = "id")
)
public class UserService extend BaseService<User> {}

当项目发动时,crane 将从 Spring 容器中获取被 @C缓存英文ontainerMethodBea数据库系统工程师n注解的类,并获取其间被注解的办法,并依据指定的 name缓存文件夹名称space 注册到办法容器对应的命名空间。

运用

当咱们运用时,与其他容器保持共同:

@Assemble(
  container = MethodSourceContainer.class, // 指定运用键值对容器
  namespace = "user", // namespace为上文指定的user
  props = @Prop("userBean") // 从命名空间user中获取办法getByIds,然后将userId对应的user方针填充到userBean字段中
)
private Integer userId;
private User userBean;

当然,也容器云能够经过 @AssembleMethodS数据库查询语句ource 注解简化写法:

@MethodSource(namespace = "user", props = @Prop("userBean"))
private Integer userId;
private User userBean;

多对一

容器总是默许办法回来的调集中的方针与 key 字段的值是一对一的,可是也能够调整为一对多。

比方咱们现在有一批待处理的 Classes 方针,需求依据 Classes#id实体类的定义段批量获取Student方针缓存视频怎样转入相册,然后依据Student#classesId字段数据库软件填充到对应的 Classe实体类是什么s 方针中:

@MethodSourceBean.Mehtod(
  namespace = "student", sourceType = Student.class, sourceKey = "classesId",
  mappingType = MappingType.ONE_TO_MORE // 声明待处理方针跟Student经过classesId构成一对多联系
)
public List<Student> listIds(List<Integer> classesIds) {
  // 查询Student方针
}

然后在待处理方针中引证:

@Assemble(
  container = MethodSourceContainer.class,
  namespace = "student",
  props = @Prop("students")
)
private Integer classesId;
private List<Student> students;

4、将待处理方针自身作为数据源

有些时分,咱们会有一些字段同步的需求,待处理方针内省容器 BeanIntrospectContainer 便是用来干这件事的,不只如此,它适用于任何需求对待数据库查询语句处理方针自身进行处理的状况。

待处理方针内省容器BeanIntrospectContainer的数据源便缓存视频合并app是待处理方针自身,它用于需求对待处理方针自身进行处理的状况。

比方简略的同步一下字段:

// 将方针中的name字段的值同步到userName字段上
@Assemble(container = BeanIntrospectContainer.class, props = @Prop("userName")
private String name;
private String userName;

缓存文件夹名称能够用于处理调集取值:

// 将方针中的users调集中悉数name字段的值同步到userNames字段上
@Assemble(container = BeanIntrospectContainer.class, props = @Prop(src = "name", ref = "userNames"))
private List<User> users;
private List<String> userNames;

或许合作 SpEL 预处理数据源的功用处理一些字段:

@Assemble(
  container = BeanIntrospectContainer.class, props = @Prop(
    ref = "name", 
    exp = "sex == 1 ? #source.name + '先生' : #source.name + '女士'", // 依据性别,在name后追加“先生”或许“女士”
    expType = String.class
   )
)
private String sex;
private String name;

也供给了 @AssembleBeaapplenIntrospe数据库设计ct 注解,作用等同于:

@Assemble(container = BeanIntrospectContainer.class)

5、将key值作为数据源

待处理 key 字段内省容器KeyIntrospectContainerBeanIntrospectContainer 根本共同,首要的不同数据库软件在于 KeyIntrospectCont缓存视频合并ainer数据库系统工程师容器对桌面的压强怎么算据源是待处理方针本此操作所对应的 key 字段值容器

除了跟 BeanIntrosp缓存英文ectContainer 差不多的用法以外,因为操作的数据源方针自身变为了 key 字段的值,因而也有了appointment一些特别的用处:

// 将Type枚举的desc字段赋值给typeName字段
@Assemble(container = KeyIntrospectContainer.class, props = @Prop(src = "desc", ref = "typeName"))
private TypeEnum type;
private String typeName;

假定是 JsonNode,还能够这样:

// 运用type字段对应枚举的desc字段替换其本来的值
@Assemble(container = KeyIntrospectContainer.class, props = @Prop(src = "desc"))
private TypeEnum type;

默许供给了 @AssembleKeyIntrospect 注解,作用等同于

@Assemble(container = KeyIntrospectContainer.class)

五、切面

完结了数据数据库系统概论第五版课后答案源和字段的装备今后,就需求在代码中履行填充的操作。crane 一共供给了三个进口:

  • approach办法上增加 @ProcessResult 注解,然后经过 AOP 主动对办法回approach来值进行填充;
  • ObjectMappe容器r 中注册 DynamicJsonN容器所能容纳什么叫做容器的容积odeModule 模块,然后运用该 ObjectMapper 实例序列号数据库原理方针时主动填充;
  • 运用 crane 注册到 spring 容器中的 Operate缓存是什么意思Template 手动容器英文的调用;

第二种会在下一节介绍,而第实体类型三种没啥特别的,这儿首要介绍一些依据切面的办容器设计法回来值主动填充。

运用

默许状况下,crane 会主动把切面注册到 spring 容器中,因而运用时,若办法地点apple类的实例已经被 spring 容器管理,则只需求在办法上增加注解就行了:

// 主动填充回来的 Classroom 方针
@ProcessResult(Classroom.class)
public Classroom getClassroom(Boolean isHandler) {
  return new Classroom();
}

切面支撑处理单个方针,一维方针数组与一维的方针 Collection 调集。

表达式校验

切面还答应依据 SpEL 表达式动态的判别本次办法调用是否需求对回来值进行处理:

@ProcessResult(
  targetClass = Classroom.class
  condition = "!#result.isEmpty && !#isHandle" // 当回来值为空调集,且isHandle参数不为true时才处理回来值
) 
public List<Classroom> getClassroom(Boolean isHandle) {
  return Collections.emptyList();
}

这儿的 SpEL 表达式中默许能够经过 #参数名 的办法引证入参,或许经过 #result 的办法获取回来值。

自定义组件

此外,切面容器所能容纳什么叫做容器的容积注解中还能够自行自定一些 crane 的组件和参数,包含实体类型且不限数据库有哪几种制与分组,履行器等:

@ProcessResult(
  targetClass = Classroom.class,
  executor = UnorderedOperationExecutor.class,
  parser = BeanOperateConfigurationParser.class,
  groups = { DefaultGroup.class }
)
public List<Classroom> getClassroom(Boolean isHandler) {
  return Collections.emptyList();
}

不同的组件会发生不同的作用,比方 executor ,当指定为 AsyncUnorderedOperationExecutor.class 时 crane 会依据本次一切操作对应的容器的不同,异步的履行填充,而指定为 Sequappearanceen容器技术tialOperationExecuto容器设计r 时将支撑按缓存清理次序填充。

这儿更多具体内容能够参阅文档。

六、Json支撑

上述比方都以appreciate一般的 JavaBea实体类n 为例容器苗,实践上 crane 也数据库查询语句支撑直接处理 JsonNappearode。若容器设计要启用 Json 支撑,则需求引进 crane-jackson-implement 模块,其余装备不需求调整。

<dependency>
  <groupId>top.xiajibagao</groupId>
  <artifactId>crane-jackson-implement</artifactId>
  <version>${last-version}</version>
</dependency>

crane-jackson-implement 版别与 crane-spring-boot-starter 版别共同,截止本文发布时,版别号为数据库原理 0.5.7

1、装备

装备 ObjectMapper

引进模块后 crane 将会主意向 spring 容器中注册必要的组件,包含 DynamicJsonNoappearancedeModule 模块,该模块是完结 JsonNode 填充的中心。用户能够自行指定该模块要注册到哪个 ObjectMapper 实例。

一般状况数据库有哪几种下,都会直接把该模块注册到 spring-web数据库设计 供给的那个 ObjectMapper 中,也便是为缓存英文 Controller 增加了 @RestCon实体类型troller 注解、或许为办数据库原理法增加 @ResponseBody 注解后,Controller 中接口回来值主动序列化时运用的 ObjectMapper

比方,咱们现在已经引进了 spring-web容器是什么 模块,则能够在装备类缓存中装备:

@Configuration
public class ExampleCraneJacksonConfig {
​
  @Primary
  @Bean
  public ObjectMapper serializeObjectMapper(DynamicJsonNodeModule dynamicJsonNodeModule) {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(dynamicJsonNodeModule); // 注册动态json模块
    return objectMapper;
   }
​
}

装备字段操作

针对 JsonNode 的装备会跟一般的 JavaBean 有点差异。咱们以一个一般的 Ja数据库系统概论第五版课后答案vaBean 装备为例:

public class Foo {
  @Assemble(
    container = UserContainer.class, 
    props = @prop(src = "name", ref = "userName")
   )
  private String id;
  private String userName;
  
  @Disassemble(Foo.class)
  private List<Foo> foos;
}

首要,需求为序列化时进行数据填充的类增加 @ProcessJacks实体类图onNoappearde 注解:

@ProcessJacksonNode
public class Foo {
   ......
}

然后,在 @Assemble@Disassemble 指定运用 Jackson 的操作者:

@Assemble(
  container = UserContainer.class, 
  props = @prop(src = "name", ref = "userName"), 
  assembler = JacksonAssembler.class
)
private String id;
private String userName;
​
@Disassemble(targetClass = Foo.class, , disassembler = JacksonDisassembler.class)
private List<Foo> foos;

至此方针序列化时的填充装备就悉数完结了。

2、运用

当运用注册了 DynamicJsonNodeModule 模块的 ObjectMapper 序列化方针时就会主动触发填充。

假定 ObjectMapper 被用于 Co缓存英文ntrollerapplication 主动序列化,则 Controller 中接口的回来值缓存是什么意思就会主动填充。而当 ObjectMapper 独自运用时,调用 valueToTree 办法,或许 writeValueAsString 办法都会触发主动填充。

因为 JsonNode数据库系统的核心是 的特别性,相比一般的 JavaBean,它实体类型能够直接增加或替换方针的特点值。

追加字段

假定咱们有如下待序列化的方针,该方针只要一个 id 字段:

@ProcessJacksonNode
public class Foo {
  private String id;
}

咱们能够依据 id 动态增加 name 和 age缓存视频怎样转入相册 字段:

@ProcessJacksonNode
public class Foo {
  @Assemble(assembler = JacksonAssembler, container = UserContainer.class, props = {
    @prop(src = "name", ref = "userName"), 
    @prop(src = "age", ref = "userAge")
   })
  private String id;
}

在序列化后得到如下 json 串:

{
  "id": 1,
  "userName": "foo",
  "userAge": 12
}

替换字段

因为 JsonNoappearancede 自身相当于一个大 Map 调集,因而咱们能够无视 Class 中的类型,直接替换指定字段的值:

@ProcessJacksonNode
public class Foo {
  @Assemble(assembler = JacksonAssembler, container = KeyValueContainer.class, namespace = "sex")
  private Integer sex;
}

序列化后得到:

{
  "sex": "男"
}

同理,假定是数据源容器中供给的数据源是方针也能够直接替换为方针:

{
  "sex": {
    "id": 1,
    "name": "男"
   }
}

结语

cran缓存清理e 的功用和特性不止本文所描绘的这些,它还支撑凭借 reflectasm 库将 JDK 原生的反射替换为字节码调用优化性能,还支撑各种缓存和依据装备缓存视频怎样转入相册文件的预加载等等……缓存的视频在哪.

它算是作者日常开发中面临这种频数据库系统工程师频的数据相关需缓存视频合并求总结出的一个解决方案,它的原型目前容器云已经在公司生成环境投入运用。实践上,crane 肯定是不能适用于一切场景的,可是假定有相approve似需求在后台处理字典项、装备项或许需求相关数缓存据的需求,运用 crane 能大大的进步开发效率。

好吧不演了,这篇文章实践上便是菜鸡作者鼓起勇气推广自己开源项目求运用求 start 的一篇软文。crane 作appearance为一个依然缓存清理还不完善的开源的项目,容器对桌面的压强怎么算还需求更多人的运用与反馈,假定各位看官有爱好,能够去库房了解一下,点个 start,假定觉得有意思,或许有什么自己的主意,也欢迎appearance提出 issues 或许直接加群评论!

crane:字典项与相关数据处理的新思路

库房实体类的作用地址:gitee.com/CreateSeque…

文档:git容器设计ee.c数据库系统概论om/CreateSeque…