2019-02-22
配置文件:
pom.xml 添加 dependency plugin 基于mybatis-plus
<dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.6</version> <scope>compile</scope> </dependency>
<plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.6</version> <configuration> <!--配置文件的位置--> <configurationFile>generator.xml</configurationFile> <verbose>true</verbose> <overwrite>true</overwrite> </configuration> <executions> <execution> <id>Generate MyBatis Artifacts</id> <phase>deploy</phase> <goals> <goal>generate</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.6</version> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.3</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <dependency> <groupId>my.base.project</groupId> <artifactId>base-core</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </plugin>
generatorConfiguration.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" /> <context id="default" targetRuntime="MyBatis3"> <!-- 生成的Java文件的编码 --> <property name="javaFileEncoding" value="UTF-8" /> <!-- 格式化java代码 --> <property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter" /> <!-- 使用自定义的插件 --> <!-- 整合lombok --> <plugin type="*.support.GeneratorPlugin"/> <commentGenerator> <!-- 关闭自动生成的注释 --> <property name="suppressAllComments" value="true"/> <!--生成的注释包含时间戳--> <property name="suppressDate" value="true"/> </commentGenerator> <!--数据库连接的信息:驱动类、连接地址、用户名、密码 --> <jdbcConnection driverClass="${jdbc.driver}" connectionURL="${jdbc.url}" userId="${jdbc.username}" password="${jdbc.password}"> <!-- 字段注解 针对oracle数据库 --> <property name="remarksReporting" value="true" /> <!-- 字段注解 针对mysql数据库 --> <property name="useInformationSchema" value="true"/> </jdbcConnection> <!-- 类型转换 --> <javaTypeResolver> <!-- 是否使用bigDecimal 默认false:把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer, 为 true时:把JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal --> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- 生成实体类 --> <!-- targetPackage:生成实体类的包名 --> <!-- targetProject:生成PO类的位置 --> <javaModelGenerator targetPackage="${model.package}" targetProject="${target.project}/java"> <!--所有实体类继承BasePojo类--> <property name="rootClass" value="*.base.BaseModel"/> <!-- enableSubPackages:是否让schema作为包的后缀 --> <property name="enableSubPackages" value="false"/> <!-- 从数据库返回的值被清理前后的空格 --> <property name="trimStrings" value="false"/> </javaModelGenerator> <!-- 生成XxxMapper.xml文件 --> <!-- targetProject:mapper映射文件生成的位置 --> <sqlMapGenerator targetPackage="${xml.mapper.package}" targetProject="${target.project}/resources"> <!-- enableSubPackages:是否让schema作为包的后缀 --> <property name="enableSubPackages" value="false"/> </sqlMapGenerator> <!-- 生成XxxMapper.java文件 --> <!--ANNOTATEDMAPPER: 生成java类文件,基于注解的Mapper接口,不会有对应的XML映射文件 MIXEDMAPPER:XML和注解的混合形式 XMLMAPPER:所有的方法都在XML中,接口调用依赖XML文件 --> <javaClientGenerator type="XMLMAPPER" targetPackage="${mapper.package}" targetProject="${target.project}/java"> <property name="enableSubPackages" value="false"/> </javaClientGenerator> <table schema="JTP" tableName="${table.name}" domainObjectName="${table.domainObjectName}" enableSelectByPrimaryKey="true" enableInsert="false" enableUpdateByPrimaryKey="false" enableDeleteByPrimaryKey="false" enableSelectByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableCountByExample="false" selectByExampleQueryId="false"> </table> </context> </generatorConfiguration>
generator.properties config 使用的参数
# 数据库连接配置
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@ip:orcl
jdbc.username=name
jdbc.password=password
# 文件路径配置
model.package=*.model.menu
mapper.package=*.mapper
xml.mapper.package=mapper.db
target.project=src/main
# 执行的表数据
table.name=SYS_MENU_T
table.domainObjectName=Menu
自定义插件文件:
GeneratorPlugin.java Model自定义注释,Inteface 自定义基类,xml删除多余方法 支持lombok插件
import org.apache.commons.lang3.StringUtils; import org.mybatis.generator.api.GeneratedXmlFile; 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.*; import org.mybatis.generator.api.dom.xml.Document; import org.mybatis.generator.api.dom.xml.Element; import java.util.Collection; import java.util.Date; import java.util.LinkedHashSet; import java.util.List; /** * Mybatis 代码生成自定义插件 * A MyBatis Generator plugin to use Lombok's annotations. * For example, use @Data annotation instead of getter ands setter. * * @className GeneratorPlugin * @author joe * @version V1.0.0 * @date 2019-01-16 */ public class GeneratorPlugin extends PluginAdapter { private final Collection<Annotations> annotations; /** * GeneratorPlugin constructor */ public GeneratorPlugin() { annotations = new LinkedHashSet<>(Annotations.values().length); } /** * @param warnings list of warnings * @return always true */ @Override public boolean validate(List<String> warnings) { return true; } /** * Intercepts base record class generation * * @param topLevelClass the generated base record class * @param introspectedTable The class containing information about the table as * introspected from the database * @return always true */ @Override public boolean modelBaseRecordClassGenerated( TopLevelClass topLevelClass, IntrospectedTable introspectedTable ) { addModelClassComment(topLevelClass, introspectedTable); return true; } /** * Intercepts primary key class generation * * @param topLevelClass the generated primary key class * @param introspectedTable The class containing information about the table as * introspected from the database * @return always true */ @Override public boolean modelPrimaryKeyClassGenerated( TopLevelClass topLevelClass, IntrospectedTable introspectedTable ) { addModelClassComment(topLevelClass, introspectedTable); return true; } /** * Intercepts "record with blob" class generation * * @param topLevelClass the generated record with BLOBs class * @param introspectedTable The class containing information about the table as * introspected from the database * @return always true */ @Override public boolean modelRecordWithBLOBsClassGenerated( TopLevelClass topLevelClass, IntrospectedTable introspectedTable ) { addModelClassComment(topLevelClass, introspectedTable); return true; } /** * 类属性注释 * * @param field 属性 * @param topLevelClass 类对象 * @param introspectedColumn 列 * @param introspectedTable 表 * @param modelClassType Class类型 * @return true */ @Override public boolean modelFieldGenerated(Field field, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) { StringBuilder sb = new StringBuilder(); field.addJavaDocLine("/**"); sb.append(" * "); // 字段注释 sb.append(columnRemarks(introspectedColumn.getRemarks())); field.addJavaDocLine(sb.toString().replace("\n", " ")); field.addJavaDocLine(" */"); // 主键 if (introspectedTable.getPrimaryKeyColumns().stream() .anyMatch(p -> p.equals(introspectedColumn))) { field.addAnnotation("@TableId"); } // 字段上生成@TableField注解 field.addAnnotation("@TableField(value = \"" + introspectedColumn.getActualColumnName() + "\")"); return true; } /** * Prevents all getters from being generated. * See SimpleModelGenerator * * @param method the getter, or accessor, method generated for the specified * column * @param topLevelClass the partially implemented model class * @param introspectedColumn The class containing information about the column related * to this field as introspected from the database * @param introspectedTable The class containing information about the table as * introspected from the database * @param modelClassType the type of class that the field is generated for */ @Override public boolean modelGetterMethodGenerated( Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType ) { return false; } /** * Prevents all setters from being generated * See SimpleModelGenerator * * @param method the setter, or mutator, method generated for the specified * column * @param topLevelClass the partially implemented model class * @param introspectedColumn The class containing information about the column related * to this field as introspected from the database * @param introspectedTable The class containing information about the table as * introspected from the database * @param modelClassType the type of class that the field is generated for * @return always false */ @Override public boolean modelSetterMethodGenerated( Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType ) { return false; } /** * 增加类注释 * * @param topLevelClass 类 * @param introspectedTable 表数据 */ private void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { topLevelClass.addJavaDocLine("/**"); topLevelClass.addJavaDocLine(" * " + tableRemarks(introspectedTable)); topLevelClass.addJavaDocLine(" * "); topLevelClass.addJavaDocLine(" * @author " + System.getProperty("user.name")); topLevelClass.addJavaDocLine(" * @date " + new Date().toString()); topLevelClass.addJavaDocLine(" *"); topLevelClass.addJavaDocLine(" */"); addAnnotations(topLevelClass); topLevelClass.addImportedType("com.baomidou.mybatisplus.annotation.TableField"); topLevelClass.addImportedType("com.baomidou.mybatisplus.annotation.TableId"); topLevelClass.addImportedType("com.baomidou.mybatisplus.annotation.TableName"); // 添加类注解 // 表名 String tableName = introspectedTable.getFullyQualifiedTable().getIntrospectedTableName(); topLevelClass.addAnnotation(String.format("@TableName(\"%s\")", tableName)); } /** * Adds the lombok annotations' imports and annotations to the class * * @param topLevelClass the partially implemented model class */ private void addAnnotations(TopLevelClass topLevelClass) { //@Data is default annotation annotations.add(Annotations.DATA); annotations.add(Annotations.EQUALS); for (Annotations annotation : annotations) { topLevelClass.addImportedType(annotation.javaType); topLevelClass.addAnnotation(annotation.name); } } /** * 数据字典类型 mapper */ @Override public boolean clientGenerated( Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable ) { interfaze.addJavaDocLine("/**"); interfaze.addJavaDocLine(" * " + tableRemarks(introspectedTable) + " Mapper"); interfaze.addJavaDocLine(" * "); interfaze.addJavaDocLine(" * @author " + System.getProperty("user.name")); interfaze.addJavaDocLine(" * @date " + new Date().toString()); interfaze.addJavaDocLine(" *"); interfaze.addJavaDocLine(" */"); interfaze.addImportedType(new FullyQualifiedJavaType("org.apache.ibatis.annotations.Mapper")); interfaze.addAnnotation("@Mapper"); interfaze.addImportedType(new FullyQualifiedJavaType("com.baomidou.mybatisplus.core.mapper.BaseMapper")); FullyQualifiedJavaType superMapper = new FullyQualifiedJavaType(String.format("BaseMapper<%s>", introspectedTable.getBaseRecordType())); // 添加 extends MybatisPlusBaseMapper interfaze.addSuperInterface(superMapper); // 清理方法 interfaze.getMethods().clear(); return true; } @Override public boolean sqlMapGenerated(GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) { // 设置 xml文件时覆盖写 默认:true [mybatis generator默认采用追加方式生成] sqlMap.setMergeable(false); return super.sqlMapGenerated(sqlMap, introspectedTable); } @Override public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) { // 之前 table 配置 保留了 一个SelectByPrimaryKey 设置为true 此处删除 List<Element> list = document.getRootElement().getElements(); list.remove(list.size() - 1); return true; } private String tableRemarks(IntrospectedTable introspectedTable) { String remark = introspectedTable.getRemarks(); if (StringUtils.isEmpty(remark)) { return introspectedTable.getFullyQualifiedTable().getIntrospectedTableName(); } return remark; } private String columnRemarks(String remark) { if (StringUtils.isEmpty(remark)) { return "TODO add remark"; } return remark; } /** * Lombok 相关的注解 * * @className Annotations * @author joe * @version V1.0.0 * @date 2019-02-21 10:35 */ private enum Annotations { /** * data */ DATA("data", "@Data", "lombok.Data"), BUILDER("builder", "@Builder", "lombok.Builder"), EQUALS("equalsAndHashCode", "@EqualsAndHashCode(callSuper = false)", "lombok.EqualsAndHashCode"), ALL_ARGS_CONSTRUCTOR("allArgsConstructor", "@AllArgsConstructor", "lombok.AllArgsConstructor"), NO_ARGS_CONSTRUCTOR("noArgsConstructor", "@NoArgsConstructor", "lombok.NoArgsConstructor"), ACCESSORS("accessors", "@Accessors", "lombok.experimental.Accessors"), TO_STRING("toString", "@ToString", "lombok.ToString"); private final String paramName; private final String name; private final FullyQualifiedJavaType javaType; Annotations(String paramName, String name, String className) { this.paramName = paramName; this.name = name; this.javaType = new FullyQualifiedJavaType(className); } } }
使用方式:
mvn mybatis-generator:generate
如果是在intellij 环境,直接鼠标点击即可
生成效果:
import *.base.BaseModel; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; /** * 系统菜单 * * @author joe * @date 2019-01-20 * */ @Data @EqualsAndHashCode(callSuper = false) @TableName("SYS_MENU_T") public class Menu extends BaseModel { /** * 菜单ID */ @TableId @TableField(value = "MENU_ID") private String menuId; /** * 菜单编码,不允许重复 */ @TableField(value = "MENU_CODE") private String menuCode; /** * 菜单名称,同一个级别下不允许重复 */ @TableField(value = "MENU_NAME") private String menuName; }
import *.MenuEO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; /** * 系统菜单 Mapper * * @author joe * @date 2019-01-22 16:24 * */ @Mapper public interface MenuMapper extends BaseMapper<Menu> { }
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="*.mapper.MenuMapper">
<resultMap id="BaseResultMap" type="*.Menu">
<id column="MENU_ID" jdbcType="VARCHAR" property="menuId" />
<result column="MENU_CODE" jdbcType="VARCHAR" property="menuCode" />
<result column="MENU_NAME" jdbcType="VARCHAR" property="menuName" />
</resultMap>
<sql id="Base_Column_List">
MENU_ID, MENU_CODE, MENU_NAME
</sql>
</mapper>
常见问题:
1、运行报错,找不到自定义的插件类[generate failed: Cannot instantiate object of type *.MyPlugin]
原因:mybatis-generator 的plugin有自己的classpath,我们在项目中直接继承的类和plugin不属于同一个classpath
解决:把插件类打基础包,再pom的plugin配置中被 mybatis-generator 的plugin 依赖。
2、报错[There are no statements enabled for table mybatis.category, this table will be ignored.]
原因:generatorConfig.xml中,<table>标签配成 所有原始的sql都是false
解决:保留一个时true的设置,再插件中处理xml时再删除。
3、获取不到数据库字段的注释
原因:mysql 和 oracle的数据库配置不同,确认配置
解决:在generatorConfiguration.xml配置文件中配置
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 --> <jdbcConnection driverClass="${jdbc.driver}" connectionURL="${jdbc.url}" userId="${jdbc.username}" password="${jdbc.password}"> <!-- 字段注解 针对oracle数据库 --> <property name="remarksReporting" value="true" /> <!-- 字段注解 针对mysql数据库 --> <property name="useInformationSchema" value="true"/> </jdbcConnection>
4、xml文件再次生成时被追加
原因:mybatis generator默认采用追加方式生成
解决:重写sqlMapGenerated方法。设置sqlMap.setMergeable(false);。默认情况下isMergeable为true,所以在这里设置为false。
mybatis-generator.xml配置文件详解 参考 https://blog.csdn.net/weixin_39805338/article/details/80999186