跳至主要內容

mybatis-plus组件

杨轩-国实信息大约 4 分钟常用组件mybatismybatis-plusdatabase

基于mybatis-plus二次封装

组件封装目的时为了弥补mybatis-plus直接使用的不足,简化一些常用操作。

git地址:

http://10.16.202.103:8089/component/component-ser/gosci-mybatis-plus-starter

使用

项目中引入:

<dependency>
    <groupId>com.gosci.tech</groupId>
    <artifactId>gosci-mybatis-plus-starter</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

实体类

BaseMapper 接口

public interface BaseMapper<T>
	extends com.baomidou.mybatisplus.core.mapper.BaseMapper<T> {
}

BaseService 接口

接口的default方法可以定义方法体。

public interface BaseService<T> extends IService<T> {

	/**
     * 根据 model 条件,删除记录
     * @param entity 实体对象封装操作类(可以为 null)
     * @return boolean
     */
	default boolean remove(T entity) {
		return remove(Wrappers.query(entity));
	}
	
	/**
     * 根据 model 条件,查询一条记录
     * @param entity 实体对象
     * @param throwEx 是否抛出异常
     * @return T
    */
	default T getOne(T entity, boolean throwEx) {
		return getOne(Wrappers.query(entity).last("LIMIT 1"), throwEx);
	}
	
	/**
	 * 根据 model 条件,查询一条记录
	 * @param entity 实体对象
	 * @return T
	 */
	default T getOne(T entity) {
		return getOne(Wrappers.query(entity).last("LIMIT 1"), false);
	}
	
	/**
	 * 获取map
	 * @param entity 对象
	 * @return Map<String, Object>
	 */
	default Map<String, Object> getMap(T entity) {
		return getMap(Wrappers.query(entity));
	}
	
	/**
	 * 查询数量通过实体类
	 * @param entity 对象
	 * @return Integer
	 */
	default long count(T entity) {
		return count(Wrappers.query(entity));
	}
	
	/**
	 * 查询集合通过实体类
	 * @param entity 对象
	 * @return List<T>
	 */
	default List<T> list(T entity) {
		return list(Wrappers.query(entity));
	}
	
	/**
	 * 查询返回map
	 * @param entity 对象
	 * @return List<Map<String, Object>>
	 */
	default List<Map<String, Object>> listMaps(T entity) {
		return listMaps(Wrappers.query(entity));
	}

	/**
	 * 通过条件获取分页
	 * @param pageNo No
	 * @param pageSize Size
	 * @param queryWrapper wrapper
	 * @return {@link IPage<T>}
	 */
	default IPage<T> page(int pageNo, int pageSize, Wrapper<T> queryWrapper){
		return page(new Page<>(pageNo,pageSize), queryWrapper);
	}

	/**
	 * 通过条件获取分页
	 * @param pageNo No
	 * @param pageSize Size
	 * @param queryWrapper Wrapper
	 * @return  分页数据
	 */
	default IPage<Map<String, Object>> pageMaps(int pageNo, int pageSize, Wrapper<T> queryWrapper){
		return pageMaps(new Page<>(pageNo,pageSize), queryWrapper);
	}
}

BaseServiceImpl 类

提供事务管理器。

@AllArgsConstructor
@NoArgsConstructor
public class BaseServiceImpl<M extends BaseMapper<T>, T> 
	extends com.baomidou.mybatisplus.extension.service.impl.ServiceImpl<M, T> implements BaseService<T> {

	@NotNull
	private PlatformTransactionManager transactionManager;
}

使用示例

以下代码可使用脚手架自动生成代码生成,这里省略Model和Controller层自动生成代码。

Mapper

@Mapper
public interface IBusinessDirectoryMapper extends BaseMapper<BusinessDirectory> {
}

Service

public interface IBusinessDirectoryService extends BaseService<BusinessDirectory> {
}

ServiceImpl

@Service
@Transactional
@AllArgsConstructor
public class BusinessDirectoryServiceImpl
    extends BaseServiceImpl<IBusinessDirectoryDao, BusinessDirectory>
    implements IBusinessDirectoryService {
}    

在serviceImpl中可以直接使用简化后的方法。

其他功能

统一标准数据库字段

数据库建表时,建议统一添加下列字段:

`create_by` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '更新人',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志,0:未删除;1:已删除',

字段常量定义

public interface MybatisPlusConsts {

    /**
     * 版本号
     */
    String VERSION = "version";

    /**
     * 创建人
     */
    String CREATE_BY = "createBy";

    /**
     * 创建时间
     */
    String CREATE_TIME = "createTime";
    /**
     * 创建时间
     */
    String CREATE_DATE = "createDate";
    /**
     * 更新人
     */
    String UPDATE_BY = "updateBy";

    /**
     * 更新时间
     */
    String UPDATE_TIME = "updateTime";
    /**
     * 更新时间
     */
    String UPDATE_DATE = "updateDate";
    /**
     * 数据标识
     */
    String DEL_FLAG = "delFlag";
}

属性自动填充

通过定义MetaObjectHandler可以实现一些特定字段的自动填充,例如数据的创建时间、创建人等。

@Slf4j
@Component
public class MybatisPlusMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        // createBy 创建人
        boolean createByOf = metaObject.hasSetter(MybatisPlusConsts.CREATE_BY);
        if (createByOf && currentLogin()) {
            this.strictInsertFill(metaObject, MybatisPlusConsts.CREATE_BY, String.class, getCurrentUser());
        }

        // createDate 创建时间
        boolean createTimeOf = metaObject.hasSetter(MybatisPlusConsts.CREATE_TIME);
        if (createTimeOf) {
            this.strictInsertFill(metaObject, MybatisPlusConsts.CREATE_TIME, LocalDateTime.class, getNow());
        }

        boolean createDateOf = metaObject.hasSetter(MybatisPlusConsts.CREATE_DATE);
        if (createDateOf) {
            this.strictInsertFill(metaObject, MybatisPlusConsts.CREATE_DATE, LocalDateTime.class, getNow());
        }

        // version 版本号
        boolean versionOf = metaObject.hasSetter(MybatisPlusConsts.VERSION);
        if (versionOf) {
            this.strictInsertFill(metaObject, MybatisPlusConsts.VERSION, Integer.class, 0);
        }

        // delFlag 数据状态
        boolean delFlagOf = metaObject.hasSetter(MybatisPlusConsts.DEL_FLAG);
        if (delFlagOf) {
            this.strictInsertFill(metaObject, MybatisPlusConsts.DEL_FLAG, Integer.class, 0);
        }
    }    
    

    @Override
    public void updateFill(MetaObject metaObject) {
        // updateBy 更新人
        boolean updateByOf = metaObject.hasSetter(MybatisPlusConsts.UPDATE_BY);
        if (updateByOf && currentLogin()) {
            this.strictUpdateFill(metaObject, MybatisPlusConsts.UPDATE_BY, String.class, getCurrentUser());
        }

        // updateDate 更新时间
        boolean updateTimeOf = metaObject.hasSetter(MybatisPlusConsts.UPDATE_TIME);
        if (updateTimeOf) {
            this.strictUpdateFill(metaObject, MybatisPlusConsts.UPDATE_TIME, LocalDateTime.class, getNow());
        }

        // updateDate 更新时间
        boolean updateDateOf = metaObject.hasSetter(MybatisPlusConsts.UPDATE_DATE);
        if (updateDateOf) {
            this.strictUpdateFill(metaObject, MybatisPlusConsts.UPDATE_DATE, LocalDateTime.class, getNow());
        }
    }    
    
}

获取用户信息接口getCurrentUser()根据项目中实际情况实现。

实体类添加注解使用:

public class Role{
    @TableId(type = IdType.AUTO)
    private Integer id;

    private String roleName;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.UPDATE)
    private LocalDateTime updateTime;
}

自定义转换器

例如可自定义JsonNodeTypeHandler将对象转换成json字符串保存到数据库中, 将数据库中的json字符串映射成对象。

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName(value = "api_datasource", autoResultMap = true)
@ApiModel(value = "ApiDatasource对象", description = "【api数据源】表")
public class ApiDatasource implements Serializable {
    private static final long serialVersionUID = 1L;

    /**  */
    @ApiModelProperty(value = "")
    @TableId(value = "ID", type = IdType.AUTO)
    private Long id;
    
    @ApiModelProperty(value = "MQ参数")
    @TableField(value = "MQ_PARAM", typeHandler = JsonNodeTypeHandler.class)
    private JsonNode mqParam;
}

JsonNodeTypeHandler实现:

import com.fasterxml.jackson.databind.JsonNode;
import com.gosci.tech.utils.json.JsonUtils;

@MappedTypes(JsonNode.class)
@MappedJdbcTypes(JdbcType.LONGVARCHAR)
public class JsonNodeTypeHandler extends BaseTypeHandler<JsonNode> {

    /**
     * 设置非空参数
     * @throws SQLException 异常
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, JsonNode parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, String.valueOf(parameter.toPrettyString()));
    }

    /**
     * 根据列名,获取可以为空的结果
     */
    @Override
    public JsonNode getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String sqlJson = rs.getString(columnName);
        if (null != sqlJson) {
            return JsonUtils.read(sqlJson);
        }
        return null;
    }

    /**
     * 根据列索引,获取可以为空的结果
     */
    @Override
    public JsonNode getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String sqlJson = rs.getString(columnIndex);
        if (null != sqlJson) {
            return JsonUtils.read(sqlJson);
        }
        return null;
    }

    @Override
    public JsonNode getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String sqlJson = cs.getString(columnIndex);
        if (null != sqlJson) {
            return JsonUtils.read(sqlJson);
        }
        return null;
    }
}

配置分页插件和乐观锁插件

通过springboot的EnableAutoConfiguration注入配置类:

@Configuration(proxyBeanMethods = false)
@ComponentScan(basePackages = {"com.gosci.tech.mybatisplus"})
public class MybatisPlusAutoConfig {

    @Bean
    @ConditionalOnMissingBean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

乐观锁插件需要配合@Version注解及数据表中version字段使用,基于数据版本号实现并发控制。