使用MBG生成MyBatis代碼

基本

第一步:創建一個Maven項目:

  • 添加依賴:
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.11</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>
<dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.3.7</version>
</dependency>
  • 在build標籤下添加
<plugins>
    <plugin>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <version>1.4.0</version>
        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.11</version>
            </dependency>
        </dependencies>
        <configuration>
            <configurationFile>
                ${basedir}/src/main/resources/genCfg.xml
                <!--這裏是配置generatorConfig.xml的路徑 該文件默認在resources目錄下找generatorConfig.xml文件  -->
            </configurationFile>
            <!--允許移動生成的文件 -->
            <verbose>true</verbose>
            <!--允許覆蓋生成的文件 -->
            <overwrite>true</overwrite>
        </configuration>
    </plugin>
</plugins>
<!-- 指定Mapper XML文件在mybatis-config.xml中的配置有效-->
<resources>
    <resource>
        <directory>src/main/java</directory>
        <includes>
            <include>**/*.xml</include>
        </includes>
    </resource>
</resources>

第二步:在resources目錄中創建屬性文件mysql.properties:

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1/test?useSSL=false&serverTimezone=CST
username=root
password=root

第三步:在resources目錄下建立 genCfg.xml,作爲mybatis-generator-maven-plugin 插件執行的配置文件:

<?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 url="file:///E:\Workspaces\MyBatis\MybatisGeneratorDemo\src\main\resources\mysql.properties"/>
    <context id="default" targetRuntime="MyBatis3">
        <!-- 自動識別數據庫關鍵字,默認false。如果設置爲true,根據SqlReservedWords中定義的關鍵字列表;一般保留默認值,遇到數據庫關鍵字(Java關鍵字),使用columnOverride覆蓋 -->
        <property name="autoDelimitKeywords" value="false"/>
        <!-- 生成的Java文件的編碼-->
        <property name="javaFileEncoding" value="UTF-8"/>
        <!-- 格式化java代碼-->
        <property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/>
        <!-- 格式化XML代碼-->
        <property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/>
        <!--beginningDelimiter和endingDelimiter:指明數據庫的用於標記數據庫對象名的符號,比如ORACLE就是雙引號,MYSQL默認是`反引號; -->
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>

        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
        <plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin"/>
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
        <!--   ②  -->
        <commentGenerator >   <!--  ③  -->
            <property name="suppressDate" value="true"/>
            <!-- 是否去除自動生成的註釋 true:是 : false:否 -->
            <property name="suppressAllComments" value="false"/>
            <property name="addRemarkComments" value="true"/>
        </commentGenerator>
        
        <!--數據庫鏈接URL,用戶名、密碼 -->
        <jdbcConnection driverClass="${driver}" connectionURL="${url}"
                        userId="${username}" password="${password}">
            <!-- property屬性會設置到配置的Driver上-->
            <property name="useInformationSchema" value="true"/><!-- 針對mysql數據庫 -->
        </jdbcConnection>
        <!-- 非必需,類型處理器,在數據庫類型和java類型之間的轉換控制-->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <!-- 生成實體類-->
        <javaModelGenerator targetPackage="com.hc.bean" targetProject="src/main/java">
            <!--  是否生成構造方法 -->
            <property name="constructorBased" value="false"/>
            <!-- 是否允許子包 -->
            <property name="enableSubPackages" value="false"/>
            <!-- 如果爲true,則創建一個沒有setter只有構造方法的類 -->
            <property name="immutable" value="false"/>
            <!-- 設置是否在getter方法中,對String類型字段調用trim()方法 -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- 生成映射文件-->
        <sqlMapGenerator targetPackage="com.hc.dao.mapping" targetProject="src/main/java">
            <!-- 允許子包 -->
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!-- 生成DAO類-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.hc.dao" targetProject="src/main/java">
            <!-- 允許子包 -->
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!-- 要生成的表 tableName是數據庫中的表名或視圖名 domainObjectName是實體類名-->

        <table tableName="tb_emp" domainObjectName="Emp" mapperName="EmpDao"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false" enableSelectByPrimaryKey="true"
               enableUpdateByPrimaryKey="true" enableDeleteByPrimaryKey="true">
        </table>

        <table tableName="tb_dept" domainObjectName="Dept" mapperName="DeptDao"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false" enableSelectByPrimaryKey="true"
               enableUpdateByPrimaryKey="true" enableDeleteByPrimaryKey="true">
        </table>
    </context>
</generatorConfiguration>

說明: 如果想要生成數據庫下面所有的表:

<table tableName="%" enableCountByExample="false"
       enableUpdateByExample="false" enableDeleteByExample="false"
       enableSelectByExample="false" selectByExampleQueryId="false"/>

第四步:採用圖形化的方式利用MBG產生代碼
依次點擊Maven Project—項目——Plugins——mybatis generator——Run Maven build,如下圖所示:
在這裏插入圖片描述

改進

自定義代碼生成器程序執行入口

MBG採用圖形化生成時會出現莫名其妙的問題,比如如果數據庫中的表的名字爲tb_admin時會會生成一堆莫名其妙的代碼,所以建議通過程序生成代碼而不是通過採用圖形化的方式。在項目中按如下所示的代碼創建程序執行入口類:

public class MBGGenerator {
    public static void main( String[] args ) throws Exception {
        List<String> warnings = new ArrayList<>();
        String path = Generator.class.getResource("/").getPath();
        File configFile = new File(path+"genCfg.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration cfg = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(true);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(cfg, callback, warnings);
        myBatisGenerator.generate(null);
    }
}

生成正確的代碼註釋

查看生成代碼中的實體類,發現儘管數據庫中表及字段都有註釋,但生成的實體類中出現了一大堆莫名其妙的英文信息。要想生成正確的代碼註釋:
第一步:按如下所示在com.hc.gen包下提供註釋工具類

public class BeanCommentsGen implements CommentGenerator {
    private Properties properties;
    private Properties systemPro;
    private boolean suppressDate;
    private boolean suppressAllComments;
    private String currentDateStr;

    public BeanCommentsGen() {
        properties = new Properties();
    }

    @Override
    public void addConfigurationProperties(Properties properties) {
// 獲取自定義的 properties
        this.properties.putAll(properties);
    }

    @Override
    public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        String author = properties.getProperty("author");
        String dateFormat = properties.getProperty("dateFormat", "yyyy-MM-dd");
        SimpleDateFormat dateFormatter = new SimpleDateFormat(dateFormat);
// 獲取表註釋
        String remarks = introspectedTable.getRemarks();
        topLevelClass.addJavaDocLine("/**");
        topLevelClass.addJavaDocLine(" * " + remarks);
        topLevelClass.addJavaDocLine(" *");
        topLevelClass.addJavaDocLine(" * @author " + author);
        topLevelClass.addJavaDocLine(" * @date " + dateFormatter.format(new Date()));
        topLevelClass.addJavaDocLine(" */");
    }

    @Override
    public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
// 獲取列註釋
        String remarks = introspectedColumn.getRemarks();
        field.addJavaDocLine("/**");
        field.addJavaDocLine(" * " + remarks);
        field.addJavaDocLine(" */");
    }

    @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().replace("\n", " "));
        field.addJavaDocLine(" */");
    }

    @Override
    public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
        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(" */");
    }

    @Override
    public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) {
    }

    @Override
    public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) {
    }

    @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.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(" */");
    }

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

    @Override
    public void addJavaFileComment(CompilationUnit compilationUnit) {
    }

    @Override
    public void addComment(XmlElement xmlElement) {
    }

    @Override
    public void addRootComment(XmlElement rootElement) {
    }

    @Override
    public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable,
                                           Set<FullyQualifiedJavaType> imports) {
    }

    @Override
    public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable,
                                           IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) {
    }

    @Override
    public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable,
                                   Set<FullyQualifiedJavaType> imports) {
    }

    @Override
    public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable,
                                   IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) {
    }

    @Override
    public void addClassAnnotation(InnerClass innerClass, IntrospectedTable introspectedTable,
                                   Set<FullyQualifiedJavaType> imports) {
    }
}

第二步:將genCfg文件中編號③處的代碼替換成如下所示的內容:

<commentGenerator type="com.tiku.utils.BeanCommentsGen">
    <property name="author" value="HC"/>
    <property name="dateFormat" value="yyyy-MM-dd"/>
</commentGenerator>

第三步:運行MBGGenerator 程序,發現在項目中生成了實體類、DAO接口以及映射文件的代碼,如下圖所示:
在這裏插入圖片描述
查看發現生成的DAO接口以及映射文件中沒有註釋了,最重要的是實體類的註釋符合也我們要求了

生成正確的Mapper文件

自定義生成正確的代碼註釋後,又發現Mapper文件中的代碼出錯了,生成了兩次。我們採用如下步驟解決這個問題:
第一步:按如下所示在com.hc.gen包下編寫代碼:

public class OverIsMergeablePlugin extends PluginAdapter {
    @Override
    public boolean validate(List<String> warnings) {
        return true;
    }
    @Override
    public boolean sqlMapGenerated(GeneratedXmlFile sqlMap, IntrospectedTable it) {
        try {
            Field field = sqlMap.getClass().getDeclaredField("isMergeable");
            field.setAccessible(true);
            field.setBoolean(sqlMap, false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }
}

第二步:在genCfg.xml文件中代碼②處添加如下代碼:

<plugin type="com.hc.gen.OverIsMergeablePlugin"/>

再次運行MBGGenerator類的main方法發現生成的DAO接口以及映射文件中和實體類都符合也我們要求了。

測試

第一步:創建MyBatis配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--引入外部properties文件  -->
    <properties resource="mysql.properties"></properties>
    <settings>
        <!-- 打印查詢語句 -->
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">  <!-- 數據源的配置,連接到數據庫 -->
                <property name="driver" value="${driver}" />
                <property name="url" value="${url}"/>
                <property name="username" value="${username}" />
                <property name="password" value="${password}" />
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/hc/dao/mapping/DeptDao.xml"/>
    </mappers>
</configuration>

第二步:創建MyBatis工具類

public class MyBatisUtil {
	private static String CONFIG_FILE_LOCATION = "mybatis-cfg.xml";
	private static final ThreadLocal<SqlSession> threadLocal = new 
													ThreadLocal<SqlSession>();
    private static SqlSessionFactory sessionFactory;
    
    static {
    		try {
			Reader reader=Resources.getResourceAsReader(CONFIG_FILE_LOCATION);
			SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
			sessionFactory=builder.build(reader);
		} catch (Exception e) {
			e.printStackTrace();
		}
    }
    
    public static SqlSession getSession() {
    		SqlSession  session = threadLocal.get();
		if (session == null) {
			session = (sessionFactory!=null) ? sessionFactory.openSession() : null;
			threadLocal.set(session);
		}
        return session;
    }
    public static void closeSession()  {
    	   SqlSession session = threadLocal.get();
        if (session != null) {
            session.close();
  		   threadLocal.set(null);
        }
    }
}

第三步:測試代碼

public class DeptMapperTest {

    private SqlSession session;
    private  DeptDao mapper;
    @Before
    public void before(){
          session = MyBatisUtil.getSession();
          mapper = session.getMapper(DeptDao.class);
    }
    @After
    public void after(){
        session.commit();
    }
    @Test
    public void deleteByPrimaryKey() {
        int res = mapper.deleteByPrimaryKey((byte) 46);
        System.out.println(res);
    }

    @Test
    public void insert() {
        Dept dept = new Dept((byte)1,"aa","aaaaaaaaaaa");
        int res = mapper.insert(dept);
        System.out.println(res);
    }

    @Test
    public void insertSelective() {
        Dept dept = new Dept();
        dept.setDname("abcd");
        int res = mapper.insertSelective(dept);
        System.out.println(res);
    }

    @Test
    public void selectByPrimaryKey() {
        Dept dept = mapper.selectByPrimaryKey((byte) 10);
        System.out.println(dept);
    }

    @Test
    public void updateByPrimaryKeySelective() {
        Dept dept = new Dept();
        dept.setDeptno((byte)40);
        dept.setDname("abc");
        int res = mapper.updateByPrimaryKeySelective(dept);
        System.out.println(res);
    }

    @Test
    public void updateByPrimaryKey() {
//        Dept dept = new Dept();
//        dept.setDeptno((byte)47);
//        dept.setDname("asdf");
//        int res = mapper.updateByPrimaryKey(dept);
        System.out.println(3/0);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章