{"id":43524489,"url":"https://github.com/wangzihaogithub/field-intercept","last_synced_at":"2026-02-03T14:37:07.500Z","repository":{"id":57723972,"uuid":"462624167","full_name":"wangzihaogithub/field-intercept","owner":"wangzihaogithub","description":"适合用于DDD思想,解决业务系统的胶水逻辑代码，整理业务逻辑","archived":false,"fork":false,"pushed_at":"2025-12-12T07:19:54.000Z","size":322,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-12-13T17:38:42.089Z","etag":null,"topics":["ddd","entity"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wangzihaogithub.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-02-23T07:19:37.000Z","updated_at":"2025-12-12T07:19:58.000Z","dependencies_parsed_at":"2024-02-11T13:26:08.682Z","dependency_job_id":"71f8c94c-4c3c-4698-9f88-ee97f4570451","html_url":"https://github.com/wangzihaogithub/field-intercept","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/wangzihaogithub/field-intercept","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangzihaogithub%2Ffield-intercept","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangzihaogithub%2Ffield-intercept/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangzihaogithub%2Ffield-intercept/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangzihaogithub%2Ffield-intercept/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wangzihaogithub","download_url":"https://codeload.github.com/wangzihaogithub/field-intercept/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangzihaogithub%2Ffield-intercept/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29047566,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-03T10:09:22.136Z","status":"ssl_error","status_checked_at":"2026-02-03T10:09:16.814Z","response_time":96,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ddd","entity"],"created_at":"2026-02-03T14:37:07.372Z","updated_at":"2026-02-03T14:37:07.473Z","avatar_url":"https://github.com/wangzihaogithub.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# field-intercept\n\n#### 介绍\n本项目解决业务系统的胶水逻辑代码，整理业务逻辑。\n本项目作为协调者，可以让你将领域对象的组织的胶水代码解脱出来，依赖倒置。\n1.业务提供者（定义逻辑），2.业务需求者（注入结果），3.组织胶水代码（由本项目解决）\n\n#### 文档：\n\n- 如果你写业务代码时，将列表查询出来后，经常需要用id再查询一遍换数据，看这个demo [demo1-simple](https://github.com/wangzihaogithub/field-intercept-example/blob/master/demo1-simple/README.md), [demo3-userdefined-selectbyid](https://github.com/wangzihaogithub/field-intercept-example/blob/master/demo3-userdefined/userdefined-selectbyid/README.md)\n- 如果你写业务代码时，将列表查询出来后，经常需要再用字典表再查询一遍换数据，看这个demo [demo3-userdefined-datadict](https://github.com/wangzihaogithub/field-intercept-example/blob/master/demo3-userdefined/userdefined-datadict/README.md) , [demo3-userdefined-datadict2](https://github.com/wangzihaogithub/field-intercept-example/blob/master/demo3-userdefined/userdefined-datadict2/README.md)\n- 如果你是dubbo微服务项目，看完前两个后，看这个demo [demo2-dubbo](https://github.com/wangzihaogithub/field-intercept-example/blob/master/demo2-dubbo/README.md)\n- 如果你想将常用的查询独立一个注解区分出来，看这个demo [demo3-userdefined-annotation](https://github.com/wangzihaogithub/field-intercept-example/blob/master/demo3-userdefined/userdefined-annotation/README.md)\n- 如果你需要做查询编排优化, 或更多自定义配置，看这个demo [SpringYML](https://github.com/wangzihaogithub/field-intercept-example/blob/master/SpringYML.md)\n\n\n#### 软件依赖\n1. 只依赖JDK，无其他多余依赖\n2. 兼容java8～java21\n3. 兼容springboot2.x～springboot3.x\n4. 兼容dubbo2.7～dubbo3（兼容dubbo调用方没有提供方的类，会退化为Map）\n\n\n#### 详细看示例项目\n\n[https://github.com/wangzihaogithub/field-intercept-example](https://github.com/wangzihaogithub/field-intercept-example)\n\n\n#### 使用概要\n\n1.  添加maven依赖, 在pom.xml中加入 [![Maven Central](https://img.shields.io/maven-central/v/com.github.wangzihaogithub/field-intercept.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:com.github.wangzihaogithub%20AND%20a:field-intercept)\n\n```xml\n\n            \u003c!-- https://mvnrepository.com/artifact/com.github.wangzihaogithub/field-intercept --\u003e\n            \u003cdependency\u003e\n                \u003cgroupId\u003ecom.github.wangzihaogithub\u003c/groupId\u003e\n                \u003cartifactId\u003efield-intercept\u003c/artifactId\u003e\n                \u003cversion\u003e1.0.18\u003c/version\u003e\n            \u003c/dependency\u003e\n\n```\n\n2. 添加配置，写上业务包名， 比如com.ig， 认为com.ig包下都是业务实体类\n\n        application.yaml里\n\n```yaml\n\n   spring:\n      fieldintercept:\n         beanBasePackages: 'com.xxx'\n\n```\n\n\n3. 在业务系统增加抽象Service， 类似下面这种\n\n```java\n\n         public abstract class AbstractCrudService\u003c\n               REPOSITORY extends AbstractMapper\u003cPO, ID\u003e, \n               PO extends AbstractPO\u003cID\u003e, \n               ID extends Number\n            \u003e \n            implements CompositeFieldIntercept\u003cID, PO, Object\u003e {\n                  @Autowired\n                  private REPOSITORY repository;\n                  // 加个字段，用户支持注入名称（例：员工表=部门/员工名称）\n                  private final KeyNameFieldIntercept\u003cID, Object\u003e keyNameFieldIntercept = new KeyNameFieldIntercept\u003c\u003e(keyClass, this::selectNameMapByKeys);\n                   @Override\n                   public KeyNameFieldIntercept\u003cID, Object\u003e keyNameFieldIntercept() {\n                       return keyNameFieldIntercept;\n                   }\n\n                  // 加个字段，用于支持注入实体类Like (例：List\u003cSysUserVO\u003e, SysUser, SysUserDTO)\n                  private final KeyValueFieldIntercept\u003cID, PO, Object\u003e keyValueFieldIntercept = new KeyValueFieldIntercept\u003c\u003e(keyClass, valueClass, this::selectValueMapByKeys);\n                   @Override\n                   public KeyValueFieldIntercept\u003cID, PO, Object\u003e keyValueFieldIntercept() {\n                       return keyValueFieldIntercept;\n                   }\n\n                  // 这个方法你可以实现的，因为持久化框架都默认实现了ByIds的查询\n                   public Map\u003cID, String\u003e selectNameMapByKeys(Collection\u003cID\u003e ids) {\n                       return convertNames(repository.findByIds(ids));\n                   }\n                  \n                   // 这个方法你可以实现的，因为持久化框架都默认实现了ByIds的查询\n                   public Map\u003cID, PO\u003e selectValueMapByKeys(Collection\u003cID\u003e ids) {\n                       return repository.findByIds(ids).stream()\n                               .collect(Collectors.toMap(AbstractPO::getId, e -\u003e e));\n                   }\n                     \n                  // 显示名称的拼接格式\n                   protected Map\u003cID, String\u003e convertNames(List\u003cPO\u003e pos) {\n                       return pos.stream().collect(Collectors.toMap(AbstractPO::getId, po -\u003e nameGetter.getReadMethod().invoke(po)));\n                   }\n         }\n         \n```\n\n4. 然后你可以使用方式1或方式2暴露你的提供者逻辑，就可以供他人使用了\n\n```java\n\n         // 方式1 （通用的无逻辑的根据id查询）\n         @Service(\"SYS_USER\")\n         public class SysUserServiceImpl extends AbstractCrudService\u003cLong, SysUser, SysUserMapper\u003e{\n    \n         }\n\n```\n\n```java\n\n         // 方式2（自定义逻辑的根据id查询）\n         @Service(\"TALENT_WORK_LAST\")\n         public class TalentWorkLastServiceImpl \n               extends DefaultCompositeFieldIntercept\u003cInteger, List\u003cTalentWork\u003e, Object\u003e {\n              public TalentWorkLastServiceImpl(TalentWorkMapper mapper) {\n                  super(\n                          ids -\u003e {\n                              // 查询名称（最近一段工作经历\t公司/职位/时间）\n                              return mapper.selectNameMapByIds(ids);\n                          },\n                          ids -\u003e {\n                              // 查询对象（最后一段工作经历）\n                              return mapper.selectMapByIds(ids);\n                          });\n              }\n       }\n\n```\n\n5. 使用方式：其他使用者在需要你的地方写上你的名字\"SYS_USER\", 这个StatisticsDetailResp只要遇到触发查询的地方，就会被填充。\n\n```java\n\n         @Data\n         public class StatisticsDetailResp {\n             private Integer pipelineId;\n             private Integer talentId;\n             private Integer userId;\n             private List\u003cInteger\u003e userIds;\n\n             @EnumFieldConsumer(value = InterTypeEnum.class, keyField = \"interType\", valueField = \"${color}\")\n             private String interTypeColor;\n\n             /**\n              * 用户\n              */\n             @FieldConsumer(value = \"SYS_USER\", keyField = \"userId\")\n             private SysUserVO user;\n\n             /**\n              * 用户\n              */\n             @FieldConsumer(value = \"SYS_USER\", keyField = \"userIds\")\n             private List\u003cSysUserVO\u003e userList;\n\n             /**\n              * 用户\n              */\n             @FieldConsumer(value = \"SYS_USER\", keyField = \"userIds\")\n             private List\u003cString\u003e userNameList;\n\n             /**\n              * 用户\n              */\n             @FieldConsumer(value = \"SYS_USER\", keyField = \"userIds\")\n             private List\u003cString\u003e userNameList;\n\n             /**\n              * 用户\n              */\n             @FieldConsumer(value = \"SYS_USER\", keyField = \"userIds\", joinDelimiter = \"、\")\n             private String userNames;\n\n             /**\n              * 最后一段工作经历\t公司/职位/时间\n              */\n             @FieldConsumer(value = \"TALENT_WORK_LAST\", keyField = \"talentId\")\n             private TalentWork talentWork;\n\n         }\n         \n```\n\n\n         触发查询的入口有两种：\n\n```java\n\n          // 1. 方法上标记 @ReturnFieldAop注解。\n\n           @ReturnFieldAop\n           @Override\n           public List\u003cStatisticsDetailResp\u003e selectHrDetailList(StatisticsHrListDetailReq req) {\n               return mapper.selectHrDetailList(req);\n           }\n           \n```\n\n```java\n\n          // 2. 主动触发查询\n            @Autowired \n            private ReturnFieldDispatchAop returnFieldDispatchAop;\n\n           @Override\n           public List\u003cStatisticsDetailResp\u003e selectHrDetailList(StatisticsHrListDetailReq req) {\n               List\u003cStatisticsDetailResp\u003e list = mapper.selectHrDetailList(req);\n               // 主动方式1: 并行查询：注：如果在Spring事物中，会导致切出当前事物查询。\n               returnFieldDispatchAop.parallelAutowiredFieldValue(list);\n               return list;\n           }\n            \n           @Override\n           public List\u003cStatisticsDetailResp\u003e selectHrDetailList(StatisticsHrListDetailReq req) {\n               List\u003cStatisticsDetailResp\u003e list = mapper.selectHrDetailList(req);\n               // 主动方式2: 串行查询：注：如果在Spring事物中，不会切出当前事物查询。\n               returnFieldDispatchAop.autowiredFieldValue(list);\n               return list;\n           }\n\n```\n\n#### 其他高阶用法\n\n- 枚举表或字典表\n\n```java\n\n        // 解锁第一种用法：value为字符串，这种不需要你自定义注解。\n        @EnumFieldConsumer(value = \"INTER_ROUND\", keyField = \"interRoundKey\")\n        private String interRoundName;\n\n        // 解锁第二种用法：value为枚举类，要你自定义注解\n        @MyEnumFieldConsumer(value = BizEnumGroupEnum.INTER_ROUND, keyField = \"interRoundKey\")\n        private String interRoundName;\n        \n        \n        // 可选：如果你选择第二种用法，可参考如下自定义注解。如果你用的第一种，value为字符串，可以忽略这一步。\n          @Retention(RetentionPolicy.RUNTIME)\n          @Target({ElementType.FIELD})\n          @EnumDBFieldConsumer.Extends\n          public @interface MyEnumFieldConsumer {\n         \n                String NAME = EnumDBFieldConsumer.NAME;\n        \n              /**\n              * 枚举组\n                */\n                MyBizEnumGroupEnum[] enumGroup();\n        \n              /**\n              * value解析\n              *\n              * @return value解析\n                */\n                Class\u003c? extends MyEnumFieldConsumer.ValueParser\u003e valueParser() default BaseEnumGroupEnumParser.class;\n        \n              /**\n              * 通常用于告知aop. id字段,或者key字段\n              *\n              * @return 字段名称\n                */\n                String[] keyField();\n        \n              /**\n              * 多个拼接间隔符\n              *\n              * @return\n                */\n                String joinDelimiter() default \",\";\n        \n                class BaseEnumGroupEnumParser implements EnumDBFieldConsumer.ValueParser {\n                        @Override\n                        public String[] apply(CField cField) {\n                        // 获取字典类型（字典组）\n                        // 这个方法是为了可供如果你自定义了，类似下面统一管理的枚举类而写的。如果没有可以不写\n                        // public enum MyBizEnumGroupEnum {\n                        //     INTER_ROUND(\"inter_round\",\"面试轮次\"),\n                        //     USER_LEVEL(\"user_level\",\"员工级别\");\n                        //     private String group;\n                        // }\n                            MyBizEnumGroupEnum annotation = (MyBizEnumGroupEnum) cField.getAnnotation();\n                            return Stream.of(annotation.value()).map(SysDictTypeEnum::getGroup).toArray(String[]::new);\n                        }\n                    }\n          }\n\n        // 最终不管你用哪种， 这步查询的实现逻辑都需要你自己写的。\n         @Component(EnumDBFieldConsumer.NAME)\n         public static class BizEnumDBFieldIntercept extends EnumDBFieldIntercept\u003cObject\u003e {\n             @Resource\n             private BizEnumMapper mapper;\n   \n              // 根据(字典group，字典key), 获取 Map\u003c字典group, Map\u003c字典key, 字典value\u003e\u003e\n             @Override\n             public Map\u003cString, Map\u003cString, Object\u003e\u003e selectEnumGroupKeyValueMap(Set\u003cString\u003e groups, Collection\u003cObject\u003e keys) {\n                 return mapper.selectEnumGroupKeyValueList(groups, keys).stream()\n                         .collect(Collectors.groupingBy(BizEnumPO::getGroup,\n                                 Collectors.toMap(BizEnumPO::getKey, e -\u003e e)));\n             }\n         }\n         \n```\n\n        // 结束。可以用了\n\n\n- 如果业务提供者在其他应用中，不在本应用里，可以借助Dubbo，别的都不用改。 详细配置参考：com.github.fieldintercept.springboot.FieldinterceptProperties\n\n\n```yaml\n\n#        提供者参考配置\n            spring: \n                fieldintercept:\n                  bean-base-packages: 'com.xxx'\n                  cluster:\n                      enabled: true\n                      rpc: dubbo\n                      role: provider\n                      dubbo:\n                        registry: 'myRegistryConfig' # 非必填，参考dubbo注册中心配置\n\n```\n\n```yaml\n    \n#        调用者参考配置\n            spring:\n                fieldintercept:\n                    bean-base-packages: 'com.xxx'\n                    cluster:\n                        enabled: true\n                        rpc: dubbo\n                        role: consumer\n                        dubbo:\n                            registry: 'myRegistryConfig' # 非必填，参考dubbo注册中心配置\n\n\n```\n\n- 递归用法\n\n```java\n\n        // 这种用法可以让纵向查询，简化为横向查询（如果递归深度为3，则只进行3次查询，不会随着条数增加而增加）\n        public class FolderParent {\n            private String name;\n            private Long parentId;\n        \n            @FieldConsumer(value = Providers.FOLDER, keyField = \"parentId\")\n            private FolderParent parent;\n        }\n        \n```\n\n- 兼容spring的多线程上下文切换组件\n\n```java\n\n        @Bean\n        public org.springframework.core.task.TaskDecorator taskDecorator(){\n             return new org.springframework.core.task.TaskDecorator() {\n                @Override\n                public Runnable decorate(Runnable runnable) {\n                    return null;\n                }\n            };\n        }\n        \n```\n\n- 非阻塞用法（取决于底层自动优化：可能为异步，可能为单线程聚合，可能为Dubbo调用）\n\n```java\n\n      @ReturnFieldAop\n      public CompletableFuture\u003cList\u003cOrderSelectListResp\u003e\u003e selectList() {\n          List\u003cOrderSelectListResp\u003e list = mapper.selectList();\n          return new FieldCompletableFuture\u003c\u003e(list);\n      }\n\n```\n\n- 非阻塞链式用法（每次回掉阶段，(user,order,errorCode)都会被注入数据 ）\n\n\n```java\n\n        @ReturnFieldAop\n        public CompletableFuture\u003cErrorCode\u003e method1() {\n            CompletableFuture\u003cErrorCode\u003e future = new FieldCompletableFuture\u003c\u003e(user)\n                    .thenApply(user -\u003e{\n                        Order order = ..user// 业务逻辑\n                        return order;\n                    })\n                    .thenApply(order -\u003e{\n                        Invoice invoice = ..order// 业务逻辑\n                        return invoice;\n                    })\n                    .thenApply(order -\u003e{\n                        ErrorCode errorCode = ..order// 业务逻辑\n                        return errorCode;\n                    });\n            return future;\n        }\n\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwangzihaogithub%2Ffield-intercept","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwangzihaogithub%2Ffield-intercept","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwangzihaogithub%2Ffield-intercept/lists"}