MyBatis(2)之MyBatis-Generator最佳实践

自定义注释
自定义注解
指定xml文件模式

上一篇文章详细阐述了xml配置文件的各种标签及其含义。其实从<context/>标签开始,每一个标签都对应一个实体类。context.class对应<context/>标签,而每一个子标签都对应一个属性;如图:。有了实体类的关系,那么自定义起来还不是易如反掌。

自定义添加注释

以用数据库中字段的注释,作为Model属性的注释为例:

针对注解的标签是<commentGenerator/>,对应的接口实体类是CommentGenerator,该类中封装了针对GetterComment、SetterComment、FieldComment、ClassComment以及xml中的注解,这些方法在生成实体类时,会通过Context被调用;该接口默认有默认的实现类DefaultCommentGenerator。切入点就是该DefaultCommentGenerator:

  1. 去除原始的Getter、Setter方法的默认注释,只要实现addSetterCommentaddGetterComment方法,返回为空,原生注释就不会再生成;
  2. 实现addFieldComment方法(管控Model属性的注释内容),具体如下:
    @Override
    public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
        StringBuffer sb = new StringBuffer();
        field.addJavaDocLine("/**");
        field.addJavaDocLine("*");
       // 获取表的名称
        sb.append("* TableName: " + introspectedTable.getFullyQualifiedTable() + "\n\t");
        //获取该表中属性的名称
        sb.append("* ColumnName: " + introspectedColumn.getActualColumnName() + "\n\t");
        sb.append("*<pre>" + "\n\t");
        //该字段的comment 信息
        sb.append("*" + introspectedColumn.getRemarks());
        field.addJavaDocLine(sb.toString());
        field.addJavaDocLine("*</pre>");
        field.addJavaDocLine("**/");
    }

解释:

  1. addFieldComment方法有重载,意思是是否标注当前属性对应数据库的那个字段,看个人需要选择性实现。

  2. IntrospectedTable实体类封装了数据库表对应的原始信息,相应的IntrospectedColumn则是封装了表中字段的原始信息,所有我们通过该对象获取到字段的注释,在添加到实体类的属性上.(我这个地方没有封装,源码中是封装了生成所有注释的通用方法,实际运用中可统一封装)。

  3. MyBatis将java中类、方法、接口、枚举、内部类、内部类枚举抽象成JavaElement对象,而Field则是针对类中属性的封装。

  4. 本人感觉xml文件中的注释多余,就实现addComment方法,不做任何的实现,去除xml中的原生注释;

自定义注解

在目前我们开发中,注解使用的非常广发,大大简化了我们的开发,比如:

  • LomBook针对实体类对象各种注解,最常用的@Data(@Setter,@Getter)、@NoArgsConstructor等。那能否再Model上自动添加上我们需要的注解呢?

  • 我们知道Spring Boot中Mapper接口对应的注解是@Repository注解,但原生生成时不会有该注解的,那要一个一个类手动添加吗?

针对以上需求,我们详细聊聊PluginAdapter。通过Idea查看该类的结构,可以看到该中方法非常之多,但可分为:

  • clientxxxx相关的方法控制Mapper接口生成规则,细粒度到每个能够生成的方法上

  • sqlMapxxxx相关方法控制xml文件生成的方式,细粒度到每个能够生成的方法上;

  • modelxxxx相关方法控制Model类的生成规则。model类的生成规则有三种,所以model相关的方法也是关于三种规则生成时的相关方法;
    针对以上需求,我们逐个击破:

  1. 生成的Model上增加Lombook相关的注释,继承PluginAdapter类,重写modelBaseRecordClassGenerated方法,具体如下:
@Override
    public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        javaTypes().forEach(item->topLevelClass.addImportedType(item));
        addAnnons().forEach(item->topLevelClass.addAnnotation(item));
        return super.modelBaseRecordClassGenerated(topLevelClass, introspectedTable);
    }
    //注解对应的完整的类路径
    private List<FullyQualifiedJavaType> javaTypes(){
        List<FullyQualifiedJavaType> javaTypes = new ArrayList<>(2);
        javaTypes.add(new FullyQualifiedJavaType("lombok.Data"));
        javaTypes.add(new FullyQualifiedJavaType("lombok.NoArgsConstructor"));
        return javaTypes;
    }
    //需要添加的注解
    private List<String> addAnnons(){
        List<String> annons = new ArrayList<>(2);
        annons.add("@Data");
        annons.add("@NoArgsConstructor");
        return annons;
    }

通过上面方法,在生成Model时会自动添加上相应的注解;再比如:Spring Boot的Swagger也是通过注解,如果返回前端的实体类也是通过Mybatis Generator自动生成,那么就可以将@ApiModel以及@ApiModelProperty注解添加到生成的类中;是不是特别的方便;

xml文件的两种模式

在MyBatis生成的xml默认是append的方式,比如:随着需求版本的迭代,数据库中的字段改变,对应的实体类以及xml需要重新生成,那么默认新生成的xml内容,会追加到旧的版本中,这时启动项目会报错(resultMap标签重复),所以这时需要将旧的覆盖掉;
此时我们要干预xml文件的生成方式,那么继承PluginAdaptor重写sqlMapGenerated方法。该方法中GeneratedXmlFile参数是封装xml文件的所有属性,其中私有属性isMergeable即是否合并的意思,默认为false,那么我们现在就要改变该属性的值。可惜的是该属性没有公开,需要通过反射改变,具体如下:

    @Override
    public boolean sqlMapGenerated(GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) {
        try {
            Field field = sqlMap.getClass().getDeclaredField("isMergeable");
            field.setAccessible(true);
            field.setBoolean(sqlMap, false);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return true;
    }

在生成时就会覆盖原来的旧文件。那如果自定义的sql也写在该文件,那么也会被覆盖,目前我实践的解决方案有两种:

  1. 通过版本管理工具控制。比如git,被覆盖掉的方法,都会有提示或者能够重新回退到最近的一个版本,方法就可以再找回来;
  2. 分两个xml文件,同一个Mapper接口对应两个xml,一个是自动生成的,永远保存自动生成的,另外在创建一个自定义的sql语句的xml文件。
    个人推荐第二种,最不易出错。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容