mybatis代码生成+自定义注解+自定义注释
mybatis代码生成
<!--mybatis的包和反向生成的包__用来生成dao,entity层-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.4</version>
</dependency>
<!-- mybatis-generator-core 反向生成java代码-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
配置文件
在resources
文件夹中创建文件mbgConfiguration.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">
<!-- 第一种mybatis逆向生成xml配置 -->
<generatorConfiguration>
<context id="sqlserverTables" targetRuntime="MyBatis3" defaultModelType="flat">
<!-- 自动识别数据库关键字,默认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="`"/>
<!-- 使用自定义的插件:entity的lombok注解 -->
<plugin type="net.cc.gen.utils.LombokPlugin"/>
<!--todo 文件名替换-->
<!-- 此处是将Example改名为Criteria 当然 想改成什么都行~ -->
<plugin type="org.mybatis.generator.plugins.RenameExampleClassPlugin">
<property name="searchString" value="Example$" />
<!-- 替换后 <property name="replaceString" value="Criteria" /> -->
<property name="replaceString" value="Query" />
</plugin>
<!-- 此处是将UserMapper.xml改名为UserDao.xml 当然 想改成什么都行~ -->
<!--<plugin type="org.mybatis.generator.plugins.rename.RenameSqlMapperPlugin">-->
<!--<property name="searchString" value="Mapper" />-->
<!--<property name="replaceString" value="Dao" />-->
<!--</plugin>-->
<!-- 此处是将UserMapper改名为UserDao 接口 当然 想改成什么都行~ -->
<!--<plugin type="org.mybatis.generator.plugins.rename.RenameJavaMapperPlugin">-->
<!--<property name="searchString" value="Mapper$" />-->
<!--<property name="replaceString" value="Dao" />-->
<!--</plugin>-->
<!-- 通过type指定自定义的注释 -->
<commentGenerator type="net.cc.gen.utils.MyCommentGenerator"/>
<!--todo 数据库链接URL、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/project1?useUnicode=true&useSSL=false&characterEncoding=utf8"
userId="test"
password="123456"/>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!--todo entity包路径-->
<javaModelGenerator targetPackage="com.cc.learn.entity" targetProject="src/main/java">
<!-- 在targetPackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false -->
<property name="enableSubPackages" value="true"/>
<!-- 从数据库返回的值被清理前后的空格,对String类型字段调用trim()方法 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!--todo mapper的xml路径-->
<sqlMapGenerator targetPackage="mappings" targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!--todo mapper的java文件路径-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.cc.learn.dao.mysql.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!--todo tableName需要生成的table名字
useActualColumnNames 驼峰命名
字段类型为text格式的字段需要专门配置
<columnOverride column="AIRSPACE_DATA" javaType="java.lang.String" jdbcType="VARCHAR"/>
<columnOverride column="AIRSPACES_DESC" javaType="java.lang.String" jdbcType="VARCHAR"/>
-->
<table tableName="User" schema="crmii" delimitIdentifiers="true"><property name="useActualColumnNames" value="false"/></table>
<!--<table tableName="数据表2" schema="crmii" delimitIdentifiers="true"><property name="useActualColumnNames" value="false"/></table>-->
<!--<table tableName="数据表3" schema="crmii" delimitIdentifiers="true"><property name="useActualColumnNames" value="false"/></table>-->
</context>
</generatorConfiguration>
配置类
自定义的lombok注解配置
效果:
在类上添加注解
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class User {
}
在时间字段上自动添加注解
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
代码
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.Plugin;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import java.util.*;
/** 自定义的lombok注解配置
* @author jingshiyu
* @date 2019/9/17 12:04:47
* @desc
*/
public class LombokPlugin extends PluginAdapter {
private final Collection<Annotations> annotations;
/**
* LombokPlugin constructor
*/
public LombokPlugin() {
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) {
addAnnotations(topLevelClass);
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) {
addAnnotations(topLevelClass);
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) {
addAnnotations(topLevelClass);
return true;
}
/**
* 设置get set方法(使用lombok不需要,直接返回false)
*/
@Override
public boolean modelGetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) {
return false;
}
/**
* 设置set方法
*/
@Override
public boolean modelSetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) {
return false;
}
/**
* 设置lombok注解 <br>
*/
private void addAnnotations(TopLevelClass topLevelClass) {
for (Annotations annotation : annotations) {
topLevelClass.addImportedType(annotation.javaType);
topLevelClass.addAnnotation(annotation.asAnnotation());
}
}
/**
* entity类设置
* @param properties
*/
@Override
public void setProperties(Properties properties) {
super.setProperties(properties);
//@Data is default annotation
annotations.add(Annotations.DATA);
annotations.add(Annotations.ALL_ARGS_CONSTRUCTOR);
annotations.add(Annotations.NO_ARGS_CONSTRUCTOR);
annotations.add(Annotations.BUILDER);
for (String annotationName : properties.stringPropertyNames()) {
if (annotationName.contains(".")) {
continue;
}
String value = properties.getProperty(annotationName);
if (!Boolean.parseBoolean(value)) {
// The annotation is disabled, skip it
continue;
}
Annotations annotation = Annotations.getValueOf(annotationName);
if (annotation == null) {
continue;
}
String optionsPrefix = annotationName + ".";
for (String propertyName : properties.stringPropertyNames()) {
if (!propertyName.startsWith(optionsPrefix)) {
// A property not related to this annotation
continue;
}
String propertyValue = properties.getProperty(propertyName);
annotation.appendOptions(propertyName, propertyValue);
annotations.add(annotation);
annotations.addAll(Annotations.getDependencies(annotation));
}
}
}
/**
* mapper类设置注解
*/
@Override
public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
interfaze.addImportedType(new FullyQualifiedJavaType("org.apache.ibatis.annotations.Mapper"));
interfaze.addAnnotation("@Mapper");
return true;
}
/**
* entity字段设置
*/
@Override
public boolean modelFieldGenerated(Field field, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, Plugin.ModelClassType modelClassType) {
if (field.getType().getShortNameWithoutTypeArguments().equals("Date")) {
field.getAnnotations().add(Annotations.DATE_TIME_FORMAT.asAnnotation());
field.getAnnotations().add(Annotations.JSON_FORMAT.asAnnotation());
topLevelClass.addImportedType(Annotations.DATE_TIME_FORMAT.javaType);
topLevelClass.addImportedType(Annotations.JSON_FORMAT.javaType);
}
return true;
}
private enum Annotations {
DATA("data", "@Data", "lombok.Data"),
BUILDER("builder", "@Builder", "lombok.Builder"),
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"),
DATE_TIME_FORMAT("dateTimeFormat", "@DateTimeFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")", "org.springframework.format.annotation.DateTimeFormat"),
JSON_FORMAT("jsonFormat", "@JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")", "com.fasterxml.jackson.annotation.JsonFormat");
private final String paramName;
private final String name;
private final FullyQualifiedJavaType javaType;
private final List<String> options;
Annotations(String paramName, String name, String className) {
this.paramName = paramName;
this.name = name;
this.javaType = new FullyQualifiedJavaType(className);
this.options = new ArrayList<String>();
}
private static Annotations getValueOf(String paramName) {
for (Annotations annotation : Annotations.values()) {
if (String.CASE_INSENSITIVE_ORDER.compare(paramName, annotation.paramName) == 0) {
return annotation;
}
}
return null;
}
private static Collection<Annotations> getDependencies(Annotations annotation) {
if (annotation == ALL_ARGS_CONSTRUCTOR) {
return Collections.singleton(NO_ARGS_CONSTRUCTOR);
} else {
return Collections.emptyList();
}
}
// A trivial quoting.
// Because Lombok annotation options type is almost String or boolean.
private static String quote(String value) {
if (Boolean.TRUE.toString().equals(value) || Boolean.FALSE.toString().equals(value))
// case of boolean, not passed as an array.
{
return value;
}
return value.replaceAll("[\\\\w]+", "\"$0\"");
}
private void appendOptions(String key, String value) {
String keyPart = key.substring(key.indexOf(".") + 1);
String valuePart = value.contains(",") ? String.format("{%s}", value) : value;
this.options.add(String.format("%s=%s", keyPart, quote(valuePart)));
}
private String asAnnotation() {
if (options.isEmpty()) {
return name;
}
StringBuilder sb = new StringBuilder();
sb.append(name);
sb.append("(");
boolean first = true;
for (String option : options) {
if (first) {
first = false;
} else {
sb.append(", ");
}
sb.append(option);
}
sb.append(")");
return sb.toString();
}
}
}
代码注释配置
代码生成时,使用数据控的注释给字段添加文档注释
效果
/**
* 编号
*/
private String planId;
代码
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
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;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import static org.mybatis.generator.internal.util.StringUtility.isTrue;
/**
* mybatis逆向工程默认的注释修改(使用表的注释)
*
* @author jingshiyu
* @date 2019/7/17 17:39:36
* @desc
*/
public class MyCommentGenerator implements CommentGenerator {
/**
* The properties.
*/
private Properties properties;
/**
* The suppress date.
*/
private boolean suppressDate;
/**
* The suppress all comments.
*/
private boolean suppressAllComments;
/**
* 是否添加doc注释,true:不添加,false:添加<br>
* The addition of table remark's comments.
* If suppressAllComments is true, this option is ignored
*/
private boolean addRemarkComments;
private SimpleDateFormat dateFormat;
public MyCommentGenerator() {
super();
properties = new Properties();
suppressDate = false;
suppressAllComments = false;
addRemarkComments = false;
}
@Override
public void addJavaFileComment(CompilationUnit compilationUnit) {
}
/**
* 实体类对应的mapper.xml注释,mapper类不加注释,如有需要参考 DefaultCommentGenerator
*/
@Override
public void addComment(XmlElement xmlElement) {
if (suppressAllComments) {
return;
}
}
@Override
public void addRootComment(XmlElement rootElement) {
}
@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);
}
}
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());
}
protected String getDateString() {
if (suppressDate) {
return null;
} else if (dateFormat != null) {
return dateFormat.format(new Date());
} else {
return new Date().toString();
}
}
/**
* 设置class的注解
*/
@Override
public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
if (suppressAllComments) {
return;
}
StringBuilder sb = new StringBuilder();
innerClass.addJavaDocLine("/**");
// sb.append(" * This class corresponds to the database table ");
sb.append(introspectedTable.getFullyQualifiedTable());
innerClass.addJavaDocLine(sb.toString());
addJavadocTag(innerClass, false);
innerClass.addJavaDocLine(" */");
}
/**
* 方法注释
*/
@Override
public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
if (suppressAllComments || !addRemarkComments) {
return;
}
StringBuilder sb = new StringBuilder();
topLevelClass.addJavaDocLine("/**");
//设置数据库的备注
String remarks = introspectedTable.getRemarks();
if (addRemarkComments && StringUtility.stringHasValue(remarks)) {
topLevelClass.addJavaDocLine(" * Database Table Remarks:");
String[] remarkLines = remarks.split(System.getProperty("line.separator"));
for (String remarkLine : remarkLines) {
topLevelClass.addJavaDocLine(" * " + remarkLine);
}
}
topLevelClass.addJavaDocLine(" *");
sb.append(introspectedTable.getFullyQualifiedTable());
topLevelClass.addJavaDocLine(sb.toString());
addJavadocTag(topLevelClass, true);
topLevelClass.addJavaDocLine(" */");
}
/**
* 添加枚举的注释
*/
@Override
public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) {
if (suppressAllComments) {
return;
}
StringBuilder sb = new StringBuilder();
innerEnum.addJavaDocLine("/**");
sb.append(introspectedTable.getFullyQualifiedTable());
innerEnum.addJavaDocLine(sb.toString());
addJavadocTag(innerEnum, false);
innerEnum.addJavaDocLine(" */");
}
/**
* 实体类字段注释
*/
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
if (suppressAllComments || StringUtils.isEmpty(introspectedColumn.getRemarks())) {
return;
}
field.addJavaDocLine("/**");
StringBuilder sb = new StringBuilder();
// introspectedColumn.getRemarks() 就是获取字段注释
sb.append(" * " + introspectedColumn.getRemarks());
field.addJavaDocLine(sb.toString());
field.addJavaDocLine(" */");
}
/**
* 实体类的静态字段
*/
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable) {
if (suppressAllComments) {
return;
}
}
/**
* 实体类toString方法
*/
@Override
public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {
if (suppressAllComments) {
return;
}
}
/**
* 实体类getter方法注释
*/
@Override
public void addGetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
if (suppressAllComments) {
return;
}
}
/**
* 实体类setter注释
*/
@Override
public void addSetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
if (suppressAllComments) {
return;
}
}
/**
* 类注释
* @param innerClass
* @param introspectedTable
* @param markAsDoNotDelete
*/
@Override
public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) {
if (suppressAllComments) {
return;
}
StringBuilder sb = new StringBuilder();
innerClass.addJavaDocLine("/**");
sb.append(introspectedTable.getFullyQualifiedTable());
innerClass.addJavaDocLine(sb.toString());
addJavadocTag(innerClass, markAsDoNotDelete);
innerClass.addJavaDocLine(" */");
}
}
调用
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.internal.DefaultShellCallback;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* java代码生成器(会生成example的entity)<br>
* mybatis逆向工程
*
* @author jingshiyu
* @date 2019/7/17 17:24
* @desc java代码生成器(会生成example的entity)<br>
*/
public class JavaExampleGenerator {
public static void main(String[] args) {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
//如果这里出现空指针,直接写绝对路径即可。
String genCfg = "/mbgConfiguration.xml";
File configFile = new File(JavaExampleGenerator.class.getResource(genCfg).getFile());
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = null;
try {
config = cp.parseConfiguration(configFile);
} catch (Exception e) {
e.printStackTrace();
}
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = null;
try {
myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
} catch (InvalidConfigurationException e) {
e.printStackTrace();
}
try {
myBatisGenerator.generate(null);
} catch (Exception e) {
e.printStackTrace();
}
}
}