代码基于SpringBoot3、Vue3、highlight实现自定义代码生成功能
SpringBoot3.x、MySQL8、MyBatisPlus3.5.x、velocity2.x、SpringSecurity6.x、Vue3、TypeScript、highlight
demo所需要的依赖及其对应版本号
pom
4.0.0 cn.molu mgzyf-api 2.4.1 Java 17 + SpringBoot3 + SpringSecurity6 org.springframework.boot spring-boot-starter-parent 3.1.5 17 17 UTF-8 5.8.15 8.0.28 1.2.16 3.5.3.1 1.5.3.Final 0.2.0 org.apache.velocity velocity-engine-core 2.3 org.projectlombok lombok provided org.projectlombok lombok-mapstruct-binding ${lombok-mapstruct-binding.version} provided cn.hutool hutool-all ${hutool.version} org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security org.apache.commons commons-pool2 mysql mysql-connector-java ${mysql.version} com.alibaba druid-spring-boot-starter ${druid.version} com.alibaba fastjson 2.0.40 com.baomidou mybatis-plus-boot-starter ${mybatis-plus.version} org.springframework.boot spring-boot-starter-validation org.springframework.boot spring-boot-configuration-processor true ${project.artifactId} org.springframework.boot spring-boot-maven-plugin
这里是最基础的MySQL的配置信息
application
server: port: 8989 spring: jackson: ## 默认序列化时间格式 date-format: yyyy-MM-dd HH:mm:ss ## 默认序列化时区 time-zone: GMT+8 datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver druid: master: url: jdbc:mysql://127.0.0.1:3306/test01?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=true username: xxx password: 123 driver-class-name: com.mysql.cj.jdbc.Driver initial-size: 15 min-idle: 15 max-active: 200 max-wait: 60000 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 validation-query: "" test-while-idle: true test-on-borrow: false test-on-return: false pool-prepared-statements: false connection-properties: false # 配置生成代码的数据库 cn: molu: generate: database: test01
这里是代码生成器的源码目录结构,下面会逐一展示这3个类
这里是根据我的项目需要,自定义的代码生成器模板,下面会以Service为例解释
提供数据到Vue页面的API接口,主要功能是将模板解析为代码返回给前台
import cn.molu.system.common.result.Result; import cn.molu.system.generate.mapper.ColumnDetailMapper; import cn.molu.system.generate.vo.ColumnDetailVo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.Cacheable; import org.springframework.web.bind.annotation.*; import java.io.IOException; import java.io.StringWriter; import java.util.List; import java.util.Map; import java.util.Properties; /** * @author 陌路 * @apiNote 数据库表细信息 * @date 2023/12/31 13:16 * @tool Created by IntelliJ IDEA */ @Slf4j @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/gen") public class ColumnDetailController { @Value("${cn.molu.generate.database}") private String database; // 这里是数据库的名字,我的数据库是 test01 private final ColumnDetailMapper columnDetailMapper; /** * 获取所有表信息数据 * * @return List*/ @GetMapping("/getAllTables") @Cacheable(value = "gen:allTableDetails", key = "#root.methodName") public Result > getAllTables() { List
columnDetailVoList = columnDetailMapper.getColumnDetailMapVo(database); return Result.success(columnDetailVoList); } /** * 获取所有表中字段信息数据 * * @param tableName 表名 * @return List */ @GetMapping("/getTableInfo/{tableName}") public Result getTableInfo(@PathVariable String tableName, @RequestParam(value = "delPrefix", required = false) String delPrefix, @RequestParam(value = "packageName", required = false) String packageName, @RequestParam(value = "type") String type ) { List columnDetailVoList = columnDetailMapper.getColumnDetailMapVoByTableName(database, tableName); try (StringWriter writer = new StringWriter()) { // 初始化Velocity引擎 Properties p = new Properties(); // 加载classpath目录下的vm文件 p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); // 定义字符集 p.setProperty(Velocity.INPUT_ENCODING, "UTF-8"); // 初始化Velocity引擎,指定配置Properties Velocity.init(p); // 获取模板 Template template = Velocity.getTemplate("vm/" + type + ".vm", "UTF-8"); ColumnDetailVo detailVo = new ColumnDetailVo(); Map map = detailVo.listToMap(columnDetailVoList, delPrefix); // 去除前缀 map.put("packageName", packageName); // 文件所在包 // 创建Velocity上下文 VelocityContext context = new VelocityContext(); // 设置模板中的变量 context.put("map", map); // 将模板与上下文数据进行合并 template.merge(context, writer); // 输出结果 String writerString = writer.toString(); return Result.success(writerString); } catch (IOException | ResourceNotFoundException | ParseErrorException | MethodInvocationException e) { log.error("报错了:" + e.getMessage(), e); } return Result.failed(); } }
查询数据库,获取表字段信息,以便后面生成代码使用
import cn.molu.system.generate.vo.ColumnDetailVo; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.List; /** * @author 陌路 * @apiNote 数据库表细信息 * @date 2023/12/31 13:14 * @tool Created by IntelliJ IDEA */ @Mapper public interface ColumnDetailMapper { /** * 获取所有表信息数据 * * @return List*/ public List getColumnDetailMapVo(@Param("database") String database); /** * 获取所有表中字段信息数据 * * @param tableName 表名 * @return List */ public List getColumnDetailMapVoByTableName(@Param("database") String database, @Param("tableName") String tableName); }
根据application中指定的数据库名,获取数据库中所有的表名以及表中的字段名
对应表中字段和字段信息的实体类
import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.ToString; import lombok.experimental.Accessors; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serial; import java.io.Serializable; import java.util.*; import java.util.concurrent.atomic.AtomicReference; /** * @author 陌路 * @apiNote 数据库表细信息 * @date 2023/12/31 13:21 * @tool Created by IntelliJ IDEA */ @Data @ToString @NoArgsConstructor @EqualsAndHashCode @Accessors(chain = true) @JsonInclude(value = JsonInclude.Include.NON_NULL, content = JsonInclude.Include.NON_EMPTY) public class ColumnDetailVo implements Serializable { @Serial private static final long serialVersionUID = 9196390045041955368L; // ====================查询所有表信息==================== /** * 表名 */ private String tableName; /** * 表名注释 */ private String tableComment; /** * 表数据引擎 */ private String engine; /** * 表字符集 */ private String tableCollation; /** * 表中数据条数 */ private String tableRows; /** * 表创建时间 */ @JsonFormat(pattern = "YYYY-MM-DD HH:mm:ss") @DateTimeFormat(pattern = "YYYY-MM-DD HH:mm:ss") private String createTime; // ====================查询指定表中的字段信息==================== /** * 数据库名 */ private String tableSchema; /** * 字段名 */ private String columnName; /** * 默认值 */ private String columnDefault; /** * 是否可为空:YES、NO */ private String isNullable; /** * 数据类型:int、varchar... */ private String dataType; /** * 字段类型:int、varchar(30)... */ private String columnType; /** * 是否主键:PRI */ private String columnKey; /** * 是否自增:auto_increment(自增) */ private String extra; /** * 字段注释 */ private String columnComment; /** * 是否主键 * * @param columnKey 字段键 * @return 是否主键 */ public boolean isPrimaryKey(String columnKey) { return StrUtil.equalsIgnoreCase(columnKey, "PRI"); } /** * 获取主键字段名 * * @param list 字段列表 * @return 主键字段名 */ public String getPrimaryKey(Listlist) { return Optional.ofNullable(list) .orElseGet(ArrayList::new) .stream() .filter(item -> isPrimaryKey(item.columnKey)) .findFirst() .orElseGet(ColumnDetailVo::new).columnName; } /** * 列表转Map * * @param list 列表 * @param replacePrefix 替换前缀 * @return Map */ public Map listToMap(List list, String replacePrefix) { if (Objects.isNull(list) || list.isEmpty()) return null; Map map = new HashMap<>(2); ColumnDetailVo detailVo = list.get(0); String voTableName = detailVo.getTableName().toLowerCase(); String subTableName = voTableName.replace(replacePrefix, ""); String className = toUpperFirst(subTableName); map.put("tableName", voTableName); // 表名 map.put("tableComment", detailVo.getTableComment()); // 表名注释 map.put("className", StrUtil.upperFirst(className)); // Java类名 map.put("subClassName", className); // Java类名 map.put("path", voTableName.replace("_", "/")); // 生成路径 map.put("prem", voTableName.replace("_", ":")); // 权限标识 map.put("currTime", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN)); // 日期时间 AtomicReference pk = new AtomicReference<>(); AtomicReference pkType = new AtomicReference<>(); AtomicReference getterPk = new AtomicReference<>(); AtomicReference pkColumn = new AtomicReference<>(); List
自定义的模板,通过模板生成所需要的代码
package $!{map.packageName}.service; import $!{map.packageName}.entity.$!{map.className}; import com.baomidou.mybatisplus.core.metadata.IPage; import $!{map.packageName}.params.$!{map.className}Params; import java.lang.*; /** * @apiNote $!{map.tableComment}($!{map.className})表服务接口 * @author 陌路 * @date $!{map.currTime} * @tool Created by IntelliJ IDEA */ public interface $!{map.className}Service /* extends IService<$!{map.className}> */{ /** * 通过ID查询单条数据 * * @author 陌路 * @date $!{map.currTime} * @param $!{map.pk} 主键 * @return $!{map.subClassName} 实例对象 */ $!{map.className} queryById($!{map.pkType} $!{map.pk}); /** * 分页查询 * * @author 陌路 * @date $!{map.currTime} * @param $!{map.subClassName}Params 筛选条件 * @return IPage<$!{map.className}> 查询结果 */ IPage<$!{map.className}> queryByPage($!{map.className}Params $!{map.subClassName}Params); /** * 新增数据 * * @author 陌路 * @date $!{map.currTime} * @param $!{map.subClassName} 实例对象 * @return $!{map.subClassName} 实例对象 */ $!{map.className} insert($!{map.className} $!{map.subClassName})); /** * 修改数据 * * @author 陌路 * @date $!{map.currTime} * @param $!{map.subClassName} 实例对象 * @return $!{map.subClassName} 实例对象 */ $!{map.className} update($!{map.className} $!{map.subClassName})); /** * 通过主键作废(逻辑删除) * * @author 陌路 * @date $!{map.currTime} * @param ids 主键 * @return boolean 是否成功 */ boolean deleteByIds(String ids); /** * 通过主键删除(物理删除) * * @author 陌路 * @date $!{map.currTime} * @param ids 主键 * @return boolean 是否成功 */ boolean removeByIds(String ids); }
后台生成代码返回给vue页面,vue渲染,并使用语法高亮展示完整代码
搜索 重置 {{ scope.row.tableSchema }} {{ scope.row.tableName }} {{ scope.row.tableComment }} {{ scope.row.engine }} {{ scope.row.tableCollation }} {{ scope.row.tableRows }} {{ scope.row.createTime }} {{ scope.row.columnName }} {{ scope.row.columnDefault }} {{ scope.row.isNullable }} {{ scope.row.dataType }} {{ scope.row.columnType }} {{ scope.row.columnKey }} {{ scope.row.extra }} {{ scope.row.columnComment }} 预览 生成
1、选择需要生成代码的表
2、根据个人需求是否去除表前缀
3、生成的代码所在的包路径
点击生成即可生成代码,并可以直接复制使用
生成的菜单SQL语句,包含权限代码
可以生成vue3的语法支持的前端页面
可以生成我们需要的mapper.xml文件
里面包含对数据库的增删改查的语句
这里可以生成对Service的代码实现类
生成对外提供的接口层,包含所需要的权限,接口问道的doc解释等
以上就是使用SpringBoot3、JDK17、Vue3、SpringSecurity6等实现的代码生成器了,其他页面就不一一展示了
优点:
可扩展性高,可以根据自己不同的需求调整代码生成器以及生成逻辑
可自定义生成内容,支持范围广
可个自定义性化代码,按照自己喜欢的风格来自定义生成器