• Mybatis增强组件


    组件编码 hzero-starter-mybatis-mapper

    一、简介

    1.1 概述

    增强ORM框架Mybatis的数据库DML处理能力,支持分页、数据多语言、基于对象的SQL编写,数据防篡改等功能。

    1.2 组件坐标

    <dependency>
        <groupId>org.hzero.starter</groupId>
        <artifactId>hzero-starter-mybatis-mapper</artifactId>
        <version>${hzero.starter.version}</version>
    </dependency>
    

    1.3 特性

    二、组件功能

    2.1 CRUD支持

    2.1.1 新增支持

    @Options(useGeneratedKeys = true, keyProperty = "主键名称")
    @InsertProvider(type = SpecialProvider.class, method = "dynamicSql")
    int insertList(List<T> recordList);
    

    2.1.2 更新支持

    2.1.3 删除支持

    2.1.4 查询支持

    mapper.selectByCondition(
        org.hzero.mybatis.domian.Condition.builder(Entity.class)
        .andWhere(
            org.hzero.mybatis.util.Sqls.custom()
                .andEqualTo(FIELD1, VALUE1)
                .andLike(FIELD2, VALUE2)
        ).build()
    );
    
    // Entity
    @Table(name = "hmsg_user_receive_config")
    class UserReceiveConfig extends AuditDomain {
        // other field ...
        @Where
        private Long userId;
        @ApiModelProperty(value = "hmsg_receive_config .receiver_code", required = true)
        @JoinTable(name = "receiveConfigJoin", target = ReceiveConfig.class, on = @JoinOn(joinField = ReceiveConfig.FIELD_RECEIVE_CODE))
        private String receiveCode;
        @Transient
        @JoinColumn(joinName = "receiveConfigJoin", field = ReceiveConfig.FIELD_DEFAULT_RECEIVE_TYPE)
        private String defaultReceiveType;
        // getter and setter ...
    }
    
    // Entity
    @Table(name = "hmsg_receive_config")
    class ReceiveConfig extends AuditDomain {
        // other field ...
        private String receiveCode;
        private String defaultReceiveType;
        // getter and setter ...
    }
    
    // Repository
    userReceiveConfigRepository
        .selectOptional(new UserReceiveConfig().setUserId(1L), 
                new Criteria().select("userReceiveId", "receiveCode", "receiveType", "defaultReceiveType", "userId"));
    
    
    -- Result SQL
    SELECT 
        A.object_version_number, 
        A.user_receive_id, 
        A.receive_code, 
        A.receive_type, 
        B.default_receive_type AS default_receive_type, 
        A.user_id 
    FROM 
        hmsg_user_receive_config A 
        INNER JOIN hmsg_receive_config B 
            ON A.receive_code = B.receive_code 
    WHERE 
        (A.user_id = ?) 
    
    

    2.2 多语言支持

    2.2.1 功能说明

    2.2.2 使用说明

    1. 创建表时创建对应的多语言表,多语言表的表明需要在原表明的基础上增加_tl,所以在设计多语言表的时候主表表名长度不要超过23,以免多语言表字段长度超出限制,多语言表中需要包含对应表的主键,以及需要多语言的列,再加上lang varchar(30)字段。
    2. 在数据库对应的多语言java实体类上继承io.choerodon.mybatis.domain.AuditDomain类,添加@io.choerodon.mybatis.annotation.MultiLanguage注解,在对应的多语言列上添加@io.choerodon.mybatis.annotation.MultiLanguageField注解
    3. 新增/更新数据时,实体类json中需要添加多语言map,结构示例:
    {
        // other field ...
        _tls:{
        roleName : {
            zh_CN : '管理员',
            en_GB : 'Admin'
        },
        description : {
            zh_CN : '管理员',
            en_GB : 'administrator'
        }
    }
    }
    
    <select id="selectEntity" resultType="c.x.Entity">
        <bind name="lang" value="@io.choerodon.mybatis.helper.LanguageHelper@language()"/>
        SELECT
            t.id,
            ttl.multi_lang
            -- other column ..
        FROM table1 t
            JOIN table1_tl ttl ON t.id = ttl.id AND ttl.lang = #{lang}
        WHERE
            -- condition
    </select>
    

    2.3 数据防篡改

    2.3.1 功能说明

    2.3.2 使用说明

    1. 如果是和数据库对应的实体类,只需要继承io.choerodon.mybatis.domain.AuditDomain即可,如果是自定义的VO/DTO,也可以继承AuditDomain类,或者实现org.hzero.mybatis.domian.SecurityToken接口,接口中的set_token方法用于往VO/DTO中保存加密信息,get_token方法用于获取VO/DTO中保存的加密信息,associateEntityClass方法用于将VO/DTO与数据库对应的实体类关联在一起,需要注意在VO/DTO中必须和实体类主键属性
    2. 在更新数据前调用org.hzero.mybatis.helper.SecurityTokenHelper#validToken(..)方法校验主键有没有被篡改。
    class Entity extends io.choerodon.mybatis.domain.AuditDomain {
        @Id
        private long id;
        // other field ...
        // getter and setter ...
    }
    
    class EntityDTO implements org.hzero.mybatis.domian.SecurityToken {
        private long id;
        // other field ...
        // getter and setter ...
        private String _token;
        @Override
        public void set_token(String _token) {
            this._token = _token;
        }
        @Override
        public String get_token() {
            return this._token;
        }
        @Override
        public Class<? extends SecurityToken> associateEntityClass() {
            return Entity.class;
        }
    }
    
    // controller
    // GET
    public ResponseEntity<List<EntityDTO>> selectEntity(...){
        List<EntityDTO> list = // select ...
        return Results.success(list)
    }
    // PUT
    public ResponseEntity<Entity> updateEntity(Entity entity){
        org.hzero.mybatis.helper.SecurityTokenHelper.validToken(entity);
        // update ...
    }
    

    2.4 数据加密存储

    2.4.1 功能说明

    2.4.2 使用说明

    1. 在数据库对应的实体类只需要加密的字段上添加@org.hzero.mybatis.annotation.DataSecurity注解。
    2. 在新增/更新数据之前,调用org.hzero.mybatis.helper.DataSecurityHelper#open方法开启数据加密
    3. 在查询数据之前,调用org.hzero.mybatis.helper.DataSecurityHelper#open方法开

    2.5 租户条件过滤

    2.5.1 功能说明

    2.5.2 使用说明

    1.注解模式,此模式针对使用平台封装好的查询方法生效。

    1.1 在Controller类方法上添加注解@org.hzero.mybatis.annotation.TenantLimitedRequest注解,默认SQL拼装为IN模式,如:

    WHERE 1 = 1
      AND tenant_id IN (可访问租户ID列表)
    

    1.2 设置注解属性TenantLimitedRequest(equal=true),SQL拼装为=模式,如:

    WHERE 1 = 1
      AND tenant_id = (当前租户ID)
    
    1. 针对自定义Mapper的SQL语句,注解方式不支持自动改写,需要在Mapper中使用bind的方式进行引用

    2.1 获取可访问租户列表函数,示例:

    <bind name="__tenantIds" value="@org.hzero.mybatis.helper.TenantLimitedHelper@tenantIds()" />
    

    引入后,在使用到的地方进行使用,如:

    <if test="__tenantIds != null and !__tenantIds.isEmpty()">
      and tenant_id in 
      <foreach colletion="__tenantIds" item="__tenantId" separator="," open="(" close=")">
        #{__tenantId}
      </foreach>
    </if>
    

    2.2 获取当前租户函数,示例:

    <bind name="__tenantId" value="@org.hzero.mybatis.helper.TenantLimitedHelper@tenantId()" />
    

    引入后,在使用到的地方进行使用,如:

    <if test="__tenantId != null">
      and tenant_id = #{__tenantId}
    </if>
    

    2.6 数据唯一校验

    2.6.1 功能说明

    2.6.2 使用说明

    1. 声明唯一校验字段:在Entity需要校验唯一的字段上添加注解@org.hzero.mybatis.annotation.Unique
    2. 调用校验方法:org.hzero.mybatis.helper.UniqueHelper#valid(T)方法,该方法返回一个布尔值,如果返回true表示校验通过,返回false表示数据已存在。
    Assert.isTrue(UniqueHelper.valid(bank), BaseConstants.ErrorCode.DATA_EXISTS);
    

    2.7 自定义主键策略

    2.6.1 雪花ID

    雪花ID是Twitter推出的分布式全局唯一ID的一套解决方案,相比于UUID,雪花ID有以下优点:

    雪花ID结构:

    0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
    

    配置属性:

    mybatis:
      configuration:
        key-generator: snowflake
        snowflake:
          start-timestamp: 1577808000000
          meta-provider: redis
          meta-provider-redis-db: 1
          meta-provider-redis-refresh-interval: 540000
          meta-provider-redis-expire: 600000
          data-center-id: 1
          worker-id: 1
    

    **注意:**一般来说只需要指定key-generator: snowflake就可以了,其他的配置都有默认值,按需设置

    三、版本更新日志

    0.8.0.RELEASE [2019-03-29]