SpringBoot_2:MyBatis-Generator插件使用教程

目录

[一、MyBatis Generator插件的安装](#一、MyBatis Generator插件的安装)

二、编写配置类

三、generatorConfig.xml配置文件

四、编写代码生成方法

[五、MyBatis Generator工作原理](#五、MyBatis Generator工作原理)

六、总结


我们在web开发初期,有很多工作需要做。其中,数据库建表后,生成实体类,mapper接口和SQL语句均需要完成。有没有一个工具,可以帮我们完成上述工作:生成实体类,生成简单的mapper接口,生成配套的简单的通用的结构化查询SQL。

事实上,是有的。就是我们本节将要使用的MyBatis Generator插件。

一、MyBatis Generator插件的安装

在pom文件中,引入generator插件。

XML 复制代码
<!-- MyBatis Generator Maven插件 -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.4.0</version>
                <configuration>
                    <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                    <includeCompileDependencies>true</includeCompileDependencies>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>com.mysql</groupId>
                        <artifactId>mysql-connector-j</artifactId>
                        <version>8.0.33</version>
                    </dependency>
                </dependencies>
            </plugin>

这里我们指定了一个待读取的配置文件src/main/resources/generatorConfig.xml,这个文件中有我们希望读取的数据库和表,以及一些配置信息。

最关键的是,插件运行在独立的ClassLoader,不会继承pom文件中的mysql驱动。但是我们的MBG(MyBatis Generator)需要数据库驱动,所以需要单独添加,选择8.0.33版本的兼容性会更好。

刷新Maven后可以看见插件。

这个插件不需要提前导入mybatis依赖,因为其自身已经实现mybatis的相关功能。

二、编写配置类

我们先建立如下数据库和表:

sql 复制代码
-- 1. 创建数据库
CREATE DATABASE IF NOT EXISTS `demo_db` 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;

USE `demo_db`;

-- 2. 用户表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
    `id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
    `username` VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
    `password` VARCHAR(100) NOT NULL COMMENT '密码',
    `email` VARCHAR(100) COMMENT '邮箱',
    `phone` VARCHAR(20) COMMENT '手机号',
    `status` TINYINT DEFAULT 1 COMMENT '状态:0禁用 1启用',
    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

-- 3. 商品表
DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
    `id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '商品ID',
    `product_name` VARCHAR(200) NOT NULL COMMENT '商品名称',
    `price` DECIMAL(10,2) NOT NULL COMMENT '单价',
    `stock` INT DEFAULT 0 COMMENT '库存数量',
    `category` VARCHAR(50) COMMENT '分类',
    `description` TEXT COMMENT '商品描述',
    `status` TINYINT DEFAULT 1 COMMENT '状态:0下架 1上架',
    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表';

-- 4. 订单表(关联用户和商品)
DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (
    `id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '订单ID',
    `order_no` VARCHAR(32) NOT NULL UNIQUE COMMENT '订单编号',
    `user_id` INT NOT NULL COMMENT '用户ID',
    `product_id` INT NOT NULL COMMENT '商品ID',
    `quantity` INT NOT NULL COMMENT '购买数量',
    `total_price` DECIMAL(10,2) NOT NULL COMMENT '总价',
    `order_status` TINYINT DEFAULT 0 COMMENT '订单状态:0待支付 1已支付 2已发货 3已完成 4已取消',
    `pay_time` DATETIME COMMENT '支付时间',
    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    FOREIGN KEY (`user_id`) REFERENCES `user`(`id`),
    FOREIGN KEY (`product_id`) REFERENCES `product`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

demo_db库中有三张表:用户表,商品表和订单表。

我们希望插件也能创建出三个对应的实体类,User、Product、Order

并且我们希望:实体类中的属性应该符合小驼峰命名规则,实体类的属性中应该有comment注释,还有就是实体类中属性的类型应该是这样的:int->Integer,bigint->Long,vahchar()->String,tinyint->Byte,DateTime->LocalDateTime这样做是应为Date.toString()会根据时区显示同样的数据不同地区显示不同,使用LocalDateTime后toString()就是一个不依赖时区的输出,Decaimal(10,2)-> BigDecimal一共十位数字,小数点后保留两位。

MBG默认会自动完成小驼峰命名规则的转换。

现在需要处理注释,MBG默认的注释可以选择部分开启,但是仍然会重复生成很多没用的注释。所以我们希望创建一个配置类来描述注释的形式。

使用配置类时,需要先导入mybatis-generator依赖。

XML 复制代码
<dependency>
   <groupId>org.mybatis.generator</groupId>
   <artifactId>mybatis-generator-core</artifactId>
   <version>1.4.0</version> <!-- 与你的插件版本保持一致 -->
</dependency>

创建CustomCommentGenerator配置类

java 复制代码
package com.miao.mbg.config;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.InnerClass;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.internal.DefaultCommentGenerator;

public class CustomCommentGenerator extends DefaultCommentGenerator {

    @Override
    public void addFieldComment(Field field, IntrospectedTable introspectedTable,
                                IntrospectedColumn introspectedColumn) {
        String remarks = introspectedColumn.getRemarks();
        if (remarks != null && !remarks.isEmpty()) {
            field.addJavaDocLine("/**");
            field.addJavaDocLine(" * " + remarks);
            field.addJavaDocLine(" */");
        }
    }

    @Override
    public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        String remarks = introspectedTable.getRemarks();
        if (remarks != null && !remarks.isEmpty()) {
            topLevelClass.addJavaDocLine("/**");
            topLevelClass.addJavaDocLine(" * " + remarks);
            topLevelClass.addJavaDocLine(" */");
        }
    }

    @Override
    public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
        String remarks = introspectedTable.getRemarks();
        if (remarks != null && !remarks.isEmpty()) {
            innerClass.addJavaDocLine("/**");
            innerClass.addJavaDocLine(" * " + remarks);
            innerClass.addJavaDocLine(" */");
        }
    }

    @Override
    public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {
    }

    @Override
    public void addGetterComment(Method method, IntrospectedTable introspectedTable,
                                 IntrospectedColumn introspectedColumn) {
    }

    @Override
    public void addSetterComment(Method method, IntrospectedTable introspectedTable,
                                 IntrospectedColumn introspectedColumn) {
    }
}

而且我们不希望生成set和get方法,我们用@Data注解更加简洁。

所以我们需要在此建立一个配置类,关闭set和get方法的生成。

java 复制代码
package com.miao.mbg.config;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.TopLevelClass;

import java.util.List;

/**
 * 自定义 MBG 插件:不生成 getter/setter,改用 Lombok 注解
 */
public class LombokPlugin extends PluginAdapter {

    @Override
    public boolean validate(List<String> warnings) {
        return true;
    }

    @Override
    public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass,
                                                 IntrospectedTable introspectedTable) {
        topLevelClass.addAnnotation("@Data");
        topLevelClass.addAnnotation("@NoArgsConstructor");
        topLevelClass.addAnnotation("@AllArgsConstructor");
        topLevelClass.addImportedType(new FullyQualifiedJavaType("lombok.Data"));
        topLevelClass.addImportedType(new FullyQualifiedJavaType("lombok.NoArgsConstructor"));
        topLevelClass.addImportedType(new FullyQualifiedJavaType("lombok.AllArgsConstructor"));
        return true;
    }

    @Override
    public boolean modelGetterMethodGenerated(Method method,
                                              TopLevelClass topLevelClass,
                                              IntrospectedColumn introspectedColumn,
                                              IntrospectedTable introspectedTable,
                                              ModelClassType modelClassType) {
        return false;
    }

    @Override
    public boolean modelSetterMethodGenerated(Method method,
                                              TopLevelClass topLevelClass,
                                              IntrospectedColumn introspectedColumn,
                                              IntrospectedTable introspectedTable,
                                              ModelClassType modelClassType) {
        return false;
    }

}

我们既然用到了Lombok就需要引入依赖。

XML 复制代码
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>

顺便把mybatis也引入了,未来肯定会用到。

三、generatorConfig.xml配置文件

在src/main/resource下创建配置文件

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <!-- ============================================================ -->
    <!-- 上下文配置                                                    -->
    <!-- targetRuntime: 使用 MyBatis3 标准模式                         -->
    <!-- defaultModelType: flat 表示每个表生成一个实体类               -->
    <!-- ============================================================ -->
    <context id="MysqlContext" targetRuntime="MyBatis3" defaultModelType="flat">

        <!-- ========================================================== -->
        <!-- 通用属性配置                                                -->
        <!-- ========================================================== -->
        <!-- 禁止XML增量合并,防止重复生成BaseResultMap -->
        <property name="mergeable" value="false"/>
        <!-- 关键字自动加反引号,避免与MySQL保留字冲突 -->
        <property name="autoDelimitKeywords" value="true"/>
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>

        <!-- ========================================================== -->
        <!-- 插件配置                                                    -->
        <!-- 使用自定义Lombok插件:自动添加@Data,禁用getter/setter生成 -->
        <!-- ========================================================== -->
        <plugin type="com.miao.mbg.config.LombokPlugin"/>

        <!-- ========================================================== -->
        <!-- 注释生成器配置                                              -->
        <!-- 使用自定义注释生成器:读取数据库COMMENT生成JavaDoc注释     -->
        <!-- ========================================================== -->
        <commentGenerator type="com.miao.mbg.config.CustomCommentGenerator">
            <!-- 不抑制所有注释 -->
            <property name="suppressAllComments" value="false"/>
            <!-- 抑制生成时间戳(减少Git提交噪音) -->
            <property name="suppressDate" value="true"/>
            <!-- 添加数据库字段注释 -->
            <property name="addRemarkComments" value="true"/>
            <!-- 使用新版注释解析方式(MySQL 8.0+) -->
            <property name="useLegacyRemark" value="false"/>
        </commentGenerator>

        <!-- ========================================================== -->
        <!-- JDBC数据库连接配置                                          -->
        <!-- nullCatalogMeansCurrent=true: 只查询当前数据库,避免跨库   -->
        <!-- ========================================================== -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/demo_db?serverTimezone=Asia/Shanghai&amp;characterEncoding=UTF-8&amp;useUnicode=true&amp;useSSL=false&amp;nullCatalogMeansCurrent=true"
                        userId="root"
                        password="182204">
        </jdbcConnection>

        <!-- ========================================================== -->
        <!-- 类型解析器                                                  -->
        <!-- useJSR310Types: DATETIME → LocalDateTime                   -->
        <!-- forceBigDecimals: DECIMAL → BigDecimal                     -->
        <!-- ========================================================== -->
        <javaTypeResolver>
            <property name="useJSR310Types" value="true"/>
            <property name="forceBigDecimals" value="true"/>
        </javaTypeResolver>

        <!-- ========================================================== -->
        <!-- 实体类生成配置                                              -->
        <!-- targetPackage: 实体类包名                                  -->
        <!-- targetProject: 生成路径                                    -->
        <!-- ========================================================== -->
        <javaModelGenerator targetPackage="com.miao.mbg.entity"
                            targetProject="src/main/java">
            <!-- 不启用子包 -->
            <property name="enableSubPackages" value="false"/>
            <!-- 去除字符串前后空格 -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!-- ========================================================== -->
        <!-- Mapper XML生成配置                                          -->
        <!-- ========================================================== -->
        <sqlMapGenerator targetPackage="mapper"
                         targetProject="src/main/resources">
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>

        <!-- ========================================================== -->
        <!-- Mapper接口生成配置                                          -->
        <!-- type=XMLMAPPER: 生成基于XML的Mapper接口                    -->
        <!-- ========================================================== -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.miao.mbg.mapper"
                             targetProject="src/main/java">
            <property name="enableSubPackages" value="false"/>
        </javaClientGenerator>

        <!-- ========================================================== -->
        <!-- 表配置                                                      -->
        <!-- enableXxxByExample=false: 不生成Example类                  -->
        <!-- generatedKey: 主键自增策略                                 -->
        <!-- columnOverride: 自定义字段类型映射                         -->
        <!-- ========================================================== -->

        <!-- 1. 用户表 -->
        <table tableName="user" domainObjectName="User"
               enableCountByExample="false"
               enableUpdateByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false">
            <generatedKey column="id" sqlStatement="MYSQL"/>
        </table>

        <!-- 2. 商品表 -->
        <table tableName="product" domainObjectName="Product"
               enableCountByExample="false"
               enableUpdateByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false">
            <generatedKey column="id" sqlStatement="MYSQL"/>
        </table>

        <!-- 3. 订单表 -->
        <!-- order 是 MySQL 保留字,autoDelimitKeywords=true 会自动加反引号 -->
        <table tableName="order" domainObjectName="Order"
               enableCountByExample="false"
               enableUpdateByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false">
            <generatedKey column="id" sqlStatement="MYSQL"/>
        </table>

    </context>
</generatorConfiguration>

四、编写代码生成方法

在启动类同级目录下创建GeneratorMain类

java 复制代码
package com.miao.mbg;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class GeneratorMain {

    public static void main(String[] args) throws Exception {
        System.setProperty("file.encoding", "UTF-8");

        List<String> warnings = new ArrayList<>();
        File configFile = new File("src/main/resources/generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);

        DefaultShellCallback callback = new DefaultShellCallback(true);
        MyBatisGenerator generator = new MyBatisGenerator(config, callback, warnings);
        generator.generate(null);

        warnings.forEach(System.out::println);
        System.out.println("代码生成完成!");

    }

}

我们运行后,就能看到想要的实体和mapper啦。

使用前,一定要把com.包目录改成你自己的,否则会出问题。

五、MyBatis Generator工作原理

MBG会读取我们的xml配置,然后连接数据库,然后读取元数据。并不是读取表结构。

元数据存放在哪里呢?

在information_schema中:

像TABLES、COLUMNS这些都是元数据,我们可以看看COLUMNS的表结构,看看里面存了什么。

里面存库名,表名,和字段名以及一些数据类型,和约束。

是所有的库+表+对应字段,数据非常多。

也就是你定义过的字段,这里面都会出现。

那么MBG实际的工作就是:

sql 复制代码
-- MBG 实际做的事(通过 JDBC DatabaseMetaData)
SELECT 
    TABLE_NAME,
    TABLE_COMMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'demo_db';

SELECT 
    COLUMN_NAME,
    DATA_TYPE,
    CHARACTER_MAXIMUM_LENGTH,
    IS_NULLABLE,
    COLUMN_DEFAULT,
    COLUMN_COMMENT
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'demo_db' 
  AND TABLE_NAME = 'user';

首先拿到需要处理的表名,和表注释。

然后分别去拿表中的列和数据类型以及字段上的注释和约束。

然后MBG拿着这些数据去创建实体。

那么保证读取到目标库的目标表就成了关键,怎么做到的?

首先是URL配合连接参数。

XML 复制代码
connectionURL="jdbc:mysql://localhost:3306/demo_db?serverTimezone=Asia/Shanghai&amp;characterEncoding=UTF-8&amp;useUnicode=true&amp;useSSL=false&amp;nullCatalogMeansCurrent=true"

首先指定了数据库连接,但是还有一个关键参数nullCatalogMeansCurrent=true,它决定了我们不去读取其他库中的相同名称的表。不然会造成字段混乱,生成的实体类可能字段会增加或者减少。

其次就是元数据查询过滤,这个是MBG做的工作,我们知道即可。

最后是xml里的配置和我们配置类里的配置,我们指定了想要生成的表,具体配置还需要仔细研读我们的xml配置文件。

最后提出一个问题:Maven插件运行在独立的类加载器中,所以我们引入了Lombok和mysql驱动,那么我们的配置类默认是不会被读取的。所以此时如果你使用终端或者Maven面板去运行MBG插件,配置类是会读取失败的。

所以我们选择使用一个Main方法,依靠项目类加载器那么肯定就可以读取到配置类了。这也是最为保险的手段,其次就是文件编码格式,为了避免编码错乱,统一使用UTF-8编码即可。

六、总结

本节我们学会了使用Mybatis Generator来帮助我们快速生成实体类、Mapper、和对应的结构化SQL。包括如何自定义配置类,以及为了读取配置类我们采取使用项目类加载器来生成代码的方法。了解了MBG是去读取Mysql的元数据信息来构建实体类的。

以上就是所有内容,如果有任何问题请指出,作者会认真勘误。

相关推荐
竹枝溪5 小时前
Tomcat与Servlet全套小白教程
java·servlet·tomcat·cookie·filter·session·listener
宠友信息6 小时前
IM系统开发技术路线分析,即时通讯源码助力快速搭建聊天应用
java·spring boot·redis·websocket·mysql·uni-app·vue
QQ_21696290968 小时前
【项目编号:project95315】SpringBoot公共自习室管理系统:座位预约、房间管理、签到核销、公告规则完整实战
java·spring boot·后端
凤山老林8 小时前
高可用服务容错架构:Spring Boot 集成 Resilience4j 实战指南
spring boot·后端·架构·resilience4j
SQL-First布道者9 小时前
全面解构传统持久层框架,拥抱真正的 SQL-First
java·数据库·spring boot·sql·spring·mybatis·spring jdbc
JacksonMx10 小时前
CompletableFuture 生产环境踩坑详解与解决方案
spring boot·spring·线程池
小蒜学长10 小时前
vue旅游攻略网站(代码+数据库+LW)
java·数据库·vue.js·spring boot·后端·旅游
凤山老林10 小时前
轻量级规则引擎落地:Spring Boot 集成 LiteFlow 实现动态业务编排与热更新
java·spring boot·后端·规则引擎·liteflow
2602_9599609210 小时前
Java大厂面试实录:Spring Boot、Redis、Kafka、Elasticsearch、分布式事务与云原生高并发系统
java·jvm·spring boot·redis·面试题