Mybatis逆向工程(java 配置实现)

在网上查看的各种逆向工程的文章, 发现基本上都是用xml配置的方式实现的, 现在基本上项目都是使用java类方式实现xml配置, 所以整理下 纯java注解的实现方式, 一定要注意 java 代码的实现方式都是基于xml 所以本文开头先把xml注解添加进来比较,

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>
        <!-- 引入配置文件 -->  
    <properties resource="generator.properties"/> 
        <!-- 数据库驱动位置 --> 
    <classPathEntry location="${classPath}" />
        <!-- 一个数据库一个context, targetRuntime:此属性用于指定生成的代码的运行时环境 ,MyBatis3:*这是默认值*,MyBatis3Simple不生成Example查询(避免后面一个一个表设置)     defaultModelType:如何生成实体类,flat表示为每一张表生成一个实体类,推荐使用--> 
<context id="mysqlTables" targetRuntime="com.practice.mybatis.TkMyBatis3Impl" defaultModelType="flat">
        <!-- 注释  type表示自定义注释-->
    <commentGenerator type="com.practice.mybatis.MyCommentGenerator">
        <!-- 生成文件的编码 (eclipse插件的时候这里并没有什么卵用,需要在eclipse根目录的eclipse.ini最后添加 -Dfile.encoding=UTF-8  )-->
        <property name="javaFileEncoding" value="UTF-8"/>
        <!-- 是否取消注释 -->
        <property name="suppressAllComments" value="false" />
        <property name="addRemarkComments" value="true"/>
        <!-- 是否生成注释代时间戳 -->
        <property name="suppressDate" value="true" />
        <!-- 当表名或者字段名为SQL关键字的时候,可以设置该属性为true,MBG会自动给表名或字段名添加**分隔符**  -->    
        <property name="autoDelimitKeywords" value="true"></property>
        <!-- 由于beginningDelimiter和endingDelimiter的默认值为双引号("),在Mysql中不能这么写,所以还要将这两个默认值改为**反单引号(`)** -->
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>  
    </commentGenerator>
        <!-- 数据库的url、用户名、密码 --> 
    <jdbcConnection driverClass="${jdbc.driver}" 
        connectionURL="${jdbc.url}" 
        userId="${jdbc.user}" 
        password="${jdbc.password}">
    </jdbcConnection>
        <!-- 类型转换 --> 
    <javaTypeResolver >
        <!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) -->  
        <property name="forceBigDecimals" value="false" />
    </javaTypeResolver>
        <!-- 生成模型的包名和位置 -->
    <javaModelGenerator targetPackage="${package_domain}" targetProject="${project}">
        <!-- 是否在当前路径下新加一层schema,eg:fase路径com.goshop.domain", true:com.goshop.domain".[schemaName] -->
        <property name="enableSubPackages" value="false" />
        <!-- 是否针对string类型的字段在set的时候进行trim调用 -->
        <property name="trimStrings" value="true" />
    </javaModelGenerator>
        <!-- 生成的映射文件包名和位置 -->
    <sqlMapGenerator targetPackage="${package_mapper}"  targetProject="${resource}">
        <!-- 是否在当前路径下新加一层schema,eg:fase路径com.goshop.domain", true:com.goshop.domain".[schemaName] -->
        <property name="enableSubPackages" value="true" />
    </sqlMapGenerator>
        <!-- 生成DAO的包名和位置 type 1、ANNOTATEDMAPPER注解形式 2、XMLMAPPER xml配置文件形式-->
    <javaClientGenerator type="XMLMAPPER" targetPackage="${package_dao}"  targetProject="${project}">
        <property name="enableSubPackages" value="true" />
    </javaClientGenerator>
        <!-- 生成那些表 tableName表名 mapperName 生成dao的名称,domainObjectName应于数据库表的javaBean类名,enable*ByExample是否生成 example类 -->
        <!-- <table tableName="sys_user" domainObjectName="SysUser" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/> -->
            <!-- 忽略列,不生成bean 字段   
            <ignoreColumn column="FRED" />-->  
            <!-- 指定列的java数据类型   
            <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" />-->  
        <table tableName="%" mapperName="{0}DAO">
            <columnOverride column="remarks" jdbcType="VARCHAR" />
        </table>
</context>
</generatorConfiguration>

前期准备

首先pom添加依赖和插件

<dependencies>
    <dependency>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-core</artifactId>
        <version>1.3.7</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.3.7</version>
            <configuration>
                <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
                <verbose>true</verbose>
                <overwrite>true</overwrite>
            </configuration>
        </plugin>
    </plugins>
</build>

mybatis-generator-core

MyBatisGenerator

Mybatis 生成器主要接口, 使用的时候只需要创建类实例, 调用generate() 方法即可, 类中内置了大量属性

/** 自定义配置类 */
private Configuration configuration;

/** 回调. */
private ShellCallback shellCallback;

/**生成java文件. */
private List<GeneratedJavaFile> generatedJavaFiles;

/** 生成xml文件 */
private List<GeneratedXmlFile> generatedXmlFiles;

/** 警号信息. */
private List<String> warnings;

/** 项目信息. */
private Set<String> projects;

/**
 * Constructs a MyBatisGenerator object.
 * 
 * @param configuration
 *            The configuration for this invocation
 * @param shellCallback
 *            an instance of a ShellCallback interface. You may specify
 *            <code>null</code> in which case the DefaultShellCallback will
 *            be used.
 * @param warnings
 *            Any warnings generated during execution will be added to this
 *            list. Warnings do not affect the running of the tool, but they
 *            may affect the results. A typical warning is an unsupported
 *            data type. In that case, the column will be ignored and
 *            generation will continue. You may specify <code>null</code> if
 *            you do not want warnings returned.
 * @throws InvalidConfigurationException
 *             if the specified configuration is invalid
 */
public MyBatisGenerator(Configuration configuration, ShellCallback shellCallback,
        List<String> warnings) throws InvalidConfigurationException {
    super();
    if (configuration == null) {
        throw new IllegalArgumentException(getString("RuntimeError.2")); //$NON-NLS-1$
    } else {
        this.configuration = configuration;
    }

    if (shellCallback == null) {
        this.shellCallback = new DefaultShellCallback(false);
    } else {
        this.shellCallback = shellCallback;
    }

    if (warnings == null) {
        this.warnings = new ArrayList<String>();
    } else {
        this.warnings = warnings;
    }
    generatedJavaFiles = new ArrayList<GeneratedJavaFile>();
    generatedXmlFiles = new ArrayList<GeneratedXmlFile>();
    projects = new HashSet<String>();

    this.configuration.validate();
}

构造器方法只提供了一个构造, 传入三个参数的构造. 所以本文只关注这三个属性

Configuration

/** The contexts. */
private List<Context> contexts;

/** The class path entries. */
private List<String> classPathEntries;

Context

提供了大量的配置类, 包括JDBC连接配置类, Sql映射配置类, Java模型生成配置类等, 具体要如何配置要自己参考源码, 本文主要提供一种基础生成方式.

/**
 * The Class Context.
 *  * @author Jeff Butler
 */
public class Context extends PropertyHolder {
    
    /** The id. */
    private String id;

    /** The jdbc connection configuration. */
    private JDBCConnectionConfiguration jdbcConnectionConfiguration;
    
    private ConnectionFactoryConfiguration connectionFactoryConfiguration;

    /** The sql map generator configuration. */
    private SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration;

    /** The java type resolver configuration. */
    private JavaTypeResolverConfiguration javaTypeResolverConfiguration;

    /** The java model generator configuration. */
    private JavaModelGeneratorConfiguration javaModelGeneratorConfiguration;

    /** The java client generator configuration. */
    private JavaClientGeneratorConfiguration javaClientGeneratorConfiguration;

    /** The table configurations. */
    private ArrayList<TableConfiguration> tableConfigurations;

    /** The default model type. */
    private ModelType defaultModelType;

    /** The beginning delimiter. */
    private String beginningDelimiter = "\""; //$NON-NLS-1$

    /** The ending delimiter. */
    private String endingDelimiter = "\""; //$NON-NLS-1$

    /** The comment generator configuration. */
    private CommentGeneratorConfiguration commentGeneratorConfiguration;

    /** The comment generator. */
    private CommentGenerator commentGenerator;

    /** The plugin aggregator. */
    private PluginAggregator pluginAggregator;

    /** The plugin configurations. */
    private List<PluginConfiguration> pluginConfigurations;

    /** The target runtime. */
    private String targetRuntime;

    /** The introspected column impl. */
    private String introspectedColumnImpl;

    /** The auto delimit keywords. */
    private Boolean autoDelimitKeywords;
    
    /** The java formatter. */
    private JavaFormatter javaFormatter;
    
    /** The xml formatter. */
    private XmlFormatter xmlFormatter;
  ...(省略)

defaultModelType: 规定了实体生成的策略, 每一种对应了一种规则

  • hierarchical: 有主键, 生成单独主键实体类, 有blob, text类型, 生成一个包含所有BLOB, text字段的单独的实体类, 其他属性生成一个实体(HierarchicalModelRules)
  • conditional (默认值): 与hierarchical基本相同, 不同之处是当 表只有一个属性, 则只生成一个基本实体类(就算这个字段是主键, 也不生成主键实体类)(ConditionalModelRules)
  • flat: 每一张表只生成一个实体类。这个实体类包含表中的所有字段(FlatModelRules)

测试实现

package com.huntkey.rx.sceo.generator;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.*;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.util.ArrayList;
import java.util.List;

/**
 * @description: mybatis 逆向工程测试
 * @author: wangml
 * @date: 2021/7/24 09:31
 */
public class MybatisGeneratorTest {

    public static final String PROJECT_SOURCES_ROOT_DIR = "D:\\workspace\\HuntKey\\springbootDemo\\src\\main\\java";
    public static final String PROJECT_RESOURCES_ROOT_DIR = "D:\\workspace\\HuntKey\\springbootDemo\\src\\main\\resources";

    public static void main(String[] args) throws Exception {
        // 警告信息
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;

        Configuration config = new Configuration();
        // Mybatis实体生成策略(CONDITIONAL)
        Context context = new Context(ModelType.CONDITIONAL);
        context.setId("myTest");

        //是否将数据库的表和列的备注生成到实体中
        CommentGeneratorConfiguration commentGeneratorConfiguration = new CommentGeneratorConfiguration();
        // addRemarkComments 为 CommentGenerator存在的属性, 只是在java类中没有申明, 要自己去按需开启(不能定义不存在的属性)
        commentGeneratorConfiguration.addProperty("addRemarkComments", "true");
        context.setCommentGeneratorConfiguration(commentGeneratorConfiguration);

        //配置数据库连接
        JDBCConnectionConfiguration jdbcConnectionConfiguration = new JDBCConnectionConfiguration();
        jdbcConnectionConfiguration.setDriverClass("com.mysql.cj.jdbc.Driver");
        jdbcConnectionConfiguration.setConnectionURL("jdbc:mysql://localhost:3306/sceo?useSSL=true");
        jdbcConnectionConfiguration.setUserId("root");
        jdbcConnectionConfiguration.setPassword("root");
        context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration);

        //配置实体类生成策略
        JavaModelGeneratorConfiguration javaModelGeneratorConfiguration = new JavaModelGeneratorConfiguration();
        // 指定实体继承的父类(父类的属性在表中要存在)
//        javaModelGeneratorConfiguration.addProperty("rootClass", "com.huntkey.rx.sceo.core.repository.entity.ResourceEntity");
        //指定实体类所属的包名
        javaModelGeneratorConfiguration.setTargetPackage("com.huntkey.rx.sceo.entity");
        //指定工程的src目录
        javaModelGeneratorConfiguration.setTargetProject(PROJECT_SOURCES_ROOT_DIR);
        context.setJavaModelGeneratorConfiguration(javaModelGeneratorConfiguration);

        //配置Sql文件的生成策略
        SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = new SqlMapGeneratorConfiguration();
        sqlMapGeneratorConfiguration.setTargetPackage("mapper");
        sqlMapGeneratorConfiguration.setTargetProject(PROJECT_RESOURCES_ROOT_DIR);
        context.setSqlMapGeneratorConfiguration(sqlMapGeneratorConfiguration);

        //配置DAO接口的生成策略
        JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration();
        //接口实现方式:XMLMAPPER、MIXEDMAPPER、ANNOTATEDMAPPER
        javaClientGeneratorConfiguration.setConfigurationType("XMLMAPPER");
//        javaClientGeneratorConfiguration.addProperty("rootInterface", "com.huntkey.rx.sceo.core.repository.dao.Mapper");
        javaClientGeneratorConfiguration.setTargetPackage("com.huntkey.rx.sceo.dao");
        javaClientGeneratorConfiguration.setTargetProject(PROJECT_SOURCES_ROOT_DIR);
        context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);

        //生成实体的其他规则配置
        TableConfiguration tableConfiguration = new TableConfiguration(context);
        tableConfiguration.setDomainObjectName("User");
        //是否直接使用数据库列名作为属性名,false时会转驼峰
        tableConfiguration.setTableName("user_test");
        context.addTableConfiguration(tableConfiguration);

        config.addContext(context);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);
        System.out.println("success");
    }
}

运行main 就可在对应目录下得到生成的 java 文件

总结

  • xml注解的实现方法 和 java 配置的方法 都可以实现功能(xml的方式有很多博客)
  • 理解底层实现 才能方便我们驾驭代码, 使用时游刃有余

参考文章:
https://www.cnblogs.com/liaojie970/p/8029000.html
https://blog.csdn.net/wl_627292578/article/details/54895587

上一篇:从零开始学Mybatis(十二)——代码自动生成器


下一篇:错误 C4996 'xxx':This function or variable may be unsafe. Consider using xxx_s instead. To d