使用 SpringBoot3 打造个性化的代码生成器

戳上方蓝字“Java知音”关注我

1自定义代码生成器

代码基于SpringBoot3、Vue3、highlight实现自定义代码生成功能

SpringBoot3.x、MySQL8、MyBatisPlus3.5.x、velocity2.x、SpringSecurity6.x、Vue3、TypeScript、highlight

demo所需要的依赖及其对应版本号

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.molu</groupId>
    <artifactId>mgzyf-api</artifactId>
    <version>2.4.1</version>
    <description>Java 17 + SpringBoot3 + SpringSecurity6 </description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.5</version> <!-- lookup parent from repository -->
        <relativePath/>
    </parent>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <hutool.version>5.8.15</hutool.version>
        <mysql.version>8.0.28</mysql.version>
        <druid.version>1.2.16</druid.version>
        <mybatis-plus.version>3.5.3.1</mybatis-plus.version>
        <mapstruct.version>1.5.3.Final</mapstruct.version>
        <lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
    </properties>

    <dependencies>
        <!-- velocity -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.3</version>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <!--编译测试环境,不打包在lib-->
            <scope>provided</scope>
        </dependency>
        
        <!-- 允许使用Lombok的Java Bean类中使用MapStruct注解 (Lombok 1.18.20+) -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok-mapstruct-binding</artifactId>
            <version>${lombok-mapstruct-binding.version}</version>
            <scope>provided</scope>
        </dependency>

        <!--    hutool工具包    -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>

  <!-- web支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
  
  <!-- security安全支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

  <!-- 连接池 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

  <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!--    阿里druid工具包    -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.40</version>
        </dependency>

  <!-- mybatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>

  <!-- 参数验证 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

  <!-- 自定义配置类支持 -->
        <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-configuration-processor</artifactId>
         <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2代码生成实现步骤

配置文件

这里是最基础的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
1.1、代码生成器源码目录

这里是代码生成器的源码目录结构,下面会逐一展示这3个类

使用 SpringBoot3 打造个性化的代码生成器
1.2、自定义模板目录

这里是根据我的项目需要,自定义的代码生成器模板,下面会以Service为例解释

使用 SpringBoot3 打造个性化的代码生成器
1.3、代码生成器源码

1.3.1、API接口层

提供数据到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<ColumnDetailVo>
     */

    @GetMapping("/getAllTables")
    @Cacheable(value = "gen:allTableDetails", key = "#root.methodName")
    public Result<List<ColumnDetailVo>> getAllTables() {
        List<ColumnDetailVo> columnDetailVoList = columnDetailMapper.getColumnDetailMapVo(database);
        return Result.success(columnDetailVoList);
    }

    /**
     * 获取所有表中字段信息数据
     *
     * @param tableName 表名
     * @return List<ColumnDetailVo>
     */

    @GetMapping("/getTableInfo/{tableName}")
    public Result<String> getTableInfo(@PathVariable String tableName,
                                       @RequestParam(value = "delPrefix", required = false)
 String delPrefix,
                                       @RequestParam(value = "packageName", required = false) String packageName,
                                       @RequestParam(value = "type") String type
    ) 
{
        List<ColumnDetailVo> 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<String, Object> 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();
    }
}

1.3.2、Mapper

查询数据库,获取表字段信息,以便后面生成代码使用

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<ColumnDetailVo>
     */

    public List<ColumnDetailVo> getColumnDetailMapVo(@Param("database") String database);

    /**
     * 获取所有表中字段信息数据
     *
     * @param tableName 表名
     * @return List<ColumnDetailVo>
     */

    public List<ColumnDetailVo> getColumnDetailMapVoByTableName(@Param("database") String database, @Param("tableName") String tableName);
}

1.3.3、对应Mapper的xml

根据application中指定的数据库名,获取数据库中所有的表名以及表中的字段名

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.molu.system.generate.mapper.ColumnDetailMapper">

    <resultMap type="cn.molu.system.generate.vo.ColumnDetailVo" id="ColumnDetailMap">
        <result property="tableName" column="table_name" jdbcType="VARCHAR"/>
        <result property="tableComment" column="table_comment" jdbcType="VARCHAR"/>
        <result property="engine" column="engine" jdbcType="VARCHAR"/>
        <result property="tableCollation" column="table_collation" jdbcType="VARCHAR"/>
        <result property="tableRows" column="table_rows" jdbcType="VARCHAR"/>
        <result property="createTime" column="create_time" jdbcType="VARCHAR"/>
    </resultMap>

    <!--  获取所有表信息数据  -->
    <select id="getColumnDetailMapVo" resultMap="ColumnDetailMap">
        select table_name, <!-- 表名 -->
               table_comment, <!-- 表名注释 -->
               engine,  <!-- 表数据引擎 -->
               table_collation,  <!-- 表字符集 -->
               table_rows,  <!-- 表中数据条数 -->
               create_time <!-- 表创建时间 -->
        from information_schema.tables
        where upper(table_schema) = upper(#{database})
    </select>

    <!--  获取所有表中字段信息数据  -->
    <select id="getColumnDetailMapVoByTableName" parameterType="string" resultMap="ColumnDetailMap">
        SELECT TABLE_SCHEMA, <!-- 数据库名 -->
               TABLE_NAME, <!-- 表名 -->
               (select b.table_comment
                  from information_schema.tables b
                 where upper(table_schema) = upper(#{database})
                   and upper(table_name) = upper(#{tableName})
                 limit 1) as TABLE_COMMENT, <!-- 表名注释 -->
               COLUMN_NAME, <!-- 字段名 -->
               COLUMN_DEFAULT, <!-- 默认值 -->
               IS_NULLABLE, <!-- 是否可为空:YES、NO -->
               DATA_TYPE, <!-- 数据类型:int、varchar... -->
               COLUMN_TYPE, <!-- 字段类型:int、varchar(30)... -->
               COLUMN_KEY, <!-- 是否主键:PRI -->
               EXTRA, <!-- 是否自增:auto_increment(自增) -->
               COLUMN_COMMENT <!-- 字段注释 -->
        FROM information_schema.columns a
        WHERE upper(table_schema) = upper(#{database})
          AND upper(table_name) = upper(#{tableName})
    </select>
</mapper>

1.3.4、各字段想起类

对应表中字段和字段信息的实体类

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(List<ColumnDetailVo> list) {
        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<String, Object> listToMap(List<ColumnDetailVo> list, String replacePrefix) {
        if (Objects.isNull(list) || list.isEmpty()) return null;
        Map<String, Object> 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<String> pk = new AtomicReference<>();
        AtomicReference<String> pkType = new AtomicReference<>();
        AtomicReference<String> getterPk = new AtomicReference<>();
        AtomicReference<String> pkColumn = new AtomicReference<>();
        List<Map<String, String>> fields = new ArrayList<>(2);
        List<Map<String, String>> otherColumn = new ArrayList<>(2);
        list.forEach(vo -> {
            Map<String, String> field = new HashMap<>(2);
            field.put("columnName", vo.getColumnName()); // 字段名
            field.put("javaField", toUpperFirst(vo.getColumnName())); // 字段对应的Java字段
            field.put("columnComment", vo.getColumnComment()); // 字段注释
            String javaType = getJavaType(vo.getDataType());
            field.put("javaType", javaType); // java字段类型
            field.put("jdbcType", vo.getDataType().toUpperCase());
            field.put("jdbcTypeXml", getJdbcTypeXml(vo.getDataType().toLowerCase()));
            field.put("type", getType(vo.getDataType()));
            field.put("getter", StrUtil.upperFirst(toUpperFirst(vo.getColumnName())));
            if (isPrimaryKey(vo.getColumnKey())) {
                if (StrUtil.equalsIgnoreCase(javaType, "Integer")) {
                    javaType = "Long";
                }
                field.put("javaType", javaType); // java字段类型
                field.put("pkColumn", vo.getColumnName()); // 主键
                pk.set(toUpperFirst(vo.getColumnName()));
                pkColumn.set(vo.getColumnName());
                pkType.set(javaType);
                getterPk.set(StrUtil.upperFirst(toUpperFirst(vo.getColumnName())));
            } else {
                otherColumn.add(field);
            }
            fields.add(field);
        });
        map.put("columns", fields);
        map.put("otherColumn", otherColumn);
        map.put("pk", pk);
        map.put("pkColumn", pkColumn);
        map.put("pkType", pkType);
        map.put("getterPk", getterPk);
        return map;
    }

    /**
     * @title 获取字段类型
     * @author 陌路
     * @date 2023/12/31 21:01
     */

    private String getJdbcTypeXml(String dataType) {
        return switch (dataType) {
            case "int""tinyint" -> "INTEGER";
            case "char" -> "CHAR";
            case "mediumint" -> "MEDIUMINT";
            case "bigint" -> "BIGINT";
            case "float" -> "FLOAT";
            case "double" -> "DOUBLE";
            case "bit" -> "BIT";
            case "datetime""date""time""timestamp" -> "TIMESTAMP";
            default -> "VARCHAR";
        };
    }

    /**
     * @title 获取字段类型
     * @author 陌路
     * @date 2023/12/31 21:01
     */

    private String getType(String dataType) {
        String javaType = getJavaType(dataType);
        String type = "java.lang." + dataType;
        if (StrUtil.equals(javaType, "Date")) {
            type = "java.util.Date";
        }
        return type;
    }

    /**
     * @title 获取字段类型
     * @author 陌路
     * @date 2023/12/31 21:01
     */

    private String getJavaType(String dataType) {
        return switch (dataType) {
            case "bigint" -> "Long";
            case "datetime""date""time""timestamp" -> "Date";
            case "decimal""double" -> "Double";
            case "float" -> "Float";
            case "int""tinyint""integer" -> "Integer";
            default -> "String";
        };
    }

    /**
     * 首字母转大写
     *
     * @param field 字段
     * @return 首字母大写
     */

    public String toUpperFirst(String field) {
        // 表名转驼峰命名
        StringBuilder string = new StringBuilder();
        if (StrUtil.isNotEmpty(field) && field.contains("_")) {
            for (String str : field.split("_")) {
                string.append(StrUtil.upperFirst(str));
            }
        } else {
            string = new StringBuilder(StrUtil.upperFirst(field));
        }
        return StrUtil.lowerFirst(string.toString());
    }
}
1.4、自定义模板

自定义的模板,通过模板生成所需要的代码

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);
}
1.5、页面预览代码

后台生成代码返回给vue页面,vue渲染,并使用语法高亮展示完整代码

<script setup lang="ts">
defineOptions({
  name"Code",
  inheritAttrsfalse,
});

import { ColumnDetailQuery, ColumnDetailVo } from "@/api/generate/types";
import { getAllTables, getTableInfo } from "@/api/generate";
import { ref, onMounted, reactive } from "vue";

import "highlight.js/styles/atom-one-light.css";
import "highlight.js/lib/common";
import hljs from "highlight.js";

const queryParams = reactive<ColumnDetailQuery>({});
const queryFormRef = ref(ElForm);
const dialog = reactive<DialogOption>({
  visiblefalse,
  title"",
});
// 选择表格行的数据ID
const loading = ref(false); // 加载状态
const columnDetailVoList = ref<ColumnDetailVo[]>([]); // 记录列表数据
const dataType = ref(0); // 数据类型
const params = ref({
  tableName""// 表名
  delPrefix""// 删除前缀
  packageName"cn.molu.system"// 所在包
  type"java/entity.java"// 数据类型
});
const result = ref({});
const codeCache = new Map();
const tableName = ref("");
const preview = ref({
  activeName"entity",
  data: [],
  title"",
  openfalse,
  codenull,
  vmName"entity.java",
});
// 这里可以从后台获取,我这里为了直观的展示就写死了这几种
const tabPaneData = reactive<any[]>([
  {
    label"entity.java",
    name"entity",
    path"java/entity.java",
  },
  {
    label"controller.java",
    name"controller",
    path"java/controller.java",
  },
  {
    label"service.java",
    name"service",
    path"java/service.java",
  },
  {
    label"serviceImpl.java",
    name"scopeImpl",
    path"java/serviceImpl.java",
  },
  {
    label"mapper.java",
    name"mapper",
    path"java/mapper.java",
  },
  {
    label"mapperXml.xml",
    name"mapperXml",
    path"xml/mapper.xml",
  },
  {
    label"params.java",
    name"params",
    path"java/params.java",
  },
  {
    label"api.ts",
    name"api",
    path"vue3/api.ts",
  },
  {
    label"page.vue",
    name"page",
    path"vue3/page.vue",
  },
  {
    label"types.ts",
    name"types",
    path"vue3/types.ts",
  },
  {
    label"sql.sql",
    name"sql",
    path"sql/sql.sql",
  },
]);

/**
 * 查询按钮点击事件
 */

const handleQuery = () => {
  getAllTables()
    .then(({ data }) => {
      columnDetailVoList.value = data;
    })
    .finally(() => {
      loading.value = false;
    });
};

/**
 * 重置按钮点击事件
 */

const resetQuery = () => {
  queryFormRef.value.resetFields();
  handleQuery();
};
/** 关闭弹窗 */
const closeDialog = () => {
  dialog.visible = false;
};

/**
 * 显示弹框
 */

const openDialog = (row: ColumnDetailVo) => {
  dialog.visible = true;
  dialog.title = "代码预览";
  console.log(row);
  params.value.tableName = row.tableName || "";
  if (!params.value.delPrefix && row.tableName?.includes("_")) {
    params.value.delPrefix = row.tableName?.split("_")[0] + "_";
  }
  tableName.value = row.tableName || "";
  generateCode();
};

/**
 * 选择列表
 */

const changeSelect = (value: string) => {
  console.log(value);
  params.value.tableName = value;
  if (!params.value.delPrefix && value?.includes("_")) {
    params.value.delPrefix = value?.split("_")[0] + "_";
  }
  tableName.value = value || "";
  generateCode();
};

/**
 * 生成代码
 */

const generateCode = () => {
  let obj = codeCache.get(tableName.value) || {};
  let activeName = preview.value.activeName;
  if (obj && obj[activeName]) {
    let code = obj[activeName] || "";
    result.value = code;
    return;
  }
  getTableInfo(tableName.value, params.value).then((response) => {
    const data = response.data;
    preview.value.code = data;
    const vmName = preview.value.vmName || "";
    let language = vmName.substring(vmName.indexOf(".") + 1, vmName.length).toLowerCase();
    language =  ["vue""html""xml"].includes(language) ? "html" : language;
    language = language === 'js' ? "javascript": language;
    result.value = hljs.highlight(data || "", {
      language: language,
      ignoreIllegalstrue,
    }).value;
    obj[activeName] = result.value || "";
    codeCache.set(tableName.value, obj);
    return result.value || "&nbsp;";
  });
};

/**
 * tab切换事件
 */

const tabChange = (tabPaneName: any) => {
  console.log(tabPaneName);
  preview.value.activeName = tabPaneName;
  const tabPane = tabPaneData.find((item) => item.name == tabPaneName);
  console.log(tabPane);
  preview.value.vmName = tabPane.label;
  params.value.type = tabPane.path;
  generateCode();
};
/**
 * 复制代码
 */

const clipboardSuccess = () => {
  ElMessage.success("复制成功");
};

/**
 * 选择页码,分页查询
 */

const updateCurrentPage = (page?: number) => {
  queryParams.page = page;
  handleQuery();
};

/**
 * 页面加载完成后执行
 */

onMounted(() => {
  handleQuery();
});
</script>

<template>
  <div class="app-container">
    <div class="search-container">
      <el-form ref="queryFormRef" :model="params" :inline="true">
        <!-- 表名 -->
        <el-form-item label="表名" prop="tableName">
          <el-input v-model="params.tableName" placeholder="表名" disabled />
        </el-form-item>
        <!-- 删除前缀 -->
        <el-form-item label="删除前缀" prop="delPrefix" v-if="false">
          <el-input
            v-model="params.delPrefix"
            placeholder="删除前缀"
            clearable
          />

        </el-form-item>
        <!-- 所在包 -->
        <el-form-item label="所在包" prop="packageName" v-if="false">
          <el-input
            v-model="params.packageName"
            placeholder="所在包"
            clearable
          />

        </el-form-item>
        <el-form-item>
          <el-button class="filter-item" type="primary" @click="handleQuery">
            <i-ep-search />
            搜索
          </el-button>
          <el-button @click="resetQuery"> <i-ep-refresh />重置 </el-button>
        </el-form-item>
      </el-form>
    </div>

    <el-card shadow="never" class="table-container">
      <el-scrollbar style="height: 400px">
        <el-table
          v-loading="loading"
          :data="columnDetailVoList"
          row-key="id"
          default-expand-all
          :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
        >

          <!-- 复选款 -->
          <el-table-column type="selection" width="55" align="center" />
          <!-- 序号 -->
          <el-table-column
            type="index"
            width="55"
            align="center"
            label="序号"
          />

          <!-- 数据库名 -->
          <el-table-column
            label="数据库名"
            align="center"
            prop="tableSchema"
            v-if="dataType == 1"
          >

            <template #default="scope">
              {{ scope.row.tableSchema }}
            </template>
          </el-table-column>
          <!-- 表名 -->
          <el-table-column label="表名" align="center" prop="tableName">
            <template #default="scope">
              {{ scope.row.tableName }}
            </template>
          </el-table-column>
          <!-- 表注释 -->
          <el-table-column
            label="表注释"
            align="center"
            prop="tableComment"
            v-if="dataType == 0"
          >

            <template #default="scope">
              {{ scope.row.tableComment }}
            </template>
          </el-table-column>
          <!-- 表数据引擎 -->
          <el-table-column
            label="表引擎"
            align="center"
            prop="engine"
            v-if="dataType == 0"
          >

            <template #default="scope">
              {{ scope.row.engine }}
            </template>
          </el-table-column>
          <!-- 表字符集 -->
          <el-table-column
            label="字符集"
            align="center"
            prop="tableCollation"
            v-if="dataType == 0"
          >

            <template #default="scope">
              {{ scope.row.tableCollation }}
            </template>
          </el-table-column>
          <!-- 表中数据条数 -->
          <el-table-column
            label="数据量"
            align="center"
            prop="tableRows"
            v-if="dataType == 0"
          >

            <template #default="scope">
              {{ scope.row.tableRows }}
            </template>
          </el-table-column>
          <!-- 表创建时间 -->
          <el-table-column
            label="创建时间"
            align="center"
            prop="createTime"
            v-if="dataType == 0"
          >

            <template #default="scope">
              {{ scope.row.createTime }}
            </template>
          </el-table-column>

          <!-- 字段名 -->
          <el-table-column
            label="字段名"
            align="center"
            prop="columnName"
            v-if="dataType == 1"
          >

            <template #default="scope">
              {{ scope.row.columnName }}
            </template>
          </el-table-column>
          <!-- 默认值 -->
          <el-table-column
            label="默认值"
            align="center"
            prop="columnDefault"
            v-if="dataType == 1"
          >

            <template #default="scope">
              {{ scope.row.columnDefault }}
            </template>
          </el-table-column>
          <!-- 是否可为空:YES、NO -->
          <el-table-column
            label="可为空"
            align="center"
            prop="isNullable"
            v-if="dataType == 1"
          >

            <template #default="scope">
              {{ scope.row.isNullable }}
            </template>
          </el-table-column>
          <!-- 数据类型:int、varchar... -->
          <el-table-column
            label="数据类型"
            align="center"
            prop="dataType"
            v-if="dataType == 1"
          >

            <template #default="scope">
              {{ scope.row.dataType }}
            </template>
          </el-table-column>
          <!-- 字段类型:int、varchar(30)... -->
          <el-table-column
            label="字段类型"
            align="center"
            prop="columnType"
            v-if="dataType == 1"
          >

            <template #default="scope">
              {{ scope.row.columnType }}
            </template>
          </el-table-column>
          <!-- 是否主键:PRI -->
          <el-table-column
            label="是否主键"
            align="center"
            prop="columnKey"
            v-if="dataType == 1"
          >

            <template #default="scope">
              {{ scope.row.columnKey }}
            </template>
          </el-table-column>
          <!-- 是否自增:auto_increment(自增) -->
          <el-table-column
            label="是否自增"
            align="center"
            prop="extra"
            v-if="dataType == 1"
          >

            <template #default="scope">
              {{ scope.row.extra }}
            </template>
          </el-table-column>
          <!-- 字段注释 -->
          <el-table-column
            label="字段注释"
            align="center"
            prop="columnComment"
            v-if="dataType == 1"
          >

            <template #default="scope">
              {{ scope.row.columnComment }}
            </template>
          </el-table-column>
          <!-- 操作 -->
          <el-table-column
            label="操作"
            fixed="right"
            align="left"
            width="200"
            v-if="dataType == 0"
          >

            <template #default="scope">
              <el-button
                type="primary"
                link
                size="small"
                @click.stop="openDialog(scope.row)"
              >

                <i-ep-view />预览
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-scrollbar>
      <div
        style="
          margin: 15px auto;
          display: flex;
          align-items: center;
          justify-content: center;
        "

      >

        <!-- 这里是分页插件 -->
        <!-- <el-pagination
          background
          layout="prev, pager, next"
          :total="queryParams.total"
          :default-page-size="10"
          v-model:page-size="queryParams.size"
          v-model:current-page="queryParams.page"
          @update:current-page="updateCurrentPage"
        /> -->

      </div>
    </el-card>

    <!-- 预览弹窗 -->
    <el-dialog
      v-model="dialog.visible"
      :title="dialog.title"
      destroy-on-close
      append-to-body
      align-center
      lock-scroll
      width="80%"
      @close="closeDialog"
      top="3vh"
    >

      <el-form ref="queryFormRef" :model="params" :inline="true">
        <!-- 表名 -->
        <el-form-item label="表名" prop="tableName">
          <el-select
            v-model="params.tableName"
            placeholder="表名"
            @change="changeSelect"
          >

            <el-option
              v-for="(item, i) in columnDetailVoList"
              :key="i"
              :label="item.tableName"
              :value="item.tableName"
            />

          </el-select>
        </el-form-item>
        <!-- 删除前缀 -->
        <el-form-item label="删除前缀" prop="delPrefix">
          <el-input v-model="params.delPrefix" placeholder="删除前缀" />
        </el-form-item>
        <!-- 所在包 -->
        <el-form-item label="所在包" prop="packageName">
          <el-input v-model="params.packageName" placeholder="所在包" />
        </el-form-item>
        <el-form-item>
          <el-button class="filter-item" type="primary" @click="generateCode">
            生成
          </el-button>
        </el-form-item>
      </el-form>

      <el-tabs
        v-model="preview.activeName"
        class="demo-tabs"
        @tab-change="tabChange"
      >

        <el-scrollbar max-height="420px">
          <el-tab-pane
            v-for="(item, key) in tabPaneData"
            :label="item.label"
            :name="item.name"
            :key="key"
          >

            <!-- <el-link :underline="false" 
              icon="el-icon-document-copy" 
              v-clipboard:copy="preview.code" 
              v-clipboard:success="clipboardSuccess" 
              style="float:right">复制</el-link> -->

            
            <pre class="hljs-container">
              <code class="hljs" v-html="result"></code>
            </pre>
          </el-tab-pane>
        </el-scrollbar>
      </el-tabs>
    </el-dialog>
  </div>
</template>

<style lang="scss" scoped>
/* 语法高亮 */
.hljs-container {
  position: relative;
  display: block;
  // width: 600px;
  padding: 30px 5px 2px;
  overflow-x: hidden;
  line-height: 20px;
  text-align: left;
  background: #21252b;
  box-shadow: 0 10px 30px 0 rgb(0 0 0 / 40%);
}

/** 3个点 */
.hljs-container::before {
  position: absolute;
  top: 10px;
  left: 15px;
  width: 12px;
  height: 12px;
  overflow: visible;
  font-weight: 700;
  font-size: 16px;
  line-height: 12px;
  white-space: nowrap;
  text-indent: 75px;
  background-color: #fc625d;
  border-radius: 16px;
  box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
  content: attr(codetype);
}

/** 滚动条 */
:deep(.hljs) {
  overflow-x: auto;
  color: #4887b8;
  background-color: #21252b;
  // background-color: #dddddd;
}

:deep(.hljs::-webkit-scrollbar) {
  width: 12px !important;
  height: 12px !important;
}

:deep(.hljs::-webkit-scrollbar-thumb) {
  height: 30px !important;
  background: #d1d8e6;
  background-clip: content-box;
  border: 2px solid transparent;
  border-radius: 19px;
  opacity: 0.8;
}

:deep(.hljs::-webkit-scrollbar-thumb:hover) {
  background: #a5b3cf;
  background-clip: content-box;
  border: 2px solid transparent;
}

:deep(.hljs::-webkit-scrollbar-track-piece) {
  width: 30px;
  height: 30px;
  background: #333;
}

::-webkit-scrollbar-button {
  display: none;
}
</style>
1.6、代码生成器的使用
  • 选择需要生成代码的表
  • 根据个人需求是否去除表前缀
  • 生成的代码所在的包路径

点击生成即可生成代码,并可以直接复制使用

使用 SpringBoot3 打造个性化的代码生成器
1.7、效果展示

1.7.1、菜单SQL

生成的菜单SQL语句,包含权限代码

使用 SpringBoot3 打造个性化的代码生成器

1.7.2、生成的vue3页面

可以生成vue3的语法支持的前端页面

使用 SpringBoot3 打造个性化的代码生成器

1.7.3、生成的xml文件

可以生成我们需要的mapper.xml文件

里面包含对数据库的增删改查的语句

使用 SpringBoot3 打造个性化的代码生成器

1.7.4、生成的Service代码

这里可以生成对Service的代码实现类

使用 SpringBoot3 打造个性化的代码生成器

1.7.5、生成的controller

生成对外提供的接口层,包含所需要的权限,接口问道的doc解释等

使用 SpringBoot3 打造个性化的代码生成器

以上就是使用SpringBoot3、JDK17、Vue3、SpringSecurity6等实现的代码生成器了,其他页面就不一一展示了

优点:

  • 可扩展性高,可以根据自己不同的需求调整代码生成器以及生成逻辑

  • 可自定义生成内容,支持范围广

  • 可个自定义性化代码,按照自己喜欢的风格来自定义生成器

感谢阅读,希望对你有所帮助 :)   来源:

blog.csdn.net/qq_51076413/article/details/135394070

后端专属技术群

构建高质量的技术交流社群,欢迎从事编程开发、技术招聘HR进群,也欢迎大家分享自己公司的内推信息,相互帮助,一起进步!

文明发言,以交流技术职位内推行业探讨为主

广告人士勿入,切勿轻信私聊,防止被骗

使用 SpringBoot3 打造个性化的代码生成器

加我好友,拉你进群

原文始发于微信公众号(Java知音):使用 SpringBoot3 打造个性化的代码生成器

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/196735.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!