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字段使用,基于数据版本号实现并发控制。