开发者

一文详解Springboot集成mybatis-plus

目录
  • 一、MyBATis-Plus介绍
  • 二、Spring boot 整合Mybatis-plus
    • 2.1 pom中引入Mybatis-plus依赖
    • 2.2 创建一张User表
    • 2.3 Mybatis-plus配置
    • 2.4 创建一个实体
    • 2.5 创建一个Mapper接口
    • 2.6 修改服务接口
    • 2.7 在启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹
    • 2.8 测试
    • 2.9 小结
  • 三、Mybatis-plus 部分字段注解和查询
    • 3.1 主键
    • 3.1.1 主键生成策略
    • 3.1.2 使用方式
    • 3.2 删除
    • 3.3 自动填充
      • 3.3.1 增加公共属性对象:
      • 3.3.2 自定义实现类 MyMetaObjectHandler
    • 3.4 条件查询
      • 3.4.1 根据各种条件查询
    • 3.5 分页查询
      • 3.6 小结
      • 四、引入对象转换组件mapstruct
        • 4.1 pom中引入依赖包
          • 4.2 创建一个Convert接口
            • 4.3 在类中引用
              • 4.4 对象属性不同怎么转换
              • 五、写在最后

                一、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 ut开发者_JS开发f8mb4_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.getUserInfoByUserI编程客栈d(id);
                }
                }

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

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

                2.8 测试

                一文详解Springboot集成mybatis-plus

                一文详解Springboot集成mybatis-plus

                一文详解Springboot集成mybatis-plus

                2.9 小结

                通过以上的步骤,我们实现了对User表的查询功能,可以看到对于简单的CRUD操作,Mybatis-Plus只需要定义一个Mapper接口即可实现,真正做到如他所说的那样,简单配置、效率至上。

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

                3.1 主键

                3.1.1 主键生成策略

                主键生成策略一共提供的五种:

                AUTO(0),递增策略,如果使用该策python略必须要求数据表的列也是递增。
                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=JdbcTyhttp://www.devze.compe.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.6 小结

                到此简单的查询基本已介绍完毕,可满足他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架构。请持续关注跟踪。

                以上就是一文详解Springboot集成mybatis-plus的详细内容,更多关于Springboot集成mybatis-plus的资料请关注我们其它相关文章!

                0

                上一篇:

                下一篇:

                精彩评论

                暂无评论...
                验证码 换一张
                取 消

                最新开发

                开发排行榜