栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis Generator插件

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis Generator插件

关于 mybatis generator 插件,官方提供了一些参考的third-party-tools,但是在实际开发的项目中,遇到了一些相关的问题,以下是写相关记录(主要是配合 gradle 使用)。

1. LombokPlugin 插件

这个很多博客上都有,也就不再重复论了,贴一下 code

public class LombokPlugin extends PluginAdapter {

    private final Set annotations;

    
    public LombokPlugin() {
 annotations = new linkedHashSet<>(Annotations.values().length);
    }

    
    @Override
    public boolean validate(List warnings) {
 return true;
    }

    
    @Override
    public boolean modelbaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
 addAnnotations(topLevelClass);
 return true;
    }

    
    @Override
    public boolean modelPrimaryKeyClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
 addAnnotations(topLevelClass);
 return true;
    }

    
    @Override
    public boolean modelRecordWithBLOBsClassGenerated(TopLevelClass topLevelClass,
     IntrospectedTable introspectedTable) {
 addAnnotations(topLevelClass);
 return true;
    }

    
    @Override
    public boolean modelGetterMethodGenerated(
     Method method,
     TopLevelClass topLevelClass,
     IntrospectedColumn introspectedColumn,
     IntrospectedTable introspectedTable,
     ModelClassType modelClassType) {
 return false;
    }

    
    @Override
    public boolean modelSetterMethodGenerated(
     Method method,
     TopLevelClass topLevelClass,
     IntrospectedColumn introspectedColumn,
     IntrospectedTable introspectedTable,
     ModelClassType modelClassType) {
 return false;
    }

    
    private void addAnnotations(TopLevelClass topLevelClass) {
 for (Annotations annotation : annotations) {
     topLevelClass.addimportedType(annotation.javaType);
     topLevelClass.addAnnotation(annotation.asAnnotation());
 }
    }

    @Override
    public void setProperties(Properties properties) {
 super.setProperties(properties);

 //@Data,@Builder,@NoArgsConstructor,@AllArgsConstructor is default annotation
 annotations.add(Annotations.DATA);
 annotations.add(Annotations.BUILDER);
 annotations.add(Annotations.NO_ARGS_CONSTRUCTOR);
 annotations.add(Annotations.ALL_ARGS_CONSTRUCTOR);

 for (String annotationName : properties.stringPropertyNames()) {
     if (annotationName.contains(".")) {
  // Not an annotation name
  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));
     }
 }
    }

    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");


 private final String paramName;
 private final String name;
 private final FullyQualifiedJavaType javaType;
 private final List options;


 Annotations(String paramName, String name, String className) {
     this.paramName = paramName;
     this.name = name;
     javaType = new FullyQualifiedJavaType(className);
     options = new ArrayList<>();
 }

 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 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)) {
  return value;
     }
     // case of boolean, not passed as an array.
     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;
     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();
 }
    }
}
2. ServicePlugin 插件

主要是为了便于自动生成 Service 类

public class ServicePlugin extends PluginAdapter {

    private String targetProject;
    private String targetPackage;

    @Override
    public boolean validate(List list) {
 return true;
    }

    @Override
    public void setProperties(Properties properties) {
 super.setProperties(properties);
 String targetProject = this.properties.getProperty("targetProject");
 if (StringUtility.stringHasValue(targetProject)) {
     this.targetProject = targetProject;
 } else {
     throw new RuntimeException("targetProject 属性不能为空!");
 }
 String targetPackage = this.properties.getProperty("targetPackage");
 if (StringUtility.stringHasValue(targetPackage)) {
     this.targetPackage = targetPackage;
 } else {
     throw new RuntimeException("targetPackage 属性不能为空!");
 }
    }

    
    @Override
    public List contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {
 FullyQualifiedJavaType entityType = new FullyQualifiedJavaType(introspectedTable.getbaseRecordType());
 String domainObjectName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();
 String service = targetPackage + "." + domainObjectName + "Service";
 TopLevelClass topLevelClass = new TopLevelClass(new FullyQualifiedJavaType(service));
 topLevelClass.addimportedType(entityType);
 topLevelClass.addimportedType(new FullyQualifiedJavaType(service));
 topLevelClass.addimportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Service"));
 topLevelClass.addimportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation" +
  ".Autowired"));
 topLevelClass.addimportedType(new FullyQualifiedJavaType("cn.mwee.service.base_framework.mysql.service" +
  ".baseService"));
 topLevelClass.addAnnotation("@Service("" + firstLetterLowerCase(domainObjectName + "Service") + "")");
 topLevelClass.setVisibility(JavaVisibility.PUBLIC);
 topLevelClass.setSuperClass(new FullyQualifiedJavaType("baseService<" + entityType.getShortName() + ">"));
 setMapperField(introspectedTable, topLevelClass);
 ElementUtil.addAuthorTag(topLevelClass);
 return Arrays.asList(new GeneratedJavaFile(topLevelClass, targetProject, new DefaultJavaFormatter()));
    }

    
    private void setMapperField(IntrospectedTable introspectedTable, TopLevelClass clazz) {
 // 实体类的类名
 String domainObjectName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();
 // Mapper类所在包的包名
 String mapperPackage = introspectedTable.getContext().getJavaClientGeneratorConfiguration().getTargetPackage();
 Field mapperField = new Field();
 // 设置Field的注解
 mapperField.addAnnotation("@Autowired");
 mapperField.setVisibility(JavaVisibility.PRIVATE);
 // 设置Field的类型
 mapperField.setType(new FullyQualifiedJavaType(domainObjectName + "Mapper"));
 // 设置Field的名称
 mapperField.setName(firstLetterLowerCase(domainObjectName) + "Mapper");
 // 将Field添加到对应的类中
 clazz.addField(mapperField);
 // 对应的类需要import Mapper类(使用全限定类名)
 clazz.addimportedType(new FullyQualifiedJavaType(mapperPackage + "." + domainObjectName + "Mapper"));
    }

    private String firstLetterLowerCase(String name) {
 char c = name.charAt(0);
 if (c >= 'A' && c <= 'Z') {
     String temp = String.valueOf(c);
     return name.replaceFirst(temp, temp.toLowerCase());
 }
 return name;
    }
}
3. 解决数据库 Unsigned 类型字段

使用官方 mybatis generator 1.3.7 版本自动生产的实体类映射,是不能区分 Unsigned 和 Signed mysql 8.x(针对 java 项目,很容易出现类型字段溢出),尤其实际项目中,接手老的项目,之前一些数据库字段的设置,留下来的一些“坑”;

  • 官方方案:(github 上也有一些小伙伴提了相应的 issue,好像没有 fixed)

    元素覆盖指定的字段
    缺点:在针对很多表的时候,都需要手动设置这些字段,而且很容易丢失(可能导致线上问题)

  • 解决方案:

    通过 download 官方 mybatis generator 源码,发现是可以自动识别 Unsigned 和 Signed 字段属性的,故修改了源码,打包,重新编译,达到了想要的目的,不需要针对指定的字段每一个修改(在 github 上已经和官方作者沟通,接受了 issue,将于下一个版本 1.4.0 做增强),由于官方作者一直没发布 1.4.0,故公司内部打包如下 Jar 版本:mybatis-generator-maven-plugin-1.3.7.2.jar

4. 如何自动生成 jdk8 时间映射

之前是打算直接写插件直接自动生成,但是考虑到有些项目还是用的 jdk8 以前的时间,老的项目也不能强制要求 jdk8 时间版本,故下面  只是展示如何处理.

在生成的实体类中加入下面处理



注:在 mybatis 使用 jdk8 时间时,需要注意的是,mybatis 3.5.1+和 druid 1.1.20 是不支持 jdk8 的时间戳的druid-jdk8,不过,现在已经修复了,等下一个版本估计就能解决了(当然,也可以切换到 HikariCP 数据源)

5. 集成 gradle 插件

市场上已经有很多 gradle 集成 mybatis generator,选择了其中一个比较好用的插件mybatis-generator-plugin(尊重原创作者),当然在公司内部处理,也针对这个插件做了相应的修改定制

6. 附录

针对上面  的一些处理,生成的结构图如下:

本文由博客一文多发平台 OpenWrite 发布!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/239054.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号