SpringBoot(十一):springboot2.0.2下配置mybatis generator环境,并自定义字段/getter/settetr注释
Mybatis Generator是供开发者在mybatis开发时,快速构建mapper xml,mapper类,model类的一个插件工具。它相对来说对开发者是有很大的帮助的,但是它也有不足之处,比如生成的xml配置文件不是完全可以拿来使用的,有很多时候需要开发者自行修改后才可以使用。因为它还是值得学习并使用的,因此有了本文的总结。
环境说明:
springboot2.0.2,
mybatis-generator-plugin版本1.3.2,
mysql-5.7.24-winx64
Maven依赖导入:
<plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <!-- mybatis generator 自动生成代码插件 --> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.2</version> <configuration> <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile> <overwrite>true</overwrite> <verbose>true</verbose> </configuration> </plugin> 。。。
这段maven配置内容的作用是用来导入mybatis-generator插件的,同时需要指定插件版本,以及mybatis generator生成配置文件路径。configuration->overwrite属性用来指定是否覆盖本地已有文件。
数据表构建:
为了配置mybatis插件生成对应mapper相关文件,我们需要定义一下数据表:jobitem。
-- ---------------------------- -- Table structure for `jobitem` -- ---------------------------- DROP TABLE IF EXISTS `jobitem`; CREATE TABLE `jobitem` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '唯一键 pk', `appId` varchar(32) NOT NULL COMMENT 'yarn任务id(applicationId)', `submitFilePath` varchar(256) NOT NULL COMMENT '提交脚本路径', `state` varchar(16) DEFAULT NULL COMMENT '任务状态', `monitorType` varchar(512) DEFAULT NULL COMMENT '监控列表', `createUserId` varchar(32) NOT NULL COMMENT '创建者关联Id', `createUserName` varchar(32) NOT NULL COMMENT '创建者用户名', `createTime` datetime NOT NULL COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `key` (`appId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='yarn任务持久化存储对象'; -- ---------------------------- -- Records of jobitem -- ----------------------------
这里的数据表是mysql下的表,在mysql下导入并生成jobitem表。
配置Mybatis配置文件(/src/main/resources/generator/generatorConfig.xml):
项目结构如下:
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> <!-- 数据库驱动包位置 --> <classPathEntry location="D:\.m2\repository\mysql\mysql-connector-java\5.1.46\mysql-connector-java-5.1.46.jar" /> <context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat"> <!-- ( property*,plugin*, commentGenerator?, jdbcConnection, javaTypeResolver?, javaModelGenerator, sqlMapGenerator?, javaClientGenerator?, table+ ) --> <property name="beginningDelimiter" value="`" /> <property name="endingDelimiter" value="`" /> <!-- 生成的 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" /> <!-- 自定义注释生成器 --> <commentGenerator> </commentGenerator> <!--<plugin type="tk.mybatis.mapper.generator.MapperPlugin"> <property name="mappers" value="com.ad.core.mapper"/> </plugin> --> <!-- 连接 那个知道把参数改为 ${}的形式,并且用的yml的 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mydb" userId="root" password="123456"> </jdbcConnection> <!--生成Model类存放位置 --> <javaModelGenerator targetPackage="com.dx.jobmonitor.model" targetProject="E:/work/git/...-model/src/main/java"> <property name="enableSubPackages" value="true" /> <property name="trimStrings" value="true" /> </javaModelGenerator> <!--生成mapper.xml配置文件位置 --> <sqlMapGenerator targetPackage="mapper" targetProject="E:/work/git/f...-mapper/src/main/resources"> <property name="enableSubPackages" value="true" /> </sqlMapGenerator> <!-- 生成mapper接口文件位置 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.dx.jobmonitor.mapper" targetProject="E:/work/git/feature-26692/。。。-mapper/src/main/java"> <property name="enableSubPackages" value="true" /> </javaClientGenerator> <!-- (已经自定义修改了某些sql语句,因此如果重新生成导致sql被覆盖)需要生成的实体类对应的表名,多个实体类复制多份该配置即可 --> <table tableName="sjmc_jobitem" enableCountByExample="false" enableDeleteByExample="false" enableDeleteByPrimaryKey="false" enableInsert="true" enableSelectByExample="true" enableUpdateByExample="true" enableUpdateByPrimaryKey="true"> <generatedKey column="id" sqlStatement="Mysql" identity="true" /> </table> </context> </generatorConfiguration>
运行mybatis generator插件,生成mapper类/mapper.xml/model类:
到此为止,所有的配置已完毕,如果在ecplise中使用,则右击工程-》maven build...-》global添加命令mybatis-generator:generate-》运行,代码生成完毕!
自定义字段/getter/settetr注释
按照上边配置完成后,会发现生成的model类,没有数据注释信息。希望将数据库的备注自动生成到model属性字段,以及setter/getter方法上。实际上这个想法是可行的,我们需要自定义commentGenerator。
第一步:新建一个插件项目
这里必须这么做,否则后边会出现错误:自定义注释类无法初始化错误。
第二步:插件项目引入maven依赖
<dependencies> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies>
第三步:添加自定义注释插件类:
import java.text.SimpleDateFormat; import java.util.Date; import java.util.Properties; 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.CompilationUnit; import org.mybatis.generator.api.dom.java.Field; import org.mybatis.generator.api.dom.java.InnerClass; import org.mybatis.generator.api.dom.java.InnerEnum; import org.mybatis.generator.api.dom.java.JavaElement; import org.mybatis.generator.api.dom.java.Method; import org.mybatis.generator.api.dom.java.Parameter; import org.mybatis.generator.api.dom.xml.XmlElement; import org.mybatis.generator.config.MergeConstants; import org.mybatis.generator.config.PropertyRegistry; /** * 自定义实现 注释生成器 CommentGenerator 接口 */ public class MyCommentGenerator implements CommentGenerator { private Properties properties; private Properties systemPro; private boolean suppressDate; private boolean suppressAllComments; private String nowTime; public MyCommentGenerator() { super(); properties = new Properties(); systemPro = System.getProperties(); suppressDate = false; suppressAllComments = false; nowTime = (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date()); } public void addJavaFileComment(CompilationUnit compilationUnit) { if (suppressAllComments) { return; } return; } /** * Adds a suitable comment to warn users that the element was generated, and * when it was generated. */ public void addComment(XmlElement xmlElement) { return; } public void addRootComment(XmlElement rootElement) { // add no document level comments by default return; } 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)); } /** * 判断传入参数是否为true * @param property * @return */ private boolean isTrue(String property) { if("true".equals(property)){ return true; } return false; } /** * 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 = nowTime; } return result; } 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().replace("\n", " ")); innerClass.addJavaDocLine(" */"); } public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) { if (suppressAllComments) { return; } StringBuilder sb = new StringBuilder(); innerEnum.addJavaDocLine("/**"); sb.append(" * "); sb.append(introspectedTable.getFullyQualifiedTable()); innerEnum.addJavaDocLine(sb.toString().replace("\n", " ")); innerEnum.addJavaDocLine(" */"); } /** * 设置字段注释 */ public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) { if (suppressAllComments) { return; } StringBuilder sb = new StringBuilder(); field.addJavaDocLine("/**"); sb.append(" * "); sb.append(introspectedColumn.getRemarks()); sb.append("<br> \n"); sb.append(" * 列名:" + introspectedColumn.getActualColumnName() + " 类型:" + introspectedColumn.getJdbcTypeName() + "(" + introspectedColumn.getLength() + ")" + " 允许空:" + introspectedColumn.isNullable() + " 缺省值:" + introspectedColumn.getDefaultValue()); field.addJavaDocLine(sb.toString()); field.addJavaDocLine(" */"); } 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(" */"); } public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) { if (suppressAllComments) { return; } method.addJavaDocLine("/**"); addJavadocTag(method, false); method.addJavaDocLine(" */"); } /** * 设置getter方法注释 */ 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().replace("\n", " ")); sb.setLength(0); //加入系统用户 sb.append(" * @author "); sb.append(systemPro.getProperty("user.name")); method.addJavaDocLine(sb.toString().replace("\n", " ")); sb.setLength(0); //是否加入时间戳 if(suppressDate){ sb.append(" * @date " + nowTime); method.addJavaDocLine(sb.toString().replace("\n", " ")); sb.setLength(0); } sb.append(" * @return "); sb.append(introspectedColumn.getActualColumnName()); sb.append(" "); sb.append(introspectedColumn.getRemarks()); method.addJavaDocLine(sb.toString().replace("\n", " ")); method.addJavaDocLine(" */"); } /** * 设置setter方法注释 */ 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().replace("\n", " ")); sb.setLength(0); //加入系统用户 sb.append(" * @author "); sb.append(systemPro.getProperty("user.name")); method.addJavaDocLine(sb.toString().replace("\n", " ")); sb.setLength(0); //是否加入时间戳 if(suppressDate){ sb.append(" * @date " + nowTime); method.addJavaDocLine(sb.toString().replace("\n", " ")); sb.setLength(0); } Parameter parm = method.getParameters().get(0); sb.append(" * @param "); sb.append(parm.getName()); sb.append(" "); sb.append(introspectedColumn.getRemarks()); method.addJavaDocLine(sb.toString().replace("\n", " ")); method.addJavaDocLine(" */"); } 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().replace("\n", " ")); sb.setLength(0); sb.append(" * @author "); sb.append(systemPro.getProperty("user.name")); sb.append(" "); sb.append(nowTime); innerClass.addJavaDocLine(" */"); } }
第四步:修改*-web项目pom中mybatis-generator-plugin配置信息,导入自定义注释插件的依赖。
<plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <!-- mybatis generator 自动生成代码插件 --> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.2</version> <configuration> <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile> <overwrite>true</overwrite> <verbose>true</verbose> </configuration> <dependencies> <dependency> <groupId>com.dx.jobmonitor.plugins.mybatis</groupId> <artifactId>...-plugins-mybatis</artifactId> <version>1.0.0-SNAPSHOT</version> <scope>system</scope> <systemPath>E:/work/git/。。。-plugins-mybatis/target/...-plugins-mybatis-1.0.0-SNAPSHOT.jar</systemPath> </dependency> </dependencies> </plugin> 。。。
第五步:修改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> <!-- 数据库驱动包位置 --> <classPathEntry location="D:\.m2\repository\mysql\mysql-connector-java\5.1.46\mysql-connector-java-5.1.46.jar" /> <context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat"> 。。。 <!-- 自定义注释生成器 --> <commentGenerator type="com.boco.jobmonitor.plugins.mybatis.MyCommentGenerator"> </commentGenerator> 。。。
第六步:重新运行mybatis-generator插件,生成mapper xml,mapper类,model类。
此时model类如下:
import java.util.Date; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; public class Jobitem { /** * 唯一键 pk<br> * 列名:id 类型:INTEGER(10) 允许空:false 缺省值:null */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; /** * yarn任务id(applicationId)<br> * 列名:appId 类型:VARCHAR(32) 允许空:false 缺省值:null */ private String appid; /** * 提交脚本路径<br> * 列名:submitFilePath 类型:VARCHAR(256) 允许空:false 缺省值:null */ private String submitfilepath; /** * 任务状态<br> * 列名:state 类型:VARCHAR(16) 允许空:true 缺省值:null */ private String state; /** * 监控列表<br> * 列名:monitorType 类型:VARCHAR(512) 允许空:true 缺省值:null */ private String monitortype; /** * 创建者关联Id<br> * 列名:createUserId 类型:VARCHAR(32) 允许空:false 缺省值:null */ private String createuserid; /** * 创建者用户名<br> * 列名:createUserName 类型:VARCHAR(32) 允许空:false 缺省值:null */ private String createusername; /** * 创建时间<br> * 列名:createTime 类型:TIMESTAMP(19) 允许空:false 缺省值:null */ private Date createtime; /** * 唯一键 pk * * @return id 唯一键 pk */ public Long getId() { return id; } /** * 唯一键 pk * * @param id * 唯一键 pk */ public void setId(Long id) { this.id = id; } /** * yarn任务id(applicationId) * * @return appId yarn任务id(applicationId) */ public String getAppid() { return appid; } /** * yarn任务id(applicationId) * * @param appid * yarn任务id(applicationId) */ public void setAppid(String appid) { this.appid = appid == null ? null : appid.trim(); } /** * 提交脚本路径 * * @return submitFilePath 提交脚本路径 */ public String getSubmitfilepath() { return submitfilepath; } /** * 提交脚本路径 * * @param submitfilepath * 提交脚本路径 */ public void setSubmitfilepath(String submitfilepath) { this.submitfilepath = submitfilepath == null ? null : submitfilepath.trim(); } /** * 任务状态 * * @return state 任务状态 */ public String getState() { return state; } /** * 任务状态 * * @param state * 任务状态 */ public void setState(String state) { this.state = state == null ? null : state.trim(); } /** * 监控列表 * * @return monitorType 监控列表 */ public String getMonitortype() { return monitortype; } /** * 监控列表 * * @param monitortype * 监控列表 */ public void setMonitortype(String monitortype) { this.monitortype = monitortype == null ? null : monitortype.trim(); } /** * 创建者关联Id * * @return createUserId 创建者关联Id */ public String getCreateuserid() { return createuserid; } /** * 创建者关联Id * * @param createuserid * 创建者关联Id */ public void setCreateuserid(String createuserid) { this.createuserid = createuserid == null ? null : createuserid.trim(); } /** * 创建者用户名 * * @return createUserName 创建者用户名 */ public String getCreateusername() { return createusername; } /** * 创建者用户名 * * @param createusername * 创建者用户名 */ public void setCreateusername(String createusername) { this.createusername = createusername == null ? null : createusername.trim(); } /** * 创建时间 * * @return createTime 创建时间 */ public Date getCreatetime() { return createtime; } /** * 创建时间 * * @param createtime * 创建时间 */ public void setCreatetime(Date createtime) { this.createtime = createtime; } }
参考:
mybatis插件--(1)--mybatis generator自定义插件或者扩展报Cannot instantiate object of type XXX
https://blog.csdn.net/u_ascend/article/details/80742919
mybatis generator为实体类生成自定义注释(读取数据库字段的注释添加到实体类,不修改源码)
https://blog.csdn.net/u012045045/article/details/83012681
使用mybatis-generator添加自定义插件时提示无法实例化插件类 Cannot instantiate object of type
https://blog.csdn.net/twj13162380953/article/details/81286714
Mybatis-generator自动生成代码时候提取数据库的字段注释作为实体类字段、getter/setter方法的注释
https://www.jianshu.com/p/7d58982a5b0b
mybatis-generator自动生成代码插件使用详解
https://www.cnblogs.com/handsomeye/p/6268513.html
基础才是编程人员应该深入研究的问题,比如:
1)List/Set/Map内部组成原理|区别
2)mysql索引存储结构&如何调优/b-tree特点、计算复杂度及影响复杂度的因素。。。
3)JVM运行组成与原理及调优
4)Java类加载器运行原理
5)Java中GC过程原理|使用的回收算法原理
6)Redis中hash一致性实现及与hash其他区别
7)Java多线程、线程池开发、管理Lock与Synchroined区别
8)Spring IOC/AOP 原理;加载过程的。。。
【+加关注】。