基于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();
        }
    }

}

完整代码下载:https://gitee.com/qiangesoft/boot-codegen

  • 14
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Boot和MyBatis-Plus是常用于Java开发的两个框架。Spring Boot是一个用于快速构建基于Spring的应用程序的框架,它简化了Spring应用的配置和部署。MyBatis-Plus是一个基于MyBatis的增强工具,提供了更便捷的操作数据库的方式。 在使用Spring Boot和MyBatis-Plus时,可以使用MyBatis-Plus提供的代码生成器来自动生成代码代码生成器可以根据数据库中的表结构自动生成实体类、Mapper接口和XML文件,并提供一些常用的CRUD方法。 使用Spring Boot和MyBatis-Plus生成代码的步骤如下: 1. 首先,在pom.xml文件中添加MyBatis-Plus和数据库驱动的依赖。 2. 在Spring Boot的配置文件中配置数据库连接信息。 3. 创建数据库表,并确保表结构正确。 4. 创建一个代码生成器的配置类,配置生成的代码的包名、作者、父类等信息。 5. 运行代码生成器,即可自动生成实体类、Mapper接口和XML文件。 需要注意的是,代码生成器生成的代码是基础的CRUD操作,可能需要根据实际业务需求进行进一步的修改和扩展。 通过使用Spring Boot和MyBatis-Plus代码生成器,可以快速生成基于数据库表结构的实体类和数据库操作代码,提高开发效率。<span class="em">1</span> #### 引用[.reference_title] - *1* [基于springboot+mybatis-plus+mysql+vue音乐网站管理系统](https://download.csdn.net/download/Timi2019/87746549)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PG_强哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值