{"id":36694715,"url":"https://github.com/developframework/resource-manager","last_synced_at":"2026-01-12T11:28:00.917Z","repository":{"id":37312804,"uuid":"201506720","full_name":"developframework/resource-manager","owner":"developframework","description":"资源管理器","archived":false,"fork":false,"pushed_at":"2025-06-06T09:05:57.000Z","size":386,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-04T19:54:17.105Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/developframework.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2019-08-09T16:42:06.000Z","updated_at":"2024-11-15T05:08:41.000Z","dependencies_parsed_at":"2025-05-29T04:24:06.492Z","dependency_job_id":"9708d3d4-5c09-4e7e-98c2-7a8fb4775169","html_url":"https://github.com/developframework/resource-manager","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/developframework/resource-manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developframework%2Fresource-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developframework%2Fresource-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developframework%2Fresource-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developframework%2Fresource-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/developframework","download_url":"https://codeload.github.com/developframework/resource-manager/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developframework%2Fresource-manager/sbom","scorecard":{"id":337187,"data":{"date":"2025-08-11","repo":{"name":"github.com/developframework/resource-manager","commit":"0f85464a63a5841548e427ab3c50caf51ba057e5"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":3,"reason":"7 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-h46c-h94j-95f3","Warn: Project is vulnerable to: GHSA-wf8f-6423-gfxg","Warn: Project is vulnerable to: GHSA-3x8x-79m2-3w2w","Warn: Project is vulnerable to: GHSA-57j2-w4cx-62h2","Warn: Project is vulnerable to: GHSA-jjjh-jjxp-wpff","Warn: Project is vulnerable to: GHSA-rgv9-q543-rqg4","Warn: Project is vulnerable to: GHSA-j288-q9x7-2f5v"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T04:58:50.786Z","repository_id":37312804,"created_at":"2025-08-18T04:58:50.786Z","updated_at":"2025-08-18T04:58:50.786Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28338971,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T10:58:46.209Z","status":"ssl_error","status_checked_at":"2026-01-12T10:58:42.742Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":[],"created_at":"2026-01-12T11:28:00.254Z","updated_at":"2026-01-12T11:28:00.909Z","avatar_url":"https://github.com/developframework.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Resource Manager\n\n规范数据库资源的操作\n\n### 资源管理器\n\n讨论资源管理器之前先明确一下现有应用分层体系每一层的职责（基于spring-boot）：\n\n- **@Repository / @Mapper**：它们本质上都属于**DAO （数据访问对象 Data Access Object）**，所谓DAO就是直接与数据库交互的对象，通常它不涉及到对业务的逻辑处理，只是单纯的操纵数据库。spring-data-jpa的自定义实现的RepositoryImpl也只是对操纵数据库的扩展；mybatis就更不用说了，仅仅只是调用了某句SQL\n- **@Service**： 这层就是应用真正存在的意义，解决业务逻辑。通常它会调用各种DAO来解决业务逻辑\n- **@Controller**： 控制层，可以认为是请求进来的第一步（实际上前面还有一层拦截器）。通常它用于分发调用Service层的逻辑方法，可以调用多个Service解决多个业务逻辑。该层也可以对Service的处理结果进一步处理，处理成希望响应的格式\n\n##### 那么资源管理器是什么？\n\n实际上资源管理器处在DAO层和Service层之间，其实算半层的Service，用于简化Service层的逻辑处理。\n\n假如说一个Service的业务逻辑涉及处理多资源业务。那么Manager就是单资源业务的处理器，把各个资源的操作划分出界限独立处理，使代码逻辑更加清晰。对资源的操作划分出若干个步骤，按生命周期来处理，方便有针对性的扩展。\n\n![](doc-images/业务图.png)\n\n### 名词定义\n\n+ **资源（Resource）**：一个现实事物称为资源，通常对应于数据库的一个表\n\n+ **实体（Entity）**: 资源对应的Java Bean称为实体，按照数据库不同可分为**关系型数据库实体（Persistence Object 简称 PO）**和**文档型数据库实体（Document 简称 DOC）**\n\n+ **数据传输对象（DTO）**： 资源操作的入参\n\n+ **资源操作（Resource Operate）**： 对资源的增删改查都称为资源操作，一个操作流程即是一个生命周期\n\n+ **管理器（Resource Manager）**: 集合资源所有操作的管理者，其实相当于通常的一层Service，但它仅仅是对单一资源的管理\n\n+ **资源操作实现者（Resource Handler）**: 真正实现资源操作的实现者\n\n+ **查询条件（Search）**： 封装普通列表查询的条件\n\n它们的关系如图：\n\n![](doc-images/结构图1.png)\n\n### 资源的管理流程\n\n一般的资源管理流程差不多都是相同的逻辑，可概述为下图：\n\n![](doc-images/流程图1.png)\n\n从图上可以看出来资源管理的通用步骤：\n\n+ **前置判断（before）**: 用于判断该资源是不是需要添加，适合配置有限制条件的资源\n+ **验重判断（check）**: 用于对不可重复资源的验重，比如像客户资源手机号码不可重复\n+ **创建/合并Entity（create/merge）**： 将资源存储进数据库的第一步肯定是先要创建实体并把入参赋值进实体，或者修改资源时需要将入参合并到现有实体中\n+ **准备Entity数据（prepare）**: 将添加资源的入参填入Entity\n+ **保存/删除Entity（save/remove）**: 将资源数据持久化进数据库\n+ **后置处理（after）**： 在资源添加完成后触发其它相关操作，比如在添加完客户资源后，要进行一系列的客户相关数据初始化工作或者发送邮件\n\n### 使用Resource Manager\n\n目前resource-manager框架有两套实现，分别基于spring-data-jpa和spring-data-mongodb\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.developframework\u003c/groupId\u003e\n    \u003cartifactId\u003eresource-manager-jpa\u003c/artifactId\u003e\n    \u003cversion\u003e${resource-manager.version}\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.developframework\u003c/groupId\u003e\n    \u003cartifactId\u003eresource-manager-mongodb\u003c/artifactId\u003e\n    \u003cversion\u003e${resource-manager.version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n#### ResourceManager的可用方法\n\nResourceManager接口涵盖了业务开发时经常需要使用的基础方法：\n\n| 方法                                      | 说明                                                         |\n| ----------------------------------------- | ------------------------------------------------------------ |\n| boolean existsById(ID id)                 | 根据ID查询资源是否存在                                       |\n| void assertExistsById(ID id)              | 根据ID断言资源存在，如果不存在则会报ResourceNotExistException |\n| Optional\u003cENTITY\u003e findOneById(ID id)       | 单查询                                                       |\n| ENTITY findOneByIdRequired(ID id)         | 单查询 不存在则抛出ResourceNotExistException                 |\n| Optional\u003cENTITY\u003e add(Object dto)          | 调用Add操作添加资源                                          |\n| boolean modifyById(ID id, Object dto)     | 根据ID调用Modify操作修改资源                                 |\n| boolean modify(Object dto, ENTITY entity) | 调用Modify操作修改资源                                       |\n| Optional\u003cENTITY\u003e removeById(ID id)        | 根据ID调用Remove操作删除资源                                 |\n| boolean remove(ENTITY entity)             | 调用Remove操作删除资源                                       |\n| List\u003cENTITY\u003e listForIds(ID[] ids)         | 根据ID数组查询资源列表                                       |\n\n如果是基于spring-data系列的持久层框架的话，还有额外的查询列表和分页方法\n\n| 方法                                                 | 说明                               |\n| ---------------------------------------------------- | ---------------------------------- |\n| List\u003cENTITY\u003e list(SEARCH search)                     | 根据Search条件查询列表             |\n| List\u003cENTITY\u003e list(Sort sort, SEARCH search)          | 根据Search条件查询列表并按Sort排序 |\n| Page\u003cENTITY\u003e pager(Pageable pageable, SEARCH search) | 根据Pageable和Search条件分页查询   |\n\n#### resource-manager-jpa分支\n\n```java\n@Service\npublic class UserManager extends JpaResourceManager\u003cUserPO, Integer, UserJpaRepository\u003e {\n\n    public UserManager(UserJpaRepository repository) {\n        super(repository, UserPO.class, \"user\");\n    }\n\n}\n```\n\n继承JpaResourceManager，实现方法需要给父类提供两个参数，实体类型和资源的名称\n\n其中内置注入EntityManager，可以方便随时编写复杂查询\n\n#### resource-manager-mongodb分支\n\n```java\n@Service\npublic class MemberManager extends MongoResourceManager\u003cMemberDOC, String, MemberMongoRepository\u003e {\n\n    public MemberManager(MemberMongoRepository repository) {\n        super(repository, MemberDOC.class, \"member\");\n    }\n\n}\n```\n\nmongodb的manager也差不多，继承自MongoResourceManager\n\n其中内置注入MongoOperations，可以方便随时编写复杂查询\n\n#### resource operate\n\nresource manager内置以下操作流程扩展：\n\n+ **AddResourceOperate** 添加资源操作\n+ **AddUniqueResourceOperate** 添加唯一资源操作\n+ **ModifyResourceOperate** 修改资源操作\n+ **ModifyUniqueResourceOperate** 修改唯一资源操作\n+ **RemoveResourceOperate** 删除资源操作\n+ **SearchResourceOperate** 查询资源操作\n\nAdd操作的扩展步骤：\n\n+ **boolean before(ENTITY dto)** 前置判断，为true时继续下面的流程\n+ **ENTITY create(DTO dto)** 创建\n+ **void prepare(DTO dto, ENTITY entity)** 准备\n+ **void after(DTO dto, ENTITY entity)** 后置处理\n\nAddUnique操作的扩展步骤在Add的基础上多了一个：\n\n+ **AddCheckExistsLogic\u003cENTITY, DTO, ID\u003e configureCheckExistsLogic()** 配置检查存在逻辑，需要实现AddCheckExistsLogic接口描述如何判定资源已存在\n\nModify操作的扩展步骤：\n\n- **boolean before(DTO dto, ENTITY entity)** 前置判断，为true时继续下面的流程\n- **void merge(DTO dto, ENTITY entity)** 合并\n- **void prepare(DTO dto, ENTITY entity)** 准备\n- **void after(DTO dto, ENTITY entity)** 后置处理\n\nModifyUnique操作的扩展步骤在Modify的基础上多了一个：\n\n- **ModifyCheckExistsLogic\u003cENTITY, DTO, ID\u003e configureCheckExistsLogic()** 配置检查存在逻辑，需要实现ModifyCheckExistsLogic接口描述如何判定资源已存在\n\nRemove操作的扩展步骤：\n\n+ **boolean before(ENTITY entity)** 前置判断，为true时继续下面的流程\n+ **void after(ENTITY entity)** 后置处理\n\nSearch操作的扩展步骤：\n\n- **void after(ENTITY entity)** 后置处理\n\n一份完整的Manager代码：\n\n```java\n@Service\npublic class UserManager extends JpaResourceManager\u003cUserPO, Integer, UserJpaRepository\u003e {\n\n    public UserManager(UserJpaRepository repository) {\n        super(repository, UserPO.class, \"user\");\n    }\n\n    private AddUniqueResourceOperate\u003cUserPO, UserDTO, Integer\u003e addResourceOperate() {\n        return new AddUniqueResourceOperate\u003c\u003e(UserDTO.class, UserMapper.class) {\n\n            @Override\n            protected boolean before(UserDTO dto) {\n                // 这里用于判断是否可以执行添加\n                return true;\n            }\n\n            // 如果是唯一资源将需要实现该方法\n            @Override\n            public AddCheckExistsLogic\u003cUserPO, UserDTO, Integer\u003e configureCheckExistsLogic() {\n                // 根据name验重\n                return dto -\u003e repository.existsByName(dto.getName());\n            }\n\n            // 此方法可以省略，内部就是这么执行的，如果没有定义mapper则会new一个ENTITY对象\n            @Override\n            protected UserPO create(UserDTO dto) {\n                // 将DTO的数据赋值到ENTITY\n                return mapper.toENTITY(dto);\n            }\n\n            @Override\n            protected void prepare(UserDTO dto, UserPO entity) {\n                // 到这里entity其实已经有了来自DTO的值，这一步主要处理其它准备数据的逻辑\n            }\n\n            @Override\n            protected void after(UserDTO dto, UserPO entity) {\n                // 持久化ENTITY完成后，后续的业务逻辑\n            }\n        };\n    }\n\n    private ModifyUniqueResourceOperate\u003cUserPO, UserDTO, Integer\u003e modifyResourceOperate() {\n        return new ModifyUniqueResourceOperate\u003c\u003e(UserDTO.class, UserMapper.class) {\n\n            @Override\n            protected boolean before(UserDTO dto, UserPO entity) {\n                // 这里用于判断是否可以执行修改\n                return true;\n            }\n\n            @Override\n            public ModifyCheckExistsLogic\u003cUserPO, UserDTO, Integer\u003e configureCheckExistsLogic() {\n                // 修改时需要判断当name值是一个新值时才需要去验重\n                return (dto, entity) -\u003e !entity.getName().equals(dto.getName()) \u0026\u0026 repository.existsByName(dto.getName());\n            }\n\n            // 此方法可以省略，内部就是这么执行的，如果没有定义mapper则不会合并数据\n            @Override\n            protected void merge(UserDTO dto, UserPO entity) {\n                // 将DTO的数据合并到原ENTITY对象上\n                mapper.toENTITY(dto, entity);\n            }\n\n            @Override\n            protected void prepare(UserDTO dto, UserPO entity) {\n                // 准备其它数据\n            }\n\n            @Override\n            protected void after(UserDTO dto, UserPO entity) {\n                // 持久化ENTITY完成后，后续的业务逻辑\n            }\n        };\n    }\n\n    private RemoveResourceOperate\u003cUserPO, Integer\u003e removeResourceOperate() {\n        return new RemoveResourceOperate\u003c\u003e() {\n\n            @Override\n            protected boolean before(UserPO entity) {\n                // 这里用于判断是否可以执行删除\n                return true;\n            }\n\n            @Override\n            protected void after(UserPO entity) {\n                // 删除ENTITY后，后续的业务逻辑\n            }\n        };\n    }\n\n    private SearchResourceOperate\u003cUserPO, Integer\u003e searchResourceOperate() {\n        return new SearchResourceOperate\u003c\u003e() {\n\n            @Override\n            public void after(UserPO entity) {\n                // 查询ENTITY后，后续的业务逻辑，通常用于批量执行ENTITY内的某个方法\n            }\n        };\n    }\n}\n```\n\n以上扩展方法都不是必须实现的，按照具体的业务逻辑来实现。\n\nAdd和Modify的操作可以根据不同的DTO定义多个不同的操作实现\n\n##### resource operate的注册\n\n资源操作的注册也是非常简单，只需要在Manager类里申明方法就可以自动注册了，该方法的特征是：\n\n+ 必须是无参的方法\n+ 返回值为ResourceOperate子类，所有的资源操作都继承与ResourceOperate\n+ 权限修饰符随意，一般为了不在外部使用申明为private，在方法上标注@SuppressWarnings(\"unused\")关闭编辑器的警告\n\n在应用启动时将会输出注册日志\n\n```\n[ 2019-09-27 16:44:12.883 INFO ] - c.g.d.r.ResourceOperateRegistry - register UserDTO for UserPO add operate\n[ 2019-09-27 16:44:12.883 INFO ] - c.g.d.r.ResourceOperateRegistry - register UserPO search operate\n[ 2019-09-27 16:44:12.884 INFO ] - c.g.d.r.ResourceOperateRegistry - register UserDTO for UserPO modify operate\n[ 2019-09-27 16:44:12.884 INFO ] - c.g.d.r.ResourceOperateRegistry - register UserPO remove operate\n```\n\nAdd和Modify的操作可以根据不同的DTO注册多个不同的操作实现\n\n```java\nprivate AddResourceOperate\u003cUserPO, UserDTOForAdd1, Integer\u003e addResourceOperate1() {\n    return new AddResourceOperate\u003c\u003e(UserDTOForAdd1.class, UserDTOForAdd1Mapper.class) {\n\n    };\n}\n\nprivate AddResourceOperate\u003cUserPO, UserDTOForAdd2, Integer\u003e addResourceOperate2() {\n    return new AddResourceOperate\u003c\u003e(UserDTOForAdd2.class, UserDTOForAdd2Mapper.class) {\n\n    };\n}\n```\n\n当Manager没有注册对应DTO的操作方法时将会报错\n\n```\ncom.github.developframework.resource.exception.UnRegisterOperateException: Manager \"xxx.UserManager\" is not register add resource operate for DTO \"xxx.UserDTO\"\n```\n\n使用`@DefaultRegister`注解可以帮你自动注册不需要自定义的操作实现\n\n```java\n@Service\n@DefaultRegister(dtoClass = UserDTO.class, mapperClass = UserMapper.class)\npublic class UserManager extends JpaResourceManager\u003cUserPO, Integer, UserJpaRepository\u003e {\n\n    public UserManager(UserJpaRepository repository) {\n        super(repository, UserPO.class, \"user\");\n    }\n}\n```\n\n`@DefaultRegister`注解会根据所填DTO和Mapper自动注册对应的Add、Modify、Remove操作，不会覆盖自定义实现的操作\n\n#### 资源查询\n\n使用统一接口`Search\u003cENTITY\u003e` 描述查询方法\n\nSearch接口根据数据库分出两个子类`JpaSearch\u003cPO\u003e`和`MongoSearch\u003cDOC\u003e`\n\n```java\npublic class UserSearch implements JpaSearch\u003cUserPO\u003e {\n    \n    private String name;\n    \n    private Integer age;\n    \n    @Override\n    public Specification\u003cUserPO\u003e toSpecification() {\n        return (root, criteriaQuery, criteriaBuilder) -\u003e {\n            List\u003cPredicate\u003e predicates = new LinkedList\u003c\u003e();\n            if(StringUtils.isNotEmpty(name)) {\n                predicates.add(\n                        criteriaBuilder.like(root.get(\"name\"), name + \"%\")\n                );\n            }\n            if(age != null) {\n                predicates.add(\n                        criteriaBuilder.equal(root.get(\"age\"), age)\n                );\n            }\n            criteriaQuery.where(predicates.toArray(Predicate[]::new));\n            return null;\n        };\n    }\n}\n```\n\nJpaSearch需要实现如何得到Specification对象\n\n```java\npublic class MemberSearch implements MongoSearch\u003cMemberDOC\u003e {\n\n    private String name;\n\n    private Integer age;\n\n    @Override\n    public Query toQuery() {\n        Criteria criteria = new Criteria();\n        if(StringUtils.isNotEmpty(name)) {\n            criteria.and(\"name\").regex(\"^\" + name);\n        }\n        if(age != null) {\n            criteria.and(\"age\").is(age);\n        }\n        return Query.query(criteria);\n    }\n}\n```\n\nMongoSearch需要实现如何得到Query对象\n\nSearch可以作为springmvc的controller参数，自动从请求中装填参数值\n\n```java\n@TemplateId(\"user-pager\")\n@GetMapping\npublic KiteResponse findUserPager(Pageable pageable, UserSearch search) {\n    Page\u003cUserPO\u003e page = resourceManager.pager(pageable, search);\n    return KiteAssist.responseForPage(page);\n}\n```\n\n#### 高级\n\n##### 简化验重逻辑\n\n比如以下只按多字段联合验重：\n\n```java\n@Override\npublic AddCheckExistsLogic\u003cUserPO, UserDTO, Integer\u003e configureCheckExistsLogic() {\n    return dto -\u003e repository.existsByNameAndMobile(dto.getName(), dto.getMobile());\n}\n\n@Override\npublic ModifyCheckExistsLogic\u003cUserPO, UserDTO, Integer\u003e configureCheckExistsLogic() {\n    return (dto, entity) -\u003e !entity.getName().equals(dto.getName()) \n        \u0026\u0026 \t!entity.getMobile().equals(dto.getMobile()) \n        \u0026\u0026 repository.existsByNameAndMobile(dto.getName(), dto.getMobile());\n}\n```\n\n这样需要定义repository的方法，字段越多越能体现复杂性，尤其是modify时\n\n可以使用byField方法替代：\n\n```java\n@Override\npublic AddCheckExistsLogic\u003cUserPO, UserDTO, Integer\u003e configureCheckExistsLogic() {\n    return byField(\"name\", \"mobile\");\n}\n\n@Override\npublic ModifyCheckExistsLogic\u003cUserPO, UserDTO, Integer\u003e configureCheckExistsLogic() {\n    return byField(\"name\", \"mobile\");\n}\n```\n\nbyField帮你实现了以上的逻辑回了一个验重接口的实现类，modify时内部会自动判断是否不等\n\n##### 简化查询条件拼接\n\n以”资源查询“章节的代码为例，多字段查询条件中每个字段都需要一个if语句来判断是否需要该字段查询，代码非常的啰嗦。可以使用Builder模式简化：\n\n```java\n@Override\npublic Specification\u003cUserPO\u003e toSpecification() {\n    return (root, criteriaQuery, criteriaBuilder) -\u003e {\n        new PredicateBuilder\u003c\u003e(root, criteriaBuilder)\n            .startWith(\"name\", name)\n            .equal(\"age\", age)\n            .where(criteriaQuery);\n        return null;\n    };\n}\n```\n\n```java\n@Override\npublic Query toQuery() {\n    return new QueryBuilder()\n        .startWith(\"name\", name)\n        .equal(\"age\", age)\n        .build();\n}\n```\n\nPredicateBuilder和QueryBuilder具有丰富的方法来简化查询条件的拼接\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevelopframework%2Fresource-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevelopframework%2Fresource-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevelopframework%2Fresource-manager/lists"}