{"id":13607927,"url":"https://github.com/gnanquanmama/tropical-fish","last_synced_at":"2025-08-20T06:33:27.049Z","repository":{"id":37116579,"uuid":"160644178","full_name":"gnanquanmama/tropical-fish","owner":"gnanquanmama","description":"Pragmatic 风格的 Java EE 后端开发脚手架，开箱即用。基于 SpringBoot，技术选型采用主流的框架（Mybatis-Plus，Redisson，Xxl-job，Swagger）。项目特点：自定义查询语法, 可以自由组装查询条件查询数据，配合代码生成模块，提高研发效率；自定义 service 方法级别的文档生成规则，在业务方法增加必要的注解，可生成方法调用树，快速把握复杂代码业务逻辑。","archived":false,"fork":false,"pushed_at":"2024-04-07T10:22:42.000Z","size":466,"stargazers_count":159,"open_issues_count":2,"forks_count":21,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-12-06T08:23:18.582Z","etag":null,"topics":["dubbo","generator","mybatis-plus","redisson","springboot","swagger","xxl-job","zipkin"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gnanquanmama.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}},"created_at":"2018-12-06T08:35:21.000Z","updated_at":"2024-11-10T08:06:33.000Z","dependencies_parsed_at":"2024-04-07T10:42:36.242Z","dependency_job_id":null,"html_url":"https://github.com/gnanquanmama/tropical-fish","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnanquanmama%2Ftropical-fish","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnanquanmama%2Ftropical-fish/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnanquanmama%2Ftropical-fish/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnanquanmama%2Ftropical-fish/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gnanquanmama","download_url":"https://codeload.github.com/gnanquanmama/tropical-fish/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230400616,"owners_count":18219831,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["dubbo","generator","mybatis-plus","redisson","springboot","swagger","xxl-job","zipkin"],"created_at":"2024-08-01T19:01:22.888Z","updated_at":"2024-12-19T08:08:50.307Z","avatar_url":"https://github.com/gnanquanmama.png","language":"Java","funding_links":[],"categories":["Projects Using MyBatis-Plus"],"sub_categories":["Tutorials"],"readme":"# Tropical Fish\n\nPragmatic 风格的 Java EE 后端开发脚手架。 基于 SpringBoot，技术选型采用主流的技术框架（Mybatis-Plus，Redisson，Xxl-job，Swagger）。开箱即用，提高研发效能。\n\n多家公司线上产品使用了该脚手架。国内某知名日化企业，已把该脚手架作为基础脚手架，支撑数字化产品的研发。\n\n### 项目特点\n1. 自定义 DSL 查询语法。配合 generator 模块，研发人员定义表结构之后，逆向生成代码，单表情况下的CRUD，包括分页查询，可不用写一行代码，就完成开发任务。减轻后端研发人员开发压力，提高研发效率。分页查询语法 在 **自定义 DSL 查询语法** 有做详细的说明。\n\n2. 自研 Excel 报表导入导出工具。 配合自定义查询语法，让导出 Excel 功能的开发和普通条件查询一样简单。高效开发报表导出功能。使用方法参照：BaseUserController.exportByExcel 。\n\n3. 自研 分布式业务编码 生成服务。业务编码可批量生成。生成和使用过程，都是线程安全。 详细参照方法：ActivityOrderBizCodeGenerator.generateNextCode ；generateBizCodeList 。\n\n4. 自定义缓存 @RCacheable 注解，实现分布式缓存。支持 Spel语法，可直接指定 expireTime 。  \n   示例：@RCacheable(key = \"dmt::miniprogram::token\", secKey = \"#token\", ttl = 1, timeUnit = TimeUnit.DAYS)  \n\n5. 自定义注解 @LoginRequired 注解，可以自动装配当前操作人实体。该注解的意义在于，消除在每个 controller 方法需要手动获取当前操作人的重复性的代码。\n\n6. 自定义 service 方法级别文档生成规则和实现。某种程度上缓解研发人员不爱写文档，又抱怨接手新项目没有文档的尴尬处境。 在**方法调用树示例** 有相应的 json 视图可以看到调用树的数据结构。\n\n   \u003e 参考 \u003c从码农到工匠\u003e 控制代码复杂度的做法。复杂的业务的流程可拆分为多个阶段，每个阶段下有多个子步骤。  自定义注解，过程 @Process， 阶段 @Phase，步骤 @Step。在业务方法的阶段和步骤上加上相应的注解，即可根据请求返回的 TraceId 获取 service 级别的方法调用树。  \n\n    \u003e 研发人员需要按照定义规则流水线化，组件化设计代码，再加上必要的注解，runtime 状态下，就可以得到一颗拥有层次结构的方法调用树，得到复杂业务逻辑的主干架构。每个树结点有 Java 类方法，行数等信息，所见即所得。  \n\n#### 自定义 DSL 查询语法   \n\n\u003e 查询条件语法\n\u003e ```json\n\u003e {\n\u003e    \"current\":  \"页码\",\n\u003e    \"size\":  \"页数\",\n\u003e    \"modelField.operation\":\"搜索条件\",\n\u003e    \"orderByDesc\":\"modelField\",\n\u003e    \"searchKeyword\": \"关键词\"\n\u003e }\n\u003e ```\n\n\u003e 示例\n\n\u003e ```json\n\u003e {\n\u003e     \"current\":1,\n\u003e     \"size\":10,\n\u003e     \"userName.like\":\"github\",\n\u003e     \"orderStatus.in\":[1,3,4],\n\u003e     \"createTime.gt\":1581392098000,\n\u003e     \"phone.isNotNull\": \"\",\n\u003e     \"orderByDesc\": \"createTime\",\n\u003e     \"searchKeyword\": \"githu\"\n\u003e }\n\u003e ```\n\n\u003e 查询条件关键字\n\n|    KEYWORD    |                             DESC                             |\n| :-----------: | :----------------------------------------------------------: |\n|  modelField   |                           模型字段                           |\n|       .       |                            分隔符                            |\n|   operation   | 不传 .operation，则默认为 eq。如果是模糊查询，支持字段加注解 @Like |\n|  orderByDesc  |                             递减                             |\n|  orderByAsc   |                             递增                             |\n| searchKeyword |          关键词查询字段，搜索字段需要加上 @Keyword           |\n\n\u003eoperation 关键字列表\n\n| operation |       DESC        |      语义       |\n| :-------: | :---------------: | :-------------: |\n|    eq     |       等于        |        =        |\n|    ne     |      不等于       |       \u003c\u003e        |\n|    gt     |       大于        |        \u003e        |\n|    ge     |     大于等于      |       \u003e=        |\n|    lt     |       小于        |        \u003c        |\n|    le     |     小于等于      |       \u003c=        |\n|   like    |     模糊匹配      |    '%value%'    |\n| likeLeft  | 以 value 结尾匹配 |    '%value'     |\n| likeRight | 以 value 开头匹配 |    'value%'     |\n|    in     |        in         |       in        |\n|  between  |      闭区间       | between s and e |\n|  isNull   |      is null      |      为空       |\n| isNotNull |    is not null    |      非空       |\n\n\n\n#### 方法调用树示例\n\n\u003e ```json\n\u003e {\n\u003e     \"id\":0,\n\u003e     \"parentId\":-1,\n\u003e     \"lineNum\":80,\n\u003e     \"method\":\"UserAuthController.register\",\n\u003e     \"event\":\"小程序用户注册\",\n\u003e     \"lifeCycle\":\"process\",\n\u003e     \"sync\":true,\n\u003e     \"childList\":[\n\u003e         {\n\u003e             \"id\":7,\n\u003e             \"parentId\":0,\n\u003e             \"lineNum\":46,\n\u003e             \"method\":\"WechatServiceImpl.getUserInfoByCode\",\n\u003e             \"event\":\"根据jscode获取用户信息\",\n\u003e             \"lifeCycle\":\"phase\",\n\u003e             \"sync\":true\n\u003e         },\n\u003e         {\n\u003e             \"id\":8,\n\u003e             \"parentId\":0,\n\u003e             \"lineNum\":25,\n\u003e             \"method\":\"BaseUserServiceImpl.getUserByOpenId\",\n\u003e             \"event\":\"根据openId获取用户信息\",\n\u003e             \"lifeCycle\":\"phase\",\n\u003e             \"sync\":true\n\u003e         },\n\u003e         {\n\u003e             \"id\":9,\n\u003e             \"parentId\":0,\n\u003e             \"lineNum\":115,\n\u003e             \"method\":\"WechatAuthServiceImpl.invalidUserToken\",\n\u003e             \"event\":\"失效用户token\",\n\u003e             \"lifeCycle\":\"phase\",\n\u003e             \"sync\":true\n\u003e         },\n\u003e         {\n\u003e             \"id\":10,\n\u003e             \"parentId\":0,\n\u003e             \"lineNum\":43,\n\u003e             \"method\":\"WechatAuthServiceImpl.register\",\n\u003e             \"event\":\"注册用户到DMT系统\",\n\u003e             \"lifeCycle\":\"phase\",\n\u003e             \"sync\":true,\n\u003e             \"childList\":[\n\u003e                 {\n\u003e                     \"id\":11,\n\u003e                     \"parentId\":10,\n\u003e                     \"lineNum\":27,\n\u003e                     \"method\":\"BaseGenerateCodeServiceImpl.generateNextCode\",\n\u003e                     \"event\":\"生成用户编码\",\n\u003e                     \"lifeCycle\":\"step\",\n\u003e                     \"sync\":true\n\u003e                 }\n\u003e             ]\n\u003e         },\n\u003e         {\n\u003e             \"id\":12,\n\u003e             \"parentId\":0,\n\u003e             \"lineNum\":27,\n\u003e             \"method\":\"BaseUserTokenServiceImpl.saveNewToken\",\n\u003e             \"event\":\"保存新token\",\n\u003e             \"lifeCycle\":\"phase\",\n\u003e             \"sync\":true\n\u003e         }\n\u003e     ]\n\u003e }\n\u003e ```\n\u003e\n\u003e \n\u003e\n\u003e \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgnanquanmama%2Ftropical-fish","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgnanquanmama%2Ftropical-fish","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgnanquanmama%2Ftropical-fish/lists"}