# 流石代码生成 **Repository Path**: changkang/flowstone-code-generator ## Basic Information - **Project Name**: 流石代码生成 - **Description**: idea代码生成插件,基于模板配置的方式生成CRUD代码、Liquibase脚本及前端页面 - **Primary Language**: Unknown - **License**: AGPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 2 - **Created**: 2023-12-12 - **Last Updated**: 2025-10-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 流石代码生成Idea插件;可以基于定义好的实体类及代码生成模板一键生成CRUD代码、前端页面、Liquibase脚本。 默认情况下,基于本文描述的模板,生成的是基于MyBatisPlus的CRUD代码,你也可以根据自己的习惯或者需要修改对应的模板,使其支持比如JPA或MyBatis的CRUD代码生成; # 1. 插件安装 插件下载:[1.0.0版本](https://gitee.com/changkang/qi-code-generator/releases/tag/v1.0.0) 安装:下载对应Jar包后,通过idea的插件来安装本地插件,安装完成后重启; # 2. 使用示例 ## 2.1 定义模板 需要在项目resources/code-generator下定义以下配置文件: ### 2.1.1 config.yaml 总的代码生成配置,示例如下: ```yaml # 类生成配置 # 基础包 #basePackage: com.liuqi.base # 表信息注解,只有被这个注解的类才处理;可以是TableName或者是Spring本身的Table tableAnnotation: com.baomidou.mybatisplus.annotation.TableName # 注释注解,用于生成类的注释 commentAnnotation: com.liuqi.common.annotations.Comment # 是否生成liquibase,如果为true,那么会根据tableAnnotation中的表名生成建表语句,并添加在liquibase/master.xml中;(默认) withLiquibase: true # withLiquibase为true时生效;liquibase的生成语句保存文件,不配置则默认是liquibase/master.xml liquibaseFile: liquibase/master.xml # 前端界面配置模板 pageTemplate: page # 需要生成的类列表,每个类列表需要对应一个同名的yaml配置文件 classes: - dto - addReq - updateReq - query - mapper - service - serviceImpl - controller ``` 其中Comment类的定义如下: ```java package com.liuqi.common.annotations; import org.springframework.core.annotation.AliasFor; import java.lang.annotation.*; /** * 注释注解 */ @Target({ElementType.TYPE, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Comment { String value() default ""; @AliasFor("value") String name() default ""; } ``` 你也可以修改成自己的Comment类,但需要注意的是使用value来存储注释内容;这些注释会作为表名注释或者对应的字段注释 在config.yaml中定义的classes即是我们需要生成的类清单,每个类需要对应一个模板文件;用户可以根据需要增加或者删除对应的类; 以上类中,默认包括了controller/service/serviceImpl/mapper,以及四个实体类: - dto:数据实体,与Entity类字段基本一致;返回前端页面使用; - addReq: 新增时的前端请求对象 - updateReq: 修改时的请求对象 - query: 前端查询对象 ### 2.1.2 控制器模板controller.yaml 示例如下: ```yaml name: $T$Controller dir: web comment: "控制器" imports: - $T$AddReq - $T$UpdateReq - $T$DTO - $T$Query - $T$Service - io.swagger.v3.oas.annotations.Operation - io.swagger.v3.oas.annotations.tags.Tag - lombok.extern.slf4j.Slf4j - org.springframework.beans.BeanUtils - org.springframework.beans.factory.annotation.Autowired - org.springframework.web.bind.annotation.RequestMapping - org.springframework.web.bind.annotation.GetMapping - org.springframework.web.bind.annotation.PostMapping - org.springframework.web.bind.annotation.PutMapping - org.springframework.web.bind.annotation.DeleteMapping - org.springframework.web.bind.annotation.RequestBody - org.springframework.web.bind.annotation.PathVariable - org.springframework.web.bind.annotation.RestController - org.springframework.validation.annotation.Validated - com.baomidou.mybatisplus.core.metadata.IPage - com.liuqi.common.base.bean.query.DynamicQuery - java.util.List template: "@RestController @RequestMapping(\"/base/$PATH$\") @Slf4j @Tag(name = \"$COMMENT$控制器\") public class $T$Controller { @Autowired private $T$Service service; @PostMapping(\"add\") @Operation(summary = \"新增\") public void add(@RequestBody @Validated $T$AddReq req) { $T$DTO dto = new $T$DTO(); BeanUtils.copyProperties(req, dto); service.insert(dto); } @PutMapping(\"update\") @Operation(summary = \"更新\") public void update(@RequestBody @Validated $T$UpdateReq req) { $T$DTO dto = new $T$DTO(); BeanUtils.copyProperties(req, dto); service.update(dto); } @DeleteMapping(\"delete/{id}\") @Operation(summary = \"删除\") public void delete(@PathVariable(\"id\") String id) { service.delete(id); } @GetMapping(\"detail/{id}\") @Operation(summary = \"根据id查找记录\") public $T$DTO findById(@PathVariable(\"id\") String id) { return service.findById(id).orElse(null); } @PostMapping(\"page-query\") @Operation(summary = \"查询-分页\") public IPage<$T$DTO> pageQuery(@RequestBody $T$Query query) { return service.pageQuery(query); } @PostMapping(\"filter\") @Operation(summary = \"查询-动态\") public IPage<$T$DTO> pageQuery(@RequestBody DynamicQuery query) { return service.dynamicQuery(query); } @PostMapping(\"query\") @Operation(summary = \"查询-不分页\") public List<$T$DTO> query(@RequestBody $T$Query query) { return service.query(query); } }" ``` 包括CRUD的基本接口,及一个动态查询的接口; 里面$$这种形式的是代码生成变量,包括: - $T$:实体类名称,比如定义的Entity为TestEntity,那么$T$的值即是Test - $PATH$:实体类路径,根据名称驼峰转换成-而成,比如TestAEntity,那么$PATH$值为test-a - $COMMENT$: 实体类的Comment注释值 ### 2.1.3 service.yaml service示例如下所示: ```yaml name: $T$Service dir: service comment: "服务接口" imports: - $T$DTO - $T$Query - com.liuqi.common.base.service.BaseService template: "public interface $T$Service extends BaseService<$T$DTO, $T$Query> { }" ``` 其中使用了BaseService这个接口,其实现如下所示:(你也可以根据自己需要在模板中直接写对应的方法或者继承自己的接口) ```java package com.liuqi.common.base.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.liuqi.common.base.bean.dto.BaseDTO; import com.liuqi.common.base.bean.query.DynamicQuery; import com.liuqi.common.base.domain.entity.BaseEntity; import com.liuqi.common.base.bean.query.BaseQuery; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; public interface BaseService { D insert(D dto); void insert(List dtos); void update(D dto); List query(Q q); long count(Q q); IPage pageQuery(Q q); void delete(String id); void deletePhysical(String id); void delete(Collection ids); void deletePhysical(Collection ids); /** * 动态查询 * * @param query 查询对象 * @return 查询结果 */ IPage dynamicQuery(DynamicQuery query); /** * 查询单个数据 * * @param q 查询对象 * @return 查询到的记录 */ default Optional findOne(Q q) { return this.query(q).stream().findAny(); } /** * 根据id查找记录 * * @param id id * @return id对应的记录 */ Optional findById(String id); /** * 根据id批量查询记录 * * @param ids id列表 * @return id列表对应的记录 */ List findByIds(List ids); /** * 查找所有记录 */ List findAll(); } ``` ### 2.1.4 serviceImpl.yaml ```yaml name: $T$ServiceImpl dir: service/impl comment: "服务实现" imports: - $T$Entity - $T$DTO - $T$Query - $T$Mapper - $T$Service - org.springframework.beans.BeanUtils - org.springframework.stereotype.Service - com.liuqi.common.base.service.AbstractBaseService - com.baomidou.mybatisplus.core.conditions.query.QueryWrapper - org.apache.commons.lang3.StringUtils template: "@Service public class $T$ServiceImpl extends AbstractBaseService<$T$Entity, $T$DTO, $T$Mapper, $T$Query> implements $T$Service { @Override public $T$DTO toDTO($T$Entity entity) { $T$DTO dto = new $T$DTO(); BeanUtils.copyProperties(entity, dto); return dto; } @Override public $T$Entity toEntity($T$DTO dto) { $T$Entity entity = new $T$Entity(); BeanUtils.copyProperties(dto, entity); return entity; } @Override protected QueryWrapper<$T$Entity> queryToWrapper($T$Query query) { return this.createQueryWrapper() \n.eq(StringUtils.isNotBlank(query.getId()), \"id\", query.getId()) \n.in(null != query.getIds(), \"id\", query.getIds()) \n.eq(\"deleted\", false) \n.orderByDesc(\"create_time\"); } }" ``` ### 2.1.5 mapper.yaml ```yaml name: $T$Mapper dir: domain/mapper comment: "数据库操作服务" imports: - $T$Entity template: "import com.liuqi.common.base.domain.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; @Mapper public interface $T$Mapper extends BaseMapper<$T$Entity> { }" ``` ### 2.1.6 dto.yaml ```yaml name: $T$DTO dir: bean/dto comment: "数据实体" like: $T$Entity imports: - com.liuqi.common.base.bean.dto.BaseDTO - lombok.Data template: "@Data public class $T$DTO extends BaseDTO{}" ``` ### 2.1.7 query.yaml ```yaml name: $T$Query dir: bean/query comment: "查询对象" imports: - com.liuqi.common.base.bean.query.BaseQuery - lombok.Data template: "@Data public class $T$Query extends BaseQuery{}" ``` 其中BaseQuery定义如下: ```java package com.liuqi.common.base.bean.query; import lombok.Data; import java.util.List; @Data public class BaseQuery { private String id; private List ids; private Long pageSize; private Long pageNo; } ``` ### 2.1.8 addReq.yaml ```yaml name: $T$AddReq dir: bean/req comment: "新增对象" like: $T$Entity imports: - lombok.Data template: "@Data public class $T$AddReq {}" ``` ### 2.1.9 updateReq.yaml ```yaml name: $T$UpdateReq dir: bean/req comment: "更新对象" like: $T$Entity imports: - lombok.Data template: "@Data public class $T$UpdateReq { private String id; }" ``` ### 2.1.10 页面模板page.yaml ```yaml dir: vue template: ' ' ``` 页面模板基于封装好的entity-manager组件进行,你也可以根据自己需要进行修改; ## 2.2 定义实体类 ```java package com.liuqi.dua.domain.entity; import com.baomidou.mybatisplus.annotation.TableName; import com.liuqi.common.annotations.Comment; import com.liuqi.common.base.domain.entity.BaseEntity; import lombok.Data; @Data @TableName("d_api") @Comment("接口") public class ApiEntity extends BaseEntity { private String content; private String name; private String remark; private String path; private String method; private String typeId; } ``` 注意包名最少需要三级,生成代码目录如下图所示: - *.*.domain.entity.ApiEntity - *.*.web - *.*.service - *.*.service.impl - *.*.bean.dto - *.*.bean.query - *.*.bean.req BaseEntity的定义如下所示: ```java package com.liuqi.common.base.domain.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.liuqi.common.annotations.Comment; import lombok.Data; import org.springframework.data.annotation.Id; import java.time.LocalDateTime; @Data public class BaseEntity { @Id @TableId(type = IdType.ASSIGN_ID) private String id; @Comment("租户编号") private String tenantId; @Comment("创建用户") private String createUser; @Comment("创建时间") private LocalDateTime createTime; @Comment("更新用户") private String updateUser; @Comment("更新时间") private LocalDateTime updateTime; @Comment("是否删除") private Boolean deleted; } ``` ## 2.3 代码生成 打开定义的实体类,通过ALT+E快捷键,或者点击菜单“Tools-> Code Generator”,来进行代码生成; 注意如果代码已经存在,不会进行覆盖,如需要重新生成,需要手动删除对应代码; 另外liquibase脚本会生成在resources/liquibase目录的master文件中,如果重复生成,对应语句会重复,暂未处理,需要手工处理一下; # 3. 说明 可以看到以上示例中,模板文件使用了一些Base类,实际上完全可以不需要这些Base类,来按自己的习惯定义对应的模板。但目前由于未处理生成mapper.xml的这种场景,因此如果想要直接使用MyBatis,暂时只能手动编写对应的Mapper.xml文件, 后续版本将会覆盖这种场景;