# jackson-expand-boot-starter **Repository Path**: stupid1t/jackson-expand-boot-starter ## Basic Information - **Project Name**: jackson-expand-boot-starter - **Description**: 基于jackson,接口层的数据翻译,,简单无侵入,解放开发 - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 24 - **Forks**: 1 - **Created**: 2023-06-02 - **Last Updated**: 2025-04-30 ## Categories & Tags **Categories**: spring-boot-ext **Tags**: None ## README # jackson-expand GitHub code size in bytes star 基于jackson,接口层的数据展开操作,使用环境是spring, 不依赖任何第三方包 * 使用场景 > 减少对于实时性不高的数据的关联查询,比如创建人姓名,字典翻译等功能。 1. 无代码侵入,引入无感知,只需要在展开的字段上打jackson注解 2. 支持自定义扩展展开行为,如字典,枚举,RPC,feign等等,只要能在spring中的容器做就可以 3. 支持缓存扩展,默认使用内存缓存,可自行扩展redis、caffeine等其它缓存。缓存配置采用Spring的SPI机制 * maven 坐标 ```xml com.github.stupdit1t jackson-expand-boot-starter 1.1.1 ``` # 快速入门 1. 引入maven依赖 2. 在需要展开 or 翻译的字段上打@Expand注解 > 原理是序列化的时候会带着`creater`的值,去请求`sysUserServiceImpl`的`expand`方法。 ```java @Data public class SysCodeRuleInfoVO implements Serializable { @ApiModelProperty("主键") private Long id; @ApiModelProperty("创建人") @Expand(bean = "sysUserServiceImpl") private Long creater; @ApiModelProperty("删除标志") private String deleted; } ``` 原始json ```json { "id": 1, "creater": 1, "deleted": 1 } ``` 展开后的json ```json { "id": 1, "creater": { "id": 1, "name": "张三" }, "deleted": 1 } ``` # 进阶使用 1. 减少每次需要展开参数的代码量,实现自定义 `@ExpandUser` 注解。 ```java /** * 翻译用户ID注解自定义 * * @author 625 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) @Inherited @JacksonAnnotationsInside @Expand(bean = "sysUserServiceImpl", paramsHandler = UserParamsHandler.class) public @interface ExpandUser { /** * 回显到字段, 填写了已填写的为准 * * @return */ String to() default ""; /** * 是否包含多个值。比如字段值为1,2,3 ,如果mul=true, 则展开为集合 * * @return */ boolean mul() default false; } ``` 2.自定义参数处理类 ```java /** * 参数处理类 */ public class UserParamsHandler implements ParamsHandler { /** * 处理被注解标注的字段当前值 * * @param params * @return */ @Override public Object handleVal(Object params) { if (ObjectUtil.isEmpty(params)) { return null; } String paramsStr = String.valueOf(params); return paramsStr; } /** * 处理当前注解的值 * * @param property * @return */ @Override public SerializerParam handleAnnotation(BeanProperty property) { SerializerParam params = new SerializerParam(); // 用户注解值处理 ExpandUser loadUser = property.getAnnotation(ExpandUser.class); if (loadUser != null) { // 反射Bean参数, 默认第一个是注解标注的值,不需要指定,只需要指定自定义的注解参数 params.setRemoteParams(new Object[]{loadUser.mul()}); if (!"".equals(loadUser.to())) { params.setWriteField(loadUser.to()); } } return params; } } ``` 3. `expand`展开类 ```java /** * 展开 数据方法 */ public class SysUserServiceImpl { /** * 处理数据 * * @param userIds 注解标记字段的值 * @param mul 自定义扩展参数值 * @return */ public Object expand(String userIds, boolean mul) { List userInfos = baseMapper.load(userIds.split(",")); if (!mul) { return userInfos.isEmpty() ? null : userInfos.get(0); } else { return userInfos; } } } ``` 4. 展开数据测试 ```java @Data public class SysCodeRuleInfoVO implements Serializable { @ApiModelProperty("主键") private Long id; @ApiModelProperty("创建人") @ExpandUser private Long creater; /** * 假设是多个删除人 */ @ApiModelProperty("删除人") @ExpandUser(mul = true) private String updater; } ``` 响应结果 ```json { "id": 1, "creater": { "id": 1, "name": "张三" }, "updater": [ { "id": 1, "name": "张二" }, { "id": 2, "name": "张三" } ] } ``` # 缓存更换方法 > 默认为本地内存缓存,扩展为Redis 或其他缓存的方法 1. 自定义实现缓存管理类,注册为Spring的Bean对象。即可 ```java import org.springframework.stereotype.Component; @Component public class CustomCovertCache implements ExpandCache { @Override public void put(String key, T value, Integer timeout) { } @Override public T get(String key) { return null; } @Override public void delete(String key){ } @Override public Set keys(String key){ return new HashSet<>(); } @Override public void clear() { } } ``` # 更多spring配置说明 ```yaml spring: jackson: expand: # 是否动态展开,通过接口传参,控制是否要展开字段,默认false dynamic-expand: true # 动态展开接收参数字段名称,默认expand dynamic-expand-parameter-name: expand # 动态展开 统一数据的Path前缀,比如前缀是 data.body. 如果配置 expand=userId, 相当于是expnad=data.body.userId, 默认无 dynamic-expand-common-prefix: data.body # 缓存Key 前缀,默认Expand: cache-prefix: expand # 缓存时间,单位秒, 默认300 cache-timeout: 300 # 展开策略, 可选COVER,COPY。覆盖如果有反序列化冲突可选COPY或者指定字段自定义字段策略,默认COVER覆盖 expand-strategy: copy # COPY策略,COPY字段格式,默认$%s copy-strategy-format: $_%s # 可以扩展到不存在的字段, 设置为false表示被扩展到的字段必须存在, 默认true can-expand-to-not-exist-field: true ``` # 动态展开使用方法 1. 设置动态展开`spring.jackson.expand.dynamic-expand=true`打开,(如果@Expand注解的`expand=false`,那即使动态展开打开了,接口传参了依然无法展开) 2. 编写代码时,在需要展开的字段上添加@Expand注解,并实现相关的展开数据方法 3. 调用接口传参,如需要展开多个字段,传参为`/api/users?expand=inUser,editUser,fater.inUser,fater.fater.inUser`, 示例原始json如下 ```json { "id": -1, "name": "无名", "inUser": 1, "father": 2 } ``` * 展开1个字段`/api/users?expand=inUser`,json如下 ```json { "id": -1, "name": "无名", "inUser": { "id": 1, "name": "儿子", "inUser": 666 }, "father": 2 } ``` * 展开2字段`/api/users?expand=inUser,father`,json如下 ```json { "id": -1, "name": "无名", "inUser": { "id": 1, "name": "儿子", "inUser": 666 }, "father": { "id": 2, "name": "爸爸", "inUser": 666 } } ``` * 展开3字段`/api/users?expand=inUser,father,father.inUser`,json如下 ```json { "id": -1, "name": "无名", "inUser": { "id": 1, "name": "儿子", "inUser": 666 }, "father": { "id": 2, "name": "爸爸", "inUser": { "id": 1, "name": "儿子", "inUser": 666 } } } ``` * 展开4字段`/api/users?expand=inUser,father,father.inUser,father.inUser.inUser`,json如下 ```json { "id": -1, "name": "无名", "inUser": { "id": 1, "name": "儿子", "inUser": 666 }, "father": { "id": 2, "name": "爸爸", "inUser": { "id": 3, "name": "苍天", "inUser": { "id": 3, "name": "苍天", "inUser": 666 } } } } ```