基于SpringBoot+MyBatis-Plus的代码生成器

一、功能说明

  • 数据源管理:实现多个数据库的表代码生成
  • 表管理:从数据源导入表,配置表和字段
  • 默认配置:配置项目默认信息,配置字段数据类型映射
  • 操作日志

功能截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、代码实现

  • 基于velocity-engine模板代码生成
package com.qiangesoft.bootcodegen.utils;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.config.ConstVal;
import com.baomidou.mybatisplus.generator.util.FileUtils;
import com.qiangesoft.bootcodegen.constant.CodegenConstant;
import com.qiangesoft.bootcodegen.entity.BcgTableColumn;
import com.qiangesoft.bootcodegen.framework.config.CodeGenParam;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 代码生成工具类
 *
 * @author qiangesoft
 * @date 2023-09-29
 */
public class CodeGenUtil {

    /**
     * 路径分隔符
     */
    public static final String FILE_SEP = "/";

    /**
     * java路径
     */
    public static final String JAVA_PATH = FILE_SEP + "src" + FILE_SEP + "main" + FILE_SEP + "java";

    /**
     * 资源文件路径
     */
    public static final String RESOURCES_PATH = FILE_SEP + "src" + FILE_SEP + "main" + FILE_SEP + "resources";

    /**
     * 控制层
     */
    public static String CONTROLLER = "controller";

    /**
     * 实体类
     */
    public static String ENTITY = "entity";

    /**
     * 服务层接口
     */
    public static String SERVICE = "service";

    /**
     * 服务层实现类
     */
    public static String SERVICE_IMPL = "serviceImpl";

    /**
     * 持久层
     */
    public static String MAPPER = "mapper";

    /**
     * 持久层xml
     */
    public static String MAPPER_XML = "mapperXml";

    /**
     * 查询对象
     */
    public static String QUERY = "query";

    /**
     * 传输对象
     */
    public static String DTO = "dto";

    /**
     * 对象转换
     */
    public static String CONVERT = "convert";

    /**
     * 视图对象
     */
    public static String VO = "vo";

    /**
     * vue页面
     */
    public static String PAGE = "page";

    /**
     * js代码
     */
    public static String API_JS = "api";

    /**
     * 模板文件
     */
    public static final Map<String, String> TEMPLATE_MAP = new HashMap<>();

    /**
     * 模板文件位置
     */
    static {
        TEMPLATE_MAP.put(CONTROLLER, FILE_SEP + "templates" + FILE_SEP + "controller.java.vm");
        TEMPLATE_MAP.put(ENTITY, FILE_SEP + "templates" + FILE_SEP + "entity.java.vm");
        TEMPLATE_MAP.put(SERVICE, FILE_SEP + "templates" + FILE_SEP + "service.java.vm");
        TEMPLATE_MAP.put(SERVICE_IMPL, FILE_SEP + "templates" + FILE_SEP + "serviceImpl.java.vm");
        TEMPLATE_MAP.put(MAPPER, FILE_SEP + "templates" + FILE_SEP + "mapper.java.vm");
        TEMPLATE_MAP.put(QUERY, FILE_SEP + "templates" + FILE_SEP + "Query.java.vm");
        TEMPLATE_MAP.put(DTO, FILE_SEP + "templates" + FILE_SEP + "DTO.java.vm");
        TEMPLATE_MAP.put(VO, FILE_SEP + "templates" + FILE_SEP + "VO.java.vm");
        TEMPLATE_MAP.put(CONVERT, FILE_SEP + "templates" + FILE_SEP + "Convert.java.vm");
        TEMPLATE_MAP.put(MAPPER_XML, FILE_SEP + "templates" + FILE_SEP + "mapper.xml.vm");
        TEMPLATE_MAP.put(PAGE, FILE_SEP + "templates" + FILE_SEP + "page.vue.vm");
        TEMPLATE_MAP.put(API_JS, FILE_SEP + "templates" + FILE_SEP + "api.js.vm");
    }

    /**
     * 代码存放路径
     */
    public static Map<String, String> codeGenFilePath(String genModule, String genPackage) {
        Map<String, String> codeGenFilePackage = codeGenFilePackage(genModule, genPackage);

        Map<String, String> map = new HashMap<>();
        String controllerPath = JAVA_PATH + FILE_SEP + codeGenFilePackage.get(CONTROLLER).replace(".", FILE_SEP) + FILE_SEP;
        String entityPath = JAVA_PATH + FILE_SEP + codeGenFilePackage.get(ENTITY).replace(".", FILE_SEP) + FILE_SEP;
        String servicePath = JAVA_PATH + FILE_SEP + codeGenFilePackage.get(SERVICE).replace(".", FILE_SEP) + FILE_SEP;
        String serviceImplPath = JAVA_PATH + FILE_SEP + codeGenFilePackage.get(SERVICE_IMPL).replace(".", FILE_SEP) + FILE_SEP;
        String mapperPath = JAVA_PATH + FILE_SEP + codeGenFilePackage.get(MAPPER).replace(".", FILE_SEP) + FILE_SEP;
        String queryPath = JAVA_PATH + FILE_SEP + codeGenFilePackage.get(QUERY).replace(".", FILE_SEP) + FILE_SEP;
        String dtoPath = JAVA_PATH + FILE_SEP + codeGenFilePackage.get(DTO).replace(".", FILE_SEP) + FILE_SEP;
        String voPath = JAVA_PATH + FILE_SEP + codeGenFilePackage.get(VO).replace(".", FILE_SEP) + FILE_SEP;
        String convertPath = JAVA_PATH + FILE_SEP + codeGenFilePackage.get(CONVERT).replace(".", FILE_SEP) + FILE_SEP;
        String mapperXmlPath = RESOURCES_PATH + FILE_SEP + "mapper" + FILE_SEP + (StringUtils.isNotBlank(genModule) ? genModule + FILE_SEP : "");
        String pagePath = FILE_SEP + "page" + FILE_SEP + "views" + FILE_SEP;
        String apiJsPath = FILE_SEP + "page" + FILE_SEP + "api" + FILE_SEP;
        map.put(CONTROLLER, controllerPath);
        map.put(ENTITY, entityPath);
        map.put(SERVICE, servicePath);
        map.put(SERVICE_IMPL, serviceImplPath);
        map.put(MAPPER, mapperPath);
        map.put(QUERY, queryPath);
        map.put(DTO, dtoPath);
        map.put(VO, voPath);
        map.put(CONVERT, convertPath);
        map.put(MAPPER_XML, mapperXmlPath);
        map.put(PAGE, pagePath);
        map.put(API_JS, apiJsPath);
        return map;
    }

    /**
     * java代码包路径
     */
    public static Map<String, String> codeGenFilePackage(String genModule, String genPackage) {
        Map<String, String> map = new HashMap<>();
        String packagePath = StringUtils.isNotBlank(genModule) ? genPackage + "." + genModule : genPackage;
        String controllerPath = packagePath + ".controller";
        String entityPath = packagePath + ".entity";
        String servicePath = packagePath + ".service";
        String serviceImplPath = servicePath + ".impl";
        String mapperPath = packagePath + ".mapper";
        String queryPath = packagePath + ".pojo.query";
        String dtoPath = packagePath + ".pojo.dto";
        String voPath = packagePath + ".pojo.vo";
        String convertPath = packagePath + ".pojo.convert";
        map.put(CONTROLLER, controllerPath);
        map.put(ENTITY, entityPath);
        map.put(SERVICE, servicePath);
        map.put(SERVICE_IMPL, serviceImplPath);
        map.put(MAPPER, mapperPath);
        map.put(QUERY, queryPath);
        map.put(DTO, dtoPath);
        map.put(VO, voPath);
        map.put(CONVERT, convertPath);
        return map;
    }

    /**
     * 本地项目生成
     */
    public static void genLocal(CodeGenParam codeGenParam) throws IOException {
        // 1.初始化Velocity引擎
        initVelocity();

        // 2.加载velocity容器
        VelocityContext velocityContext = buildVelocityContext(codeGenParam);

        // 3.生成文件
        String genClass = codeGenParam.getGenClass();
        Map<String, String> map = codeGenFilePath(codeGenParam.getGenModule(), codeGenParam.getGenPackage());
        for (String key : map.keySet()) {
            String templatePath = TEMPLATE_MAP.get(key);
            String filePath = map.get(key);
            String fileName = getFileName(genClass, key, templatePath, filePath);
            File file = new File(codeGenParam.getGenPath() + fileName);
            boolean exist = file.exists();
            if (!exist) {
                File parentFile = file.getParentFile();
                FileUtils.forceMkdir(parentFile);
            }
            Template template = Velocity.getTemplate(templatePath, ConstVal.UTF8);
            try (FileOutputStream fos = new FileOutputStream(file);
                 OutputStreamWriter ow = new OutputStreamWriter(fos, ConstVal.UTF8);
                 BufferedWriter writer = new BufferedWriter(ow)) {
                template.merge(velocityContext, writer);
            } catch (Exception e) {
                throw new RuntimeException("代码生成失败");
            }
        }
    }

    /**
     * 下载代码
     *
     * @param codeGenParam
     * @param response
     */
    public static void genDownload(CodeGenParam codeGenParam, HttpServletResponse response) {
        // 1.初始化Velocity引擎
        initVelocity();

        // 2.加载velocity容器
        VelocityContext velocityContext = buildVelocityContext(codeGenParam);

        // 3.生成文件
        String genClass = codeGenParam.getGenClass();
        Map<String, String> map = codeGenFilePath(codeGenParam.getGenModule(), codeGenParam.getGenPackage());
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
            for (String key : map.keySet()) {
                String templatePath = TEMPLATE_MAP.get(key);
                String filePath = map.get(key);
                String fileName = getFileName(genClass, key, templatePath, filePath).replaceFirst("/", "");
                creatZipEntry(templatePath, fileName, velocityContext, zipOutputStream);
            }
            IOUtils.closeQuietly(zipOutputStream);
            byte[] bytes = outputStream.toByteArray();
            response.reset();
            response.setHeader("Content-Disposition", "attachment; filename=code.zip");
            response.addHeader("Content-Length", "" + bytes.length);
            response.setContentType("application/octet-stream; charset=UTF-8");
            IOUtils.write(bytes, response.getOutputStream());
        } catch (Exception e) {
            throw new RuntimeException("代码生成失败");
        }
    }

    /**
     * 初始化vm
     */
    private static void initVelocity() {
        Properties properties = new Properties();
        properties.setProperty(ConstVal.VM_LOAD_PATH_KEY, ConstVal.VM_LOAD_PATH_VALUE);
        properties.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, StringPool.EMPTY);
        properties.setProperty(Velocity.ENCODING_DEFAULT, ConstVal.UTF8);
        properties.setProperty(Velocity.INPUT_ENCODING, ConstVal.UTF8);
        properties.setProperty("file.resource.loader.unicode", StringPool.TRUE);

        Velocity.init(properties);
    }

    /**
     * 变量替换参数
     *
     * @param codeGenParam
     * @return
     */
    private static VelocityContext buildVelocityContext(CodeGenParam codeGenParam) {
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("tableName", codeGenParam.getTableName());
        velocityContext.put("genAuthor", codeGenParam.getGenAuthor());
        velocityContext.put("genDate", codeGenParam.getGenDate());
        velocityContext.put("genFunction", codeGenParam.getGenFunction());
        velocityContext.put("genClass", codeGenParam.getGenClass());
        char firstChar = codeGenParam.getGenClass().charAt(0);
        velocityContext.put("genClassCamel", Character.toLowerCase(firstChar) + codeGenParam.getGenClass().substring(1));
        List<BcgTableColumn> columnList = codeGenParam.getColumnList();
        velocityContext.put("columnList", columnList);
        velocityContext.put("controllerMapping", TableColumnInitUtil.camelToChar(codeGenParam.getGenClass(), '-'));
        velocityContext.put("packageConfig", codeGenFilePackage(codeGenParam.getGenModule(), codeGenParam.getGenPackage()));
        velocityContext.put("columnConfig", CodegenConstant.COLUMN_CONFIG);
        for (BcgTableColumn tableColumn : columnList) {
            if (tableColumn.getColumnPk()) {
                velocityContext.put("idConfig", tableColumn);
                break;
            }
        }

        velocityContext.put("hutoolStrUtil", cn.hutool.core.util.StrUtil.class);
        return velocityContext;
    }

    /**
     * 文件信息
     *
     * @param genClass
     * @param key
     * @param templatePath
     * @param filePath
     * @return
     */
    private static String getFileName(String genClass, String key, String templatePath, String filePath) {
        String fileBaseName = templatePath.substring(templatePath.lastIndexOf('/') + 1, templatePath.lastIndexOf('.'));
        String fileName;
        if (ENTITY.equals(key)) {
            fileName = filePath + genClass + ".java";
        } else if (PAGE.equals(key)) {
            fileName = filePath + genClass + ".vue";
        } else if (API_JS.equals(key)) {
            fileName = filePath + genClass + ".js";
        } else if (SERVICE.equals(key)) {
            fileName = filePath + "I" + genClass + Character.toUpperCase(fileBaseName.charAt(0)) + fileBaseName.substring(1);
        } else {
            fileName = filePath + genClass + Character.toUpperCase(fileBaseName.charAt(0)) + fileBaseName.substring(1);
        }
        return fileName;
    }

    /**
     * 合成单个文件
     *
     * @param templatePath
     * @param fileName
     * @param velocityContext
     * @param zipOutputStream
     */
    private static void creatZipEntry(String templatePath, String fileName, VelocityContext velocityContext, ZipOutputStream zipOutputStream) throws IOException {
        // 加载模板并替换变量
        try (StringWriter stringWriter = new StringWriter()) {
            Template template = Velocity.getTemplate(templatePath, ConstVal.UTF8);
            template.merge(velocityContext, stringWriter);
            zipOutputStream.putNextEntry(new ZipEntry(fileName));
            String content = stringWriter.toString();
            zipOutputStream.write(content.getBytes(ConstVal.UTF8));
            zipOutputStream.flush();
            zipOutputStream.closeEntry();
        }
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/528670.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

工单管理系统设计方案,工单系统的流程

工单管理系统是一种用于管理和跟踪工作流程的软件系统。它可以帮助企业和组织更好地分配任务、优化工作流程、提高生产效率和客户满意度。下面是一个基本的工单管理系统设计方案&#xff1a;需求分析  在设计工单管理系统之前&#xff0c;需要进行需求分析&#xff0c;确定系…

三极管原理特性介绍,课堂上可不这么讲!

原文来自微信公众号&#xff1a;工程师看海&#xff0c;与我联系&#xff1a;chunhou0820 看海原创视频教程&#xff1a;《运放秘籍》 大家好&#xff0c;我是工程师看海&#xff0c;原创文章欢迎点赞分享&#xff01; 今天介绍下三极管的特性&#xff0c;清晰易懂&#xff0c…

C语言进阶课程学习记录-第27课 - 数组的本质分析

C语言进阶课程学习记录-第27课 - 数组的本质分析 数组实验-数组元素个数的指定实验-数组地址与数组首元素地址实验-指针与数组地址的区别小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程&#xff0c;图片全部来源于课程PPT&#xff0c;仅用于个人学习记录 数组 实验-数…

Ubuntu 22上安装Anaconda3。下载、安装、验证详细教程

在Ubuntu 22上安装Anaconda3&#xff0c;你可以遵循以下步骤&#xff1a; 更新系统存储库&#xff1a; 打开终端并运行以下命令来更新系统存储库&#xff1a; sudo apt update安装curl包&#xff1a; 下载Anaconda安装脚本通常需要使用curl工具。如果系统中没有安装curl&#x…

如何提升产品用户体验?4个工具+6张案例,让你快速吃透!

在数字时代的浪潮中&#xff0c;产品用户体验早已不再是简单的“好用”或“不好用”的评判标准&#xff0c;它不仅仅是功能的堆砌&#xff0c;更是情感的连接、智慧的体现。在这个竞争激烈的市场中&#xff0c;只有那些能够深入理解用户需求、精准把握用户心理的产品&#xff0…

HarmonyOS 开发-应用新功能引导实现案例

介绍 本文介绍如何使用high_light_guide三方库完成应用新版本功能导航。通过高亮区域与蒙版背景的明暗度对比&#xff0c;让用户快速锁定重点功能&#xff0c;了解版本变更和业务入口。 效果图预览 使用说明 点击页面上对应按钮或空白区域进入下一个提示&#xff0c;直至提示…

MiniApp SDK 是什么?

介绍 MiniApp SDK 是提供开发、部署、产品体验分析、上线全流程各种需求的解决方案。接入此 SDK&#xff0c;您就可以只关注于代码开发本身&#xff0c;剩余的所有事情都可以交由 SDK 及其依赖方解决。另外&#xff0c;能够有效降低多端开发的技术门槛和研发成本&#xff0c;提…

一篇文章学会进程替换

进程替换是什么 fork之后&#xff0c;父子进程各自执行父进程的代码的一部分&#xff0c;父子代码共享&#xff0c;数据写时拷贝各自一份。 但是&#xff0c;如果子进程不想执行父进程的代码&#xff0c;就想执行一个全新的代码呢&#xff1f; 这就需要用到 进程程序替换 所谓的…

MybatisPlus分页插件的使用

目录 &#x1f9c2;1.添加mybatisPlus依赖 &#x1f953;2.添加配置类 &#x1f32d;3.添加分页接口 &#x1f37f;4. 添加实现类 &#x1f95e;5.测试 1.添加mybatisPlus依赖 <!--mybatisPlus--><dependency><groupId>com.baomidou</groupId>&l…

linux中查看占用端口的进程方法

1、netstat -tlnp | grep 端口号 netstat -tlnp|grep 3306 其中&#xff1a;95115是进程号&#xff0c;mysqld是进程名称 2、ss -ltnp | grep 端口号 注意&#xff1a;-tlnp和-ltnp ss -ltnp|grep 3306其中&#xff1a;mysqld是进程名称&#xff0c;95115是进程id 3、lsof…

【Python 基础知识课程】Python的第一个程序

Python 简介 Python 是一种功能强大且用途广泛的编程语言&#xff0c;广泛用于数据科学、Web 开发、自动化等高需求领域。 幸运的是&#xff0c;对于初学者来说&#xff0c;它也是一种很好的学习语言&#xff0c;因为Python代码更容易阅读和编写。它的简单性使其成为初学者的完…

R语言绘图 | 散点小提琴图

原文链接&#xff1a;R语言绘图 | 散点小提琴图 本期教程 写在前面 本期的图形来自发表在Nature期刊中的文章&#xff0c;这样的基础图形在日常分析中使用频率较高。 获得本期教程数据及代码&#xff0c;后台回复关键词&#xff1a;20240405 绘图 设置路径 setwd("You…

我是如何从功能测试成功转岗测试开发的?记录下我的面试经验

由于这段时间我面试了很多家公司&#xff0c;也经历了之前公司的不愉快。所以我想写一篇文章来分享一下自己的面试体会。希望能对我在之后的工作或者面试中有一些帮助&#xff0c;也希望能帮助到正在找工作的你。 一 找工作 壹&#xff0f; 我们总是草率地进入一个自己不了解…

岩土工程监测振弦采集仪在隧道工程中的监测与应用

岩土工程监测振弦采集仪在隧道工程中的监测与应用 岩土工程监测是隧道工程的重要环节之一&#xff0c;而振弦采集仪作为岩土工程监测中的关键设备之一&#xff0c;在隧道工程中的应用十分重要。本文将从振弦采集仪的基本原理、在隧道工程中的监测与应用以及其优点和局限性等方…

面试(01)————JVM篇,最大白话的一集,常见概念的讲解以及GC监控调优等等

一、JDK体系结构图 二、JVM整体架构 三、JVM组成 3.1、JVM内存区域的执行底层原理 ​编辑 3.1.1、程序计数器 3.1.2、堆栈关系的发现 3.1.3、方法去和堆的关系 3.1.4、堆&#xff08;重点&#xff09; 3.1.4.1、可达性分析算法 3.1、内存泄漏测试以及堆区的GC监控 3.…

【论文解读】大模型事实性调查(上)

一、简要介绍 本调查探讨了大型语言模型&#xff08;llm&#xff09;中的事实性的关键问题。随着llm在不同领域的应用&#xff0c;其输出的可靠性和准确性变得至关重要。论文将“事实性问题”定义为llm产生与既定事实不一致的内容的概率。论文首先深入研究了这些不准确性的含义…

kali基础渗透学习,永恒之蓝,木马实战

简介 kali的学习本质是在linux上对一些攻击软件的使用&#xff0c;只是学习的初期 先在终端切换到root用户&#xff0c;以便于有些工具对权限的要求 下载链接 镜像源kali 攻击流程 公网信息搜集 寻找漏洞&#xff0c;突破口&#xff0c;以进入内网 进入内网&#xff0c…

GD32F470_SHT20温湿度传感器模块/数字型温湿度测量模块 I2C通讯小体积模块

2.24 SHT20温湿度传感器 由瑞士Sensirion推出的 SHT20数字温湿度传感器&#xff0c;基于领先世界的CMOSens 数字传感技术&#xff0c;具有极高的可靠性和卓越的长期稳定性。全量程标定&#xff0c;两线数字接口&#xff0c;可与单片机直接相连&#xff0c;大大缩短研发时间、…

物联网数据服务平台

随着物联网技术的迅猛发展&#xff0c;海量数据的产生和应用成为推动工业数字化转型的核心动力。在这个数据为王的时代&#xff0c;如何高效地收集、处理、分析并应用这些数据&#xff0c;成为了企业关注的焦点。物联网数据服务平台应运而生&#xff0c;为企业提供了全面、高效…

考研数学|打基础看张宇《30讲》还是武忠祥《基础篇》?

这题我会啊&#xff0c;基础阶段我还是推荐张宇老师 因为张宇老师和武忠祥老师的实力都很厉害&#xff0c;最主要的区别就是讲课的风格。我比较喜欢张宇老师的讲课风格&#xff0c;比较幽默风趣&#xff0c;能够调动课堂氛围了和学生思维。这一点在考研初期&#xff0c;帮助我…