zoukankan      html  css  js  c++  java
  • MyBatis Generator的使用

    Mybatis Generator使用

    介绍

    使用MyBatis Generator (MBG) 可以减少重复代码工作量,自动根据数据库表的结构生成MyBatis的Model/Dao/XML。
    本文主要介绍MBG如何根据Oralce数据库表的结构生成相应文件的。同时通过MBG提供的插件扩展能力,实现两个插件,用于在生成的Model中包含数据库中定义的注释和添加Lombok注解。

    MBG官方说明文档

    项目结构

    本演示项目使用IDE为IDEA。首先创建一个简单的Maven工程。
    根据《IntelliJ IDEA 创建 Maven简单项目》创建Maven工程。

    项目结构预览:
    下面是使用MBG生成MyBatis中的Model(Pojo)/Dao/XML各层的最终项目结构。

    com.zqq.dao 存放生成的MyBatis数据库操作类
    com.zqq.pojo 存放与数据库表映射的数据库模型bean
    mappers/DemoPojoMapper.xml 存放与DAO包中的方法对应的sql操作语句文件

    配置文件(搭建Maven项目)

    使用MBG不需要依赖于Spring等框架,只需要依赖基本的MBG插件即可。但是由于是根据数据库表生成MyBatis操作对象,因此还需要配置数据库连接信息datasource.properties。同时,使用MBG时需要配置generatorConfig.xml文件。

    注意oracle驱动与jdk的关系 ojdbc7 对应jdk 7 8 https://download.csdn.net/download/panhaigang123/10757085

    //datasource.properties
    #下面配置的是Oracle数据库的连接信息,oracle url要使用域名:端口/实例
    #驱动本地路径
    db.driverLocation=D:\code\private\model_generator\src\main\tools\ojdbc7-12.1.0.2.jar
    #驱动类路径
    db.driverClassName=oracle.jdbc.driver.OracleDriver
    
    #数据库连接信息
    db.url=jdbc:oracle:thin:@host:1521/database
    db.username=xxx
    db.password=xxx
    
    //generatorConfig.xml
    <!--配置文件中的suppresscomment不要配置。type=MyCommentGenerator 要用全类名,否则可能找不到。多次执行generate,生成的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="datasource.properties"></properties>
    
        <!--指定特定数据库的jdbc驱动jar包的位置-->
        <classPathEntry location="${db.driverLocation}"/>
    
        <context id="default" targetRuntime="MyBatis3">
    
            <!--可选配置,使用自定义插件,通过注解使每次重复执行时覆盖原有的xml文件-->
            <!--<plugin type="OverIsMergeablePlugin"/>-->
            <!--可选配置,使用自定义插件,生成Lombok注解-->
            <plugin type="com.zqq.plugins.LombokPlugin">
                <property name="hasLombok" value="true"/>
            </plugin>
    
            <!-- 可选配置,旨在创建class时,对注释进行控制 -->
            <!--MyCommentGenerator实现了对字段添加注释功能-->
            <commentGenerator type="com.zqq.plugins.MyCommentGenerator">
    
                <!--<property name="suppressDate" value="true"/>-->
                <!--不能添加如下配置,否则无法生成注释-->
                <!--<property name="suppressAllComments" value="true"/>-->
            </commentGenerator>
    
            <!--jdbc的数据库连接 -->
            <jdbcConnection
                    driverClass="${db.driverClassName}"
                    connectionURL="${db.url}"
                    userId="${db.username}"
                    password="${db.password}">
                <property name="remarksReporting" value="true"></property>
            </jdbcConnection>
    
    
            <!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制-->
            <javaTypeResolver>
                <property name="forceBigDecimals" value="false"/>
            </javaTypeResolver>
    
    
            <!-- Model模型生成器,用来生成含有主键key的类,记录类 以及查询Example类
                targetPackage     指定生成的model生成所在的包名
                targetProject     指定在该项目下所在的路径
            -->
            <javaModelGenerator targetPackage="com.zqq.pojo" targetProject="./src/main/java">
                <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
                <property name="enableSubPackages" value="false"/>
                <!-- 是否对model添加 构造函数 当immutable为false时,此处设置才有效-->
                <property name="constructorBased" value="false"/>
                <!-- 是否对类CHAR类型的列的数据进行trim操作 -->
                <property name="trimStrings" value="true"/>
                <!-- 建立的Model对象是否 不可改变  即生成的Model对象不会有 setter方法,只有构造方法 -->
                <!--该属性用来配置实体类属性是否可变,如果设置为true,那么constructorBased不管设置成什么,都会使用构造方法入参,并且不会生成setter方法。如果为false,实体类属性就可以改变。默认为false。-->
                <property name="immutable" value="false"/>
            </javaModelGenerator>
    
            <!--mapper映射文件生成所在的目录 为每一个数据库的表生成对应的SqlMap文件 -->
            <sqlMapGenerator targetPackage="mappers" targetProject="./src/main/resources">
                <property name="enableSubPackages" value="false"/>
            </sqlMapGenerator>
    
            <!-- 客户端代码,生成易于使用的针对Model对象和XML配置文件 的代码
                    type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象
                    type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象
                    type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口
            -->
    
            <!-- targetPackage:mapper接口dao生成的位置 -->
            <javaClientGenerator type="XMLMAPPER" targetPackage="com.zqq.dao" targetProject="./src/main/java">
                <!-- enableSubPackages:是否让schema作为包的后缀 -->
                <property name="enableSubPackages" value="false"/>
            </javaClientGenerator>
    
            <!--需要生成相应MyBatis操作dao/pojo/xml的数据库表以及映射的pojo-->
            <table tableName="DEMO_TABLE" domainObjectName="DemoPojo"
                   enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
                   enableSelectByExample="false" selectByExampleQueryId="false"></table>
    
          
        </context>
    </generatorConfiguration>
    

    POM配置

    下面给出pom.xml的配置。MBG要用1.3.3及以后版本 否则无法生成类注释addModelClassComment。

    <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/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com</groupId>
        <artifactId>MBG</artifactId>
        <packaging>war</packaging>
        <version>1.0-SNAPSHOT</version>
        <name>MBG DEMO</name>
        <url>http://maven.apache.org</url>
    
    
        <dependencies>
            <dependency>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-core</artifactId>
                <version>1.3.5</version>
            </dependency>
        </dependencies>
    
        <build>
            <finalName>mmall</finalName>
            <plugins>
                <plugin>
                    <groupId>org.mybatis.generator</groupId>
                    <artifactId>mybatis-generator-maven-plugin</artifactId>
                    <version>1.3.5</version>
                    <configuration>
                        <verbose>true</verbose>
                        <overwrite>true</overwrite>
                    </configuration>
                </plugin>
    
            </plugins>
    
        </build>
        
    </project>
    
    

    自定义插件

    MBG提供的插件的扩展类PluginAdapter,可以实现自己需要的特定功能。需要注意的是,MBG不同的版本提供的接口是不同的。下面分别给出,三个自定义插件的实现。

    LombokPlugin

    该插件提供了在生成的POJO上面添加Lombok注解。

    package com.zqq.plugins;
    
    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.Interface;
    import org.mybatis.generator.api.dom.java.Method;
    import org.mybatis.generator.api.dom.java.TopLevelClass;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.List;
    
    
    public class LombokPlugin extends PluginAdapter
    {
    
        @Override
        public boolean validate(List<String> list)
        {
            return true;
        }
    
        @Override
        public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable)
        {
            //添加domain的import
            topLevelClass.addImportedType("lombok.Data");
            topLevelClass.addImportedType("lombok.Builder");
            topLevelClass.addImportedType("lombok.NoArgsConstructor");
            topLevelClass.addImportedType("lombok.AllArgsConstructor");
    
            //添加domain的注解
            topLevelClass.addAnnotation("@Data");
            topLevelClass.addAnnotation("@Builder");
            topLevelClass.addAnnotation("@NoArgsConstructor");
            topLevelClass.addAnnotation("@AllArgsConstructor");
            return true;
        }
    
        @Override
        public boolean modelSetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType)
        {
            //不生成getter
            return false;
        }
    
        @Override
        public boolean modelGetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType)
        {
            //不生成setter
            return false;
        }
    
        private String date2Str(Date date)
        {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
            return sdf.format(date);
        }
    }
    
    

    MyCommentGenerator

    原生的MBG无法将数据库中的表注释及字段注释添加到生成的POJO的类或字段上。该插件可以提供该能力生成Oracle或MySQL数据库表及字段的注释。

    package com.zqq.plugins;
    
    import static org.mybatis.generator.internal.util.StringUtility.isTrue;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Properties;
    import java.util.Set;
    
    import org.mybatis.generator.api.CommentGenerator;
    import org.mybatis.generator.api.IntrospectedColumn;
    import org.mybatis.generator.api.IntrospectedTable;
    import org.mybatis.generator.api.dom.java.*;
    import org.mybatis.generator.api.dom.xml.XmlElement;
    import org.mybatis.generator.config.MergeConstants;
    import org.mybatis.generator.config.PropertyRegistry;
    import org.mybatis.generator.internal.util.StringUtility;
    
    public class MyCommentGenerator implements CommentGenerator
    {
    
        private Properties properties;
        private Properties systemPro;
        private boolean suppressDate;
        private boolean suppressAllComments;
        private String currentDateStr;
    
        public MyCommentGenerator()
        {
            super();
            properties = new Properties();
            systemPro = System.getProperties();
            suppressDate = false;
            suppressAllComments = false;
            currentDateStr = (new SimpleDateFormat("yyyy-MM-dd")).format(new Date());
        }
    
        @Override
        public void addJavaFileComment(CompilationUnit compilationUnit)
        {
            // add no file level comments by default
            return;
        }
    
        /**
         * Adds a suitable comment to warn users that the element was generated, and
         * when it was generated.
         */
        @Override
        public void addComment(XmlElement xmlElement)
        {
            return;
        }
    
        @Override
        public void addRootComment(XmlElement rootElement)
        {
            // add no document level comments by default
            return;
        }
    
        @Override
        public void addConfigurationProperties(Properties properties)
        {
            this.properties.putAll(properties);
    
            suppressDate = isTrue(properties.getProperty(PropertyRegistry.COMMENT_GENERATOR_SUPPRESS_DATE));
    
            suppressAllComments = isTrue(properties.getProperty(PropertyRegistry.COMMENT_GENERATOR_SUPPRESS_ALL_COMMENTS));
        }
    
        /**
         * This method adds the custom javadoc tag for. You may do nothing if you do
         * not wish to include the Javadoc tag - however, if you do not include the
         * Javadoc tag then the Java merge capability of the eclipse plugin will
         * break.
         *
         * @param javaElement the java element
         */
        protected void addJavadocTag(JavaElement javaElement, boolean markAsDoNotDelete)
        {
            javaElement.addJavaDocLine(" *");
            StringBuilder sb = new StringBuilder();
            sb.append(" * ");
            sb.append(MergeConstants.NEW_ELEMENT_TAG);
            if (markAsDoNotDelete)
            {
                sb.append(" do_not_delete_during_merge");
            }
            String s = getDateString();
            if (s != null)
            {
                sb.append(' ');
                sb.append(s);
            }
            javaElement.addJavaDocLine(sb.toString());
        }
    
        /**
         * This method returns a formated date string to include in the Javadoc tag
         * and XML comments. You may return null if you do not want the date in
         * these documentation elements.
         *
         * @return a string representing the current timestamp, or null
         */
        protected String getDateString()
        {
            String result = null;
            if (!suppressDate)
            {
                result = currentDateStr;
            }
            return result;
        }
    
        @Override
        public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable)
        {
            if (suppressAllComments)
            {
                return;
            }
            StringBuilder sb = new StringBuilder();
            innerClass.addJavaDocLine("/**");
            sb.append(" * ");
            sb.append(introspectedTable.getFullyQualifiedTable());
            sb.append(" ");
            sb.append(getDateString());
            innerClass.addJavaDocLine(sb.toString());
            innerClass.addJavaDocLine(" */");
        }
    
        @Override
        public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable)
        {
            if (suppressAllComments)
            {
                return;
            }
    
            StringBuilder sb = new StringBuilder();
    
            innerEnum.addJavaDocLine("/**");
            //		addJavadocTag(innerEnum, false);
            sb.append(" * ");
            sb.append(introspectedTable.getFullyQualifiedTable());
            innerEnum.addJavaDocLine(sb.toString());
            innerEnum.addJavaDocLine(" */");
        }
    
        /**
         * 添加字段注释
         *
         * @param field
         * @param introspectedTable
         * @return
         * @throws
         * @auther 
         * @since 11:58 2019/1/9
         */
        @Override
        public void addFieldComment(Field field, IntrospectedTable introspectedTable)
        {
            if (suppressAllComments)
            {
                return;
            }
    
            StringBuilder sb = new StringBuilder();
    
            field.addJavaDocLine("/**");
            sb.append(" * ");
            sb.append(introspectedTable.getFullyQualifiedTable());
            field.addJavaDocLine(sb.toString());
            field.addJavaDocLine(" */");
        }
    
        //字段添加ApiModelProperty
        @Override
        public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn)
        {
            if (suppressAllComments)
            {
                return;
            }
    
            StringBuilder sb = new StringBuilder();
    
            field.addJavaDocLine("/**");
            sb.append(" * ");
            sb.append(introspectedColumn.getRemarks());
            field.addJavaDocLine(sb.toString());
    
            //		addJavadocTag(field, false);
    
            field.addJavaDocLine(" */");
            StringBuilder sb1 = new StringBuilder();
            //@ApiModelProperty(name = "approveStatus", notes = "审批状态")
            sb1.append("@ApiModelProperty").append("(name = "").append(field.getName())
                    .append("" , notes = "").append(introspectedColumn.getRemarks())
                    .append("")");
            System.out.println(sb1.toString());
            field.addJavaDocLine(sb1.toString());
        }
    
        @Override
        public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable)
        {
            if (suppressAllComments)
            {
                return;
            }
            //		method.addJavaDocLine("/**");
            //		addJavadocTag(method, false);
            //		method.addJavaDocLine(" */");
        }
    
        @Override
        public void addGetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn)
        {
            if (suppressAllComments)
            {
                return;
            }
    
            method.addJavaDocLine("/**");
    
            StringBuilder sb = new StringBuilder();
            sb.append(" * ");
            sb.append(introspectedColumn.getRemarks());
            method.addJavaDocLine(sb.toString());
    
            sb.setLength(0);
            sb.append(" * @return ");
            sb.append(introspectedColumn.getActualColumnName());
            sb.append(" ");
            sb.append(introspectedColumn.getRemarks());
            method.addJavaDocLine(sb.toString());
    
            //		addJavadocTag(method, false);
    
            method.addJavaDocLine(" */");
        }
    
        @Override
        public void addSetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn)
        {
            if (suppressAllComments)
            {
                return;
            }
    
    
            method.addJavaDocLine("/**");
            StringBuilder sb = new StringBuilder();
            sb.append(" * ");
            sb.append(introspectedColumn.getRemarks());
            method.addJavaDocLine(sb.toString());
    
            Parameter parm = method.getParameters().get(0);
            sb.setLength(0);
            sb.append(" * @param ");
            sb.append(parm.getName());
            sb.append(" ");
            sb.append(introspectedColumn.getRemarks());
            method.addJavaDocLine(sb.toString());
    
            //		addJavadocTag(method, false);
    
            method.addJavaDocLine(" */");
        }
    
        /**
         * 内部类的注释
         *
         * @param innerClass
         * @param introspectedTable
         * @param markAsDoNotDelete
         * @return
         * @throws
         * @auther 
         * @since 11:59 2019/1/9
         */
    
        @Override
        public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete)
        {
            if (suppressAllComments)
            {
                return;
            }
    
            StringBuilder sb = new StringBuilder();
    
            innerClass.addJavaDocLine("/**");
            sb.append(" * ");
            sb.append(introspectedTable.getFullyQualifiedTable());
            innerClass.addJavaDocLine(sb.toString());
    
            sb.setLength(0);
            sb.append(" * @author ");
            sb.append(systemPro.getProperty("user.name"));
            sb.append(" ");
            sb.append(currentDateStr);
    
            //		addJavadocTag(innerClass, markAsDoNotDelete);
    
            innerClass.addJavaDocLine(" */");
        }
    
        /**
         * 获取表注释,设置到Bean注释
         *
         * @param topLevelClass
         * @param introspectedTable
         * @return
         * @throws
         * @auther 
         * @since 11:57 2019/1/9
         */
        @Override
        public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable)
        {
    
            topLevelClass.addJavaDocLine("/**");
    
            String remarks = introspectedTable.getRemarks();
            if (StringUtility.stringHasValue(remarks))
            {
                String[] remarkLines = remarks.split(System.getProperty("line.separator"));
                for (String remarkLine : remarkLines)
                {
                    topLevelClass.addJavaDocLine(" * " + remarkLine);
                }
            }
    
            //        topLevelClass.addJavaDocLine(" * ");
            StringBuilder sb = new StringBuilder();
            sb.append(" * ");
            sb.append(introspectedTable.getFullyQualifiedTable());
            topLevelClass.addJavaDocLine(sb.toString());
    //        topLevelClass.addJavaDocLine(" *");
    //        addJavadocTag(topLevelClass, false);
            topLevelClass.addJavaDocLine(" */");
    
        }
    
    }
    

    OverIsMergeablePlugin

    该插件用于解决多次执行generate,生成的xml只能追加无法覆盖问题。一般情况下不需要多次执行generate操作。

    package com.zqq.plugins;
    
    import org.mybatis.generator.api.GeneratedXmlFile;
    import org.mybatis.generator.api.IntrospectedTable;
    import org.mybatis.generator.api.PluginAdapter;
    
    import java.lang.reflect.Field;
    import java.util.List;
    
    /**
     * 解决生成xml无法覆盖只能追加的问题
     *
     * @author 
     * @version v1.0
     * @since 13:42 2019/1/9
     */
    public class OverIsMergeablePlugin extends PluginAdapter
    {
        @Override
        public boolean validate(List<String> warnings)
        {
            return true;
        }
    
        @Override
        public boolean sqlMapGenerated(GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable)
        {
            try
            {
                Field field = sqlMap.getClass().getDeclaredField("isMergeable");
                field.setAccessible(true);
                field.setBoolean(sqlMap, false);
            } catch (Exception e)
            {
                e.printStackTrace();
            }
            return true;
        }
    }
    
    

    生成

    MBG启动可以直接通过mybatis-generator:generate命令执行,也可以直接通过main方法执行。下面给出main方法执行的方式。

    package com.zqq;
    
    import org.mybatis.generator.api.MyBatisGenerator;
    import org.mybatis.generator.config.Configuration;
    import org.mybatis.generator.config.xml.ConfigurationParser;
    import org.mybatis.generator.exception.InvalidConfigurationException;
    import org.mybatis.generator.exception.XMLParserException;
    import org.mybatis.generator.internal.DefaultShellCallback;
    
    import java.io.File;
    import java.io.IOException;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    
    public class App
    {
    
    
        public static void main(String[] args)
        {
            List<String> warnings = new ArrayList<String>();
            try
            {
                // true:生成的文件覆盖之前的
                boolean overwrite = true;
                // 读取配置,构造 Configuration 对象.
                // 如果不想使用配置文件的话,也可以直接来 new Configuration(),然后给相应属性赋值.
                File configFile = new File("./src/main/resources/generatorConfig.xml");
                ConfigurationParser cp = new ConfigurationParser(warnings);
                // Configuration config = cp.parseConfiguration(App.class.getClassLoader().getResourceAsStream("generatorConfig.xml"));
                Configuration config = cp.parseConfiguration(configFile);
                DefaultShellCallback callback = new DefaultShellCallback(overwrite);
                MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
                myBatisGenerator.generate(null);
            } catch (SQLException e)
            {
                e.printStackTrace();
            } catch (IOException e)
            {
                e.printStackTrace();
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            } catch (InvalidConfigurationException e)
            {
                e.printStackTrace();
            } catch (XMLParserException e)
            {
                e.printStackTrace();
            }
        }
    
    }
    

    项目工程文件

    MyBatisGeneratorDemo

    参考资料
    Mybatis Generator的model生成中文注释,支持oracle和mysql

  • 相关阅读:
    git cmd 命令在已有的仓库重新添加新的文件夹
    google guava Multimap的学习介绍
    JavaScript笔记基础版
    初识hive
    深入学习HBase架构原理
    初识Azkaban
    MapReduce工作流多种实现方式
    Hive 分组问题
    sqoop使用中的小问题
    Sqoop 结合多种系统的具体应用
  • 原文地址:https://www.cnblogs.com/z00377750/p/10355610.html
Copyright © 2011-2022 走看看