一、Mybatis-Plus介绍

Mybatis-plus是Mybatis的增强工具包,其官网的介绍如下:

  • 润物细无声:只做增强不做改动,引进它不会对现有工程发生影响,如丝般顺滑。
  • 效率至上:只需简略装备,即可快速进行单表CRUD操作,然后节约大量时刻。
  • 丰厚功用:代码生成、主动分页、逻辑删去、主动填充等功用一应俱全。

其长处如下:

  • 无侵入:Mybatis-Plus 在 Mybatis 的基础上进行扩展,只做增强不做改动,引进 Mybatis-Plus 不会对您现有的 Mybatis 构架发生任何影响,并且 MP 支撑所有 Mybatis 原生的特性
  • 依靠少:只是依靠 Mybatis 以及 Mybatis-Spring
  • 损耗小:启动即会主动注入根本CURD,功用根本无损耗,直接面向目标操作
  • 通用CRUD操作:内置通用 Mapper、通用 Service,只是经过少量装备即可完结单表大部分 CRUD 操作,更有强壮的条件结构器,满意各类运用需求
  • 多种主键战略:支撑多达4种主键战略(内含分布式仅有ID生成器),可自在装备,完美解决主键问题
  • 支撑ActiveRecord:支撑 ActiveRecord 办法调用,实体类只需继承 Model 类即可完结根本 CRUD 操作
  • 支撑代码生成:选用代码或许 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支撑模板引擎,更有超多自定义装备等您来运用(P.S. 比 Mybatis 官方的 Generator 愈加强壮!)
  • 支撑自定义大局通用操作:支撑大局通用办法注入( Write once, use anywhere )
  • 内置分页插件:基于Mybatis物理分页,开发者无需关心具体操作,装备好插件之后,写分页等同于写根本List查询
  • 内置功用分析插件:可输出Sql句子以及其执行时刻,建议开发测验时启用该功用,能有用解决慢查询
  • 内置大局阻拦插件:供给全表 delete 、 update 操作智能分析阻断,预防误操作

二、Spring boot 整合Mybatis-plus

2.1 pom中引进Mybatis-plus依靠

<!--https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>

注:假如是gradle,引进的办法如下:

implementation group: ‘com.baomidou’, name: ‘mybatis-plus-boot-starter’, version: ‘3.5.3.1’

2.2 创立一张User表

创立对应的数据表 Schema 的表结构和表数据:

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `user_base_info`
-- ----------------------------
DROP TABLE IF EXISTS `user_base_info`;
CREATE TABLE `user_base_info` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `u_id` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户ID',
  `name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
  `cn_name` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '中文名',
  `sex` char(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '性别',
  `alias` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '别名',
  `web_chat` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '微信号',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

表中插入数据

-- ----------------------------
-- Records of user_base_info
-- ----------------------------
INSERT INTO `user_base_info` VALUES ('1', '001', 'holmium', '钬', '1', '虎啸山村', 'holmium');
INSERT INTO `user_base_info` VALUES ('2', '001', 'test', '测验', '0', '美女', '虎啸山村');

2.3 Mybatis-plus装备

#mybatis-plus
mybatis-plus:
##这个能够不必装备,因其默认就是这个途径
mapper-locations:classpath:/mapper/*Mapper.xml
#实体扫描,多个package用逗号或许分号分隔
typeAliasesPackage:com.holmium.springboot.repository.*.entity
global-config:
#数据库相关装备
db-config:
#主键类型AUTO:"数据库ID自增",INPUT:"用户输入ID",ID_WORKER:"大局仅有ID(数字类型仅有ID)",UUID:"大局仅有IDUUID";
id-type:AUTO
#字段战略IGNORED:"疏忽判断",NOT_NULL:"非NULL判断"),NOT_EMPTY:"非空判断"
field-strategy:not_empty
#驼峰下划线转化
column-underline:true
#数据库大写下划线转化
#capital-mode:true
#逻辑删去装备
logic-delete-value:0
logic-not-delete-value:1
db-type:h2
#改写mapper调试神器
refresh:true
#原生装备
configuration:
map-underscore-to-camel-case:true
cache-enabled:false

2.4 创立一个实体

//BasePo,后续能够继续扩展
@Data
publicclassBasePo{
@TableId(value="id",type=IdType.AUTO)
privateIntegerid;
}
packagecom.holmium.springboot.infra.user.entity;
importcom.baomidou.mybatisplus.annotation.TableField;
importcom.baomidou.mybatisplus.annotation.TableName;
importlombok.Getter;
importlombok.Setter;
/**
*@authorholmium
*@description:
*@date2023年04月20日16:19
*/
@TableName(value="user_base_info",autoResultMap=true)
@Getter
@Setter
publicclassUserPoextendsBasePo{
/**
*用户ID
*/
@TableField(value="u_id")
StringuId;
/**
*用户名
*/
@TableField(value="name")
Stringname;
/**
*中文名称
*/
@TableField(value="cn_name")
StringcnName;
/**
*性别:1-男0-女
*/
@TableField(value="sex")
Stringsex;
/**
*别名
*/
@TableField(value="alias")
Stringalias;
/**
*微信号
*/
@TableField(value="web_chat")
StringwebChat;
}

2.5 创立一个Mapper接口

packagecom.holmium.springboot.infra.user.mapper;
importcom.baomidou.mybatisplus.core.mapper.BaseMapper;
importcom.holmium.springboot.infra.user.entity.UserPo;
importorg.apache.ibatis.annotations.Mapper;
@Mapper
publicinterfaceUserMapperextendsBaseMapper<UserPo>{
}

2.6 修正服务接口

//假如不理解,能够看之前的文章
@RestController
@RequestMapping("/user/center")
publicclassUserApi{
@Resource
UserAppImpluserApp;

@GetMapping(value="/userinfo")
publicUserVogerUserInfo(@RequestParam("id")Stringid)throwsException{
returnuserApp.getUserInfoByUserId(id);
}
}

2.7 在启动类中增加 @MapperScan 注解,扫描 Mapper 文件夹

@SpringBootApplication
@MapperScan("com.holmium.springboot.infra.*.mapper")//增加mapper扫描
publicclassHolmiumApplication{
publicstaticvoidmain(String[]args){
SpringApplication.run(HolmiumApplication.class,args);
}
}

2.8 测验

Spring boot 集成mybatis-plus

Spring boot 集成mybatis-plus

Spring boot 集成mybatis-plus

2.9 小结

经过以上的步骤,咱们完结了对User表的查询功用,能够看到对于简略的CRUD操作,Mybatis-Plus只需要定义一个Mapper接口即可完结,真实做到如他所说的那样,简略装备、效率至上。

三、Mybatis-plus 部分字段注解和查询

3.1 主键

3.1.1 主键生成战略

主键生成战略总共供给的五种:

AUTO(0),递加战略,假如运用该战略必须要求数据表的列也是递加。
NONE(1),没有战略,必须人为的输入id值
INPUT(2),没有战略,必须人为的输入id值
ASSIGN_ID(3), 随机生成一个Long类型的值。该值一定是仅有。并且每次生成都不会相同。算法:雪花算法。 适合分布式主键。
ASSIGN_UUID(4); 随机发生一个String类型的值。该值也是仅有的。

3.1.2 运用办法

经过装备文件中,装备id-type特点:

mybatis-plus:
global-config:
#数据库相关装备
db-config:
#主键类型AUTO:"数据库ID自增",INPUT:"用户输入ID",ID_WORKER:"大局仅有ID(数字类型仅有ID)",UUID:"大局仅有IDUUID";
id-type:AUTO

也可在目标特点上进行注解设置:

@Data
publicclassBasePo{
//装备为数据库ID自增
@TableId(value="id",type=IdType.AUTO)
privateIntegerid;
}

3.2 删去

实际开发过程中,对数据都不会直接删去,都会选用逻辑删去的办法。所谓的逻辑删去,只是将数据置为一个状况,这个状况代表数据为删去状况,一般自己程序中写的话,就设置一个状况字段,给字段赋值为0D代表删去。而Mybatis-plus供给了@TableLogic注解,完结逻辑删去。 只对主动注入的 sql 起效:

  • 插入: 不作限制
  • 查找: 追加 where 条件过滤掉已删去数据,且运用 wrapper.entity 生成的 where 条件会疏忽该字段
  • 更新: 追加 where 条件避免更新到已删去数据,且运用 wrapper.entity 生成的 where 条件会疏忽该字段
  • 删去: 转变为 更新
@Data
publicclassBasePo{
/**
*主键
*/
@TableId(value="id",type=IdType.AUTO)
privateIntegerid;
/**
*是否删去:0表明未删去1表明删去.
*/
@TableLogic
privateBooleandeleted;
}

3.3 主动填充

实际开发中,咱们会在表中记录数据创立时刻、创立人、修正时刻、修正人几个字段,可是几个字段假如咱们每次都要进行赋值,代码比较冗余,Mybatis-plus供给的主动填充功用。

3.3.1 增加公共特点目标:

@Data
publicclassBasePo{
/**
*主键
*/
@TableId(value="id",type=IdType.AUTO)
privateIntegerid;
/**
*创立时刻
*/
@TableField(fill=FieldFill.INSERT)
@JsonFormat(pattern="yyyy-MM-ddHH:mm:ss")
privateDatecreateTime;
/**
*最终更新时刻
*/
@TableField(fill=FieldFill.INSERT_UPDATE)
@JsonFormat(pattern="yyyy-MM-ddHH:mm:ss")
privateDateupdateTime;
/**
*创立者,默认体系User的id编号
*<p>
*运用String类型的原因是,未来可能会存在非数值的状况,留好拓展性。
*/
@TableField(fill=FieldFill.INSERT,jdbcType=JdbcType.VARCHAR)
privateStringcreator;
/**
*更新者,默认体系User的id编号
*<p>
*运用String类型的原因是,未来可能会存在非数值的状况,留好拓展性。
*/
@TableField(fill=FieldFill.INSERT_UPDATE,jdbcType=JdbcType.VARCHAR)
privateStringupdater;
/**
*是否删去
*/
@TableLogic
privateBooleandeleted;
}

3.3.2 自定义完结类 MyMetaObjectHandler

publicclassDefaultDbFieldHandlerimplementsMetaObjectHandler{
@Override
publicvoidinsertFill(MetaObjectmetaObject){
if(Objects.nonNull(metaObject)&&metaObject.getOriginalObject()instanceofBaseEntity){
BaseEntitybaseDO=(BaseEntity)metaObject.getOriginalObject();

Datecurrent=newDate();
//创立时刻为空,则以当时时刻为插入时刻
if(Objects.isNull(baseDO.getCreateTime())){
baseDO.setCreateTime(current);
}
//更新时刻为空,则以当时时刻为更新时刻
if(Objects.isNull(baseDO.getUpdateTime())){
baseDO.setUpdateTime(current);
}

LonguserId=WebUtils.getLoginUserId();
//当时登录用户不为空,创立人为空,则当时登录用户为创立人
if(Objects.nonNull(userId)&&Objects.isNull(baseDO.getCreator())){
baseDO.setCreator(userId.toString());
}
//当时登录用户不为空,更新人为空,则当时登录用户为更新人
if(Objects.nonNull(userId)&&Objects.isNull(baseDO.getUpdater())){
baseDO.setUpdater(userId.toString());
}
}
}

@Override
publicvoidupdateFill(MetaObjectmetaObject){
//更新时刻为空,则以当时时刻为更新时刻
ObjectmodifyTime=getFieldValByName("updateTime",metaObject);
if(Objects.isNull(modifyTime)){
setFieldValByName("updateTime",newDate(),metaObject);
}

//当时登录用户不为空,更新人为空,则当时登录用户为更新人
Objectmodifier=getFieldValByName("updater",metaObject);
LonguserId=WebUtils.getLoginUserId();
if(Objects.nonNull(userId)&&Objects.isNull(modifier)){
setFieldValByName("updater",userId.toString(),metaObject);
}
}
}

3.4 条件查询

3.4.1 根据各种条件查询

Wrapper:封装了关于查询的各种条件办法。

有三个子类最常用: LambdaQueryWrapper查询条件 LambdaUpdateWrapper修正条件 LambdaQueryWrapper查询运用lambda表达式条件

  • LambdaQueryWrapper

    selectPage(userDo,newLambdaQueryWrapperX<UserPo>()
    .likeIfPresent(UserPo::getName,userDo.getName())
    .likeIfPresent(UserPo::getSex,userDo.getSex())
    .betweenIfPresent(UserPo::getCreateTime,userDo.getCreateTime())
    .orderByDesc(UserPo::getId))
    
  • LambdaUpdateWrapper

update(update,newLambdaUpdateWrapper<UserPo>()
.eq(UserPo::getId,id).eq(UserPo::getName,name))
  • LambdaQueryWrapper

    newLambdaQueryWrapper<UserDo>()
    .eq(UserPo::getId,id)
    .eq(UserPo::getName,name);
    

3.5 分页查询

  • 增加分页阻拦器
@Bean
publicMybatisPlusInterceptormybatisPlusInterceptor(){
MybatisPlusInterceptormybatisPlusInterceptor=newMybatisPlusInterceptor();
//分页插件
mybatisPlusInterceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));
returnmybatisPlusInterceptor;
}
  • 分页查询
Page<UserPo>page=userMapper.selectPage(page,wrapper);//把查询的结果主动封装到Page目标中

3.5 小结

到此简略的查询根本已介绍完毕,可满意他80%的日常开发需求。

四、引进目标转化组件mapstruct

从上述代码中能够看到,咱们从数据库查询出来的结果是转化为一个想XXXPo的目标,而接口返回的是XXXVo目标。在实际项目中,一般一个project都会分很多层,每层都会定义自己的目标,如:PO、VO、DAO、BO、DTO、POJO等等。

  • DO(Data Object):此目标与数据库表结构一一对应,经过 DAO 层向上传输数据源目标。
  • DTO(Data Transfer Object):数据传输目标,Service 或 Manager 向外传输的目标。
  • BO(Business Object):事务目标,由 Service 层输出的封装事务逻辑的目标。
  • AO(ApplicationObject):使用目标,在Web层与Service层之间笼统的复用目标模型, 极为贴近展示层,复费用不高。
  • VO(View Object):显现层目标,通常是 Web 向模板烘托引擎层传输的目标。
  • POJO是DO/DTO/BO/VO的统称,禁止命名成xxxPOJO。

这些目标在传递过程中,需要相互转化,假如手工书写,往往会经过getxxx,再setxxx,操作起来十分繁琐,那有没有一种办法比较简略完结能?下面咱们介绍一个目标转化的组件mapstruct

4.1 pom中引进依靠包

<!--https://mvnrepository.com/artifact/org.mapstruct/mapstruct-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.4.Final</version>
</dependency>

4.2 创立一个Convert接口

packagecom.holmium.springboot.app.user.convert;
importcom.holmium.springboot.api.user.vo.UserVo;
importcom.holmium.springboot.common.user.app.dto.UserDto;
importorg.mapstruct.Mapper;
importorg.mapstruct.factory.Mappers;
/**
*@authorholmium
*@date2023年04月16日20:24
*/
@Mapper
publicinterfaceUserAppConvert{
UserAppConvertINSTANCES=Mappers.getMapper(UserAppConvert.class);
UserVovoToDto(UserDtouserDto);
}

避坑

这儿的@Mapper注解和上述Mybatis-plus中的@Mapper注解相同,很简单引进错误,导致会报错。

这儿的Mapperimport org.mapstruct.Mapper;

mybatis-plus中的@Mapper, import org.apache.ibatis.annotations.Mapper;

一定要注意看清楚引进的类

4.3 在类中引用

@Service
publicclassUserAppImplimplementsUserApp{
@Resource
publicUserDomainuserDomain;
@Override
publicUserVogetUserInfoByUserId(StringuserId)throwsException{
//这样就完结了目标转化
returnUserAppConvert.INSTANCES.voToDto(userDomain.getUserInfoByUid(userId));
}
}

4.4 目标特点不同怎样转化

上述是两个目标中特点相同话,能够不必做其他任何操作,就能够事项目标互转,但实际在开发中,两个目标特点不可能完全相同。而上述操作只能将相同特点做转化,不同的特点没法相互转化,导致目标有部分数据丢掉?那怎样解决,可在转化办法上参加@Mappings注解,如下:

@Mapper
publicinterfaceUserAppConvert{
UserAppConvertINSTANCES=Mappers.getMapper(UserAppConvert.class);
@Mappings({
//特点不一致转化
@Mapping(source="name",target="userName"),
//类型不一致转化
@Mapping(target="createTime",expression="java(com.java.mmzsblog.util.DateTransform.strToDate(source.getCreateTime()))"),
})
UserVovoToDto(UserDtouserDto);
}

这样就解决了不同目标特点和特点类型不一致转化问题。

五、写在最终

截止本篇文章,咱们现已将如何创立一个Spring boot 工程,如何开发一个服务,以及从数据库总获取数据根本已完结。根据这一系列文章,我们做日常的开发联络根本够。

后续章节将把druid和mybatis-plus的整合转化成starter的办法,对其做一定的封装。

同时咱们会将体系的使用架构转化成DDD模式架构,后续我将用多个篇幅介绍DDD架构。请继续重视盯梢。