最近做项目,ORM 使用的是 MyBatis,为了偷懒,我自然而然的想到了使用 MyBatis Generator(MBG)来生成数据库表对应的实体代码和 Mapper 代码。于是做了如下的配置(对 MBG 配置不熟悉的同学可以参考 Mybatis Generator最完整配置详解):
<?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>
<!-- 指定数据库驱动的jdbc驱动jar包的位置 -->
<classPathEntry location="./mysql-connector-java-5.1.40.jar" />
<context id="mysql" defaultModelType="hierarchical" targetRuntime="MyBatis3Simple" >
<!-- 生成的 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"/>
<!-- 配置数据库连接 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8" userId="root" password="123456">
</jdbcConnection>
<!-- 生成实体的位置 -->
<javaModelGenerator targetPackage="me.mizhoux.model" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaModelGenerator>
<!-- 生成 Mapper 接口的位置 -->
<sqlMapGenerator targetPackage="me.mizhoux.mapper" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成 Mapper XML 的位置 -->
<javaClientGenerator targetPackage="me.mizhoux.mapper" type="XMLMAPPER" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 设置数据库的表名和实体类名 -->
<table tableName="t_user" domainObjectName="User">
<!-- generatedKey用于生成生成主键的方法 -->
<generatedKey column="id" sqlStatement="SELECT LAST_INSERT_ID()"/>
</table>
</context>
</generatorConfiguration>
数据库建库建表的代码:
CREATE SCHEMA `db_test` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ;
CREATE TABLE `db_test`.`t_user` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '用户 ID',
`username` VARCHAR(30) NULL COMMENT '用户名称',
`password` VARCHAR(20) NULL COMMENT '用户密码',
`birthday` DATE NULL COMMENT '用户生日',
PRIMARY KEY (`id`),
UNIQUE INDEX `username_UNIQUE` (`username` ASC)
) COMMENT = '用户';
开开心心,执行命令,开始生成代码:
java -jar mybatis-generator-core-1.3.7.jar -configfile generatorConfig.xml -overwrite
然后查看生成的 Java 实体类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tgBb4K4I-1659077096089)(https://segmentfault.com/img/bVbhvhV?w=718&h=500)]
看着这个注释,让我有点纠结啊 —— 为什么不是数据库中每个字段对应的注释呢?查找相关资料,得知 MBG 生成的是由 org.mybatis.generator.api.CommentGenerator
来控制的。这是一个接口,MBG 的默认实现类是 org.mybatis.generator.internal.DefaultCommentGenerator
。当你在 generatorConfig.xml
中配置了 commentGenerator
标签,那么默认状态下,生成注释的工作,将由 DefaultCommentGenerator
来完成。 所以我们来查看下这个 DefaultCommentGenerator
的源码:
public class DefaultCommentGenerator implements CommentGenerator {
// 属性,即配置在 commentGenerator 标签之内的 Property 标签
private Properties properties;
// 是否不生成日期
private boolean suppressDate;
// 是否不生成注释
private boolean suppressAllComments;
// 是否添加数据库内的注释
private boolean addRemarkComments;
// 日期的格式
private SimpleDateFormat dateFormat;
public DefaultCommentGenerator() {
super();
properties = new Properties();
suppressDate = false;
suppressAllComments = false;
addRemarkComments = false;
}
@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));
addRemarkComments = isTrue(properties
.getProperty(PropertyRegistry.COMMENT_GENERATOR_ADD_REMARK_COMMENTS));
String dateFormatString = properties.getProperty(PropertyRegistry.COMMENT_GENERATOR_DATE_FORMAT);
if (StringUtility.stringHasValue(dateFormatString)) {
dateFormat = new SimpleDateFormat(dateFormatString);
}
}
// 其他代码
...
}
addRemarkComments
这个属性,看来就是用来生成数据库注释用的 —— 好开心,那把它设置为 true
试试:
<generatorConfiguration>
<!-- 指定数据库驱动的jdbc驱动jar包的位置 -->
<classPathEntry location="./mysql-connector-java-5.1.40.jar" />
<context id="mysql" defaultModelType="hierarchical" targetRuntime="MyBatis3Simple" >
<property name="javaFileEncoding" value="UTF-8"/>
<!-- 其他 Property -->
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="addRemarkComments" value="true"/>
</commentGenerator>
...
</context>
</generatorConfiguration>
运行命令:
java -jar mybatis-generator-core-1.3.7.jar -configfile generatorConfig.xml -overwrite
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8KqK5brs-1659077096090)(https://segmentfault.com/img/bVbhvhX?w=705&h=711)]
数据库注释倒是拿到了,但是生成的一堆其他信息,看着实在是太扎眼了。查看源码,发现这些内容已经写死在 DefaultCommentGenerator
中了,没有办法自定义。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ooc3Aoao-1659077096091)(https://segmentfault.com/img/bVbhvik?w=527&h=356)]
自己动手丰衣足食,我们为啥不自己写个类实现 CommentGenerator
接口,然后自定义自己想要的注释呢。查看 commentGenerator
的 DTD,发现正好 commentGenerator
有个 type
属性,可以用来指定自己的注释实现类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eyhtCWKb-1659077096091)(https://segmentfault.com/img/bVbhvio?w=419&h=67)]
观察 CommentGenerator
接口,发现里面的方法非常多,不仅包含了生成 Java 实体注释对应的方法,还包括了生成 XML 中注释的方法。所以我们先写一个默认的实现类,实现CommentGenerator
接口,但不做任何操作 —— 因为 DefaultCommentGenerator
本文已经存在了,为了避免混淆,就叫它EmptyCommentGenerator
吧。然后定义我们自己的注释类,MySQLCommentGenerator
,继承 EmptyCommentGenerator
,重写我们需要的方法:
public class MySQLCommentGenerator extends EmptyCommentGenerator {
private Properties properties;
public MySQLCommentGenerator() {
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(" */");
}
}
因为我们现在要使用到我们自己自定义的 CommentGenerator
,所以我们 通过代码的方式来操作 MBG:
public class Generator {
public static void main( String[] args ) throws Exception {
List<String> warnings = new ArrayList<>();
File configFile = new File("generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(true);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
}
然后配置 generatorConfig.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>
<!-- 指定数据库驱动的jdbc驱动jar包的位置 -->
<!-- 不再需要,因为 jar 包已经在 classpath 中
<classPathEntry location="./mysql-connector-java-5.1.40.jar" />
-->
<context id="mysql" defaultModelType="hierarchical" targetRuntime="MyBatis3Simple" >
...
<!-- 自定义注释生成器 -->
<commentGenerator type="me.mizhoux.mbgcomment.MySQLCommentGenerator">
<property name="author" value="Michael Chow"/>
<property name="dateFormat" value="yyyy/MM/dd"/>
</commentGenerator>
...
</context>
</generatorConfiguration>
完整的 Maven 项目在 我的 GitHub。现在,我们运行主类 Generator
,成功生成了数据库中的注释:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sqaCeWuG-1659077096092)(https://segmentfault.com/img/bVbhvh9?w=334&h=519)]
等等,好像有点不对劲!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zLhPxrN5-1659077096093)(https://segmentfault.com/img/bVbhvid?w=260&h=260)]
类的注释怎么没有了!
想来应该是 JDBC 连接 MySQL 的时候需要添加什么属性才能获取表的注释,上网查询,发现是 useInformationSchema
,需要将其设置为 true
(看来 MBG 给自己的 DefaultCommentGenerator
开了小灶):
<?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>
<context id="mysql" defaultModelType="hierarchical" targetRuntime="MyBatis3Simple" >
...
<!-- 自定义注释生成器 -->
<commentGenerator type="me.mizhoux.mbgcomment.MySQLCommentGenerator">
<property name="author" value="Michael Chow"/>
<property name="dateFormat" value="yyyy/MM/dd"/>
</commentGenerator>
<!-- 配置数据库连接 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8" userId="root" password="123456">
<!-- 设置 useInformationSchema 属性为 true -->
<property name="useInformationSchema" value="true" />
</jdbcConnection>
...
</context>
</generatorConfiguration>
然后再次运行主类 Generator
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rnXseUT3-1659077096093)(https://segmentfault.com/img/bVbhvii?w=328&h=511)]
成功的生成了类注释和字段注释~