tulip notes
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Star-Lord

希望一天成为大师的学徒
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 探索SpringBoot

  • 常用功能实现

  • Security认证授权

  • 扩展

    • Spring中的设计模式
    • 工作中常用的设计模式
    • 对接第三方接口的注意事项
    • MybatisPlus的使用跟扩展
      • 介绍
        • 分页插件
        • 快速实现实体类查询
        • 业务类的继承类【提高效率】
        • VO类的查询结果的处理
        • 增加字段
        • 减少字段
        • 自定义复杂连表查询
        • 多表查询
        • 映射别名跟ResultMap
        • 额外的参数
      • 注意事项
        • 关于别名
    • 数据加密与安全
  • 实战与注意事项

  • 其它

  • 《SpringBoot》笔记
  • 扩展
EffectTang
2025-03-31
目录

MybatisPlus的使用跟扩展

# MybatisPlus的使用跟扩展

# 介绍

不整虚的,直接来官网。它是什么呢,

MyBatis-Plus (opens new window) 是一个 MyBatis (opens new window) 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

  • 官网- https://baomidou.com/

本质是通过反射和动态代理,生成常用的sql的一个工具。

官网有快速入门,这里就不多做介绍了。下面介绍的是一些不常用的场景跟注意事项。

# 分页插件

以下是mybatisplus分页插件的配置,更多信息请查阅官网

@Configuration
public class MybatisPlusConfig {

    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
        // 添加分页插件
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 快速实现实体类查询

@Data
@TableName("`user`")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
1
2
3
4
5
6
7
8
  • mapper
public interface UserMapper extends BaseMapper<User> {

    Page<ExUser> selectPageVo(Page<ExUser> page, QueryWrapper queryWrapper);
}
1
2
3
4
  • xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sugar.mybatisplus_demo.mapper.UserMapper">

    <!-- 其他 SQL 语句 -->
    <select id="selectPageVo" resultMap="com.sugar.mybatisplus_demo.bean.ExUser">
        select * from user
    </select>
</mapper>
1
2
3
4
5
6
7
8
9

如此一来继承BaseMapper后,UserMapper ,就会拥有一些常用的sql操作。

当然还有复杂操作

Page<User> page = new Page<>(1, 2);
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(User::getName, "小")
                        .eq(User::getAge, 18);
        userMapper.selectPage(page,queryWrapper);
1
2
3
4
5

# 业务类的继承类【提高效率】

@Service
@Slf4j
public class XxxxServiceImpl extends ServiceImpl<XxxxMapper, XxxxEntity> implements XxxxService {
	// ........其他正常的业务注入与业务代码
}

1
2
3
4
5
6

使用mybatisplus开发时,常会看到以上代码。

这样写法的作用,其中 implements XxxxService 为我自己定义的接口类,与框架无关,实际需要的是 extends ServiceImpl<XxxxMapper, XxxxEntity> 这一部分。

  • ServiceImpl<M, T> 是 MyBatis-Plus 框架提供的通用 Service 实现类,封装了常见的 CRUD 操作,减少了重复代码的编写。
  • 两个泛型参数:
    • XxxxMapper:你的 Mapper 接口(需继承 MyBatis-Plus 的 BaseMapper)。
    • XxxxEntity:实体类(对应数据库表)。

在使用 ServiceImpl 时,你通常会创建自己的服务实现类,继承自 ServiceImpl,并指定相应的 Mapper 接口(接口记得继承对应BaseMapper)和实体类。这样,你的服务类就继承了一系列 CRUD(创建、读取、更新、删除)操作。

它的内部向我们提供了 如下公共方法,可以直接使用,甚至还为我们添加了事务回滚。

  1. 简化CRUD操作:通过继承ServiceImpl类,XXxxxServiceImpl自动获得了MyBatisPlus提供的基础CRUD(增删改查)操作方法,如save、remove、getById、list等。这大大减少了手动编写这些方法的工作量,提高了开发效率。
  2. 事务管理:ServiceImpl类中包含了对事务的处理,例如批量插入、更新和删除操作的事务支持。这意味着在进行这些操作时,可以确保数据的一致性和完整性。
  3. 泛型支持:ServiceImpl<XXxxxoMapper, XXxxx>中的泛型参数指定了具体的Mapper接口和实体类。这样,``XXxxxServiceImpl就可以针对XXxxx`实体进行操作,而不需要重复编写针对该实体的数据库操作代码。
  4. 接口实现:通过实现IXXxxxService接口,XXxxxServiceImpl可以定义和实现特定于业务逻辑的方法。这使得服务层的代码更加模块化和易于维护。
  5. 代码复用:继承ServiceImpl类意味着可以复用MyBatisPlus提供的通用方法,避免了重复代码的编写。同时,通过实现自定义的接口,可以在需要时扩展特定的功能

换句话说,在该业务类中,我们不需要注入对应Mapper文件,直接

this.mapper.xxx
1

即可操作持久层。

总结下,这样写的作用,主要是完成了以下2个目的:

  • 自动注入 Mapper 继承后无需手动注入 XxxxMapper,父类会通过泛型自动完成 Mapper 的绑定。
  • 获得现成的 CRUD 方法 直接使用父类提供的通用方法

# VO类的查询结果的处理

通常情况下,有些实体类的查询结构是不能直接展示给前端的,需要进行一些处理,比如,增加字段,或者合并2个结果,下面就展示几个解决方案。

# 增加字段

//  增加 景区字段 done
List<String> sellPoints = new ArrayList<String>();
// OrderId
List<Long> orderIdLists = new ArrayList<Long>();
for (SOrderBaseinfoVo vo:list) {
    orderIdLists.add(vo.getOrderId());
}
// 产品Id
List<Long> productIdList = new ArrayList();
for (Long orderId:orderIdLists) {
    com.cdtskj.vo.front.SOrderGoodsVo byOrderIdDetail = orderGoodsService.getByOrderIdDetail(orderId);
    productIdList.add(byOrderIdDetail.getProductId());
}
for (Long productId:productIdList) {
    SProduct sProduct = productService.getBaseMapper().selectById(productId);
    sellPoints.add(sProduct.getSellpoint());
}
//  关键代码 在次
List<SOrderBaseinfoVoEx> orderAndSellPoints = BeanUtil.copyListProperties(list,
        SOrderBaseinfoVoEx::new);
// SOrderBaseinfoVoEx 该类的DynamicAttribute 是一个map
int num = 0;
for (SOrderBaseinfoVoEx vo:orderAndSellPoints) {
    vo.setDynamicAttribute("sellPoint",sellPoints.get(num));
    num++;
}
pageEx.setRecords(orderAndSellPoints);
return pageEx;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

SOrderBaseinfoVoEx::new 是一种方法引用的写法,用于简化代码。它的原本写法是通过 Lambda 表达式 或 匿名类 来实现的。

如果没有使用方法引用,而是直接写成 Lambda 表达式,代码会是这样的:

List<SOrderBaseinfoVoEx> vos = originalList.stream()
    .map(item -> new SOrderBaseinfoVoEx(item)) // 使用 Lambda 表达式创建新对象
    .collect(Collectors.toList());
1
2
3
  • 通过装饰者模式实现动态增加字段

实现List的拷贝

/**
 * 集合数据的拷贝
 * @param sources: 数据源类
 * @param target: 目标类::new(eg: UserVO::new)
 * @return
 */
public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target) {
    return copyListProperties(sources, target, null);
}


/**
 * 带回调函数的集合数据的拷贝(可自定义字段拷贝规则)
 * @param sources: 数据源类
 * @param target: 目标类::new(eg: UserVO::new)
 * @param callBack: 回调函数
 * @return
 */
public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target, BeanCopyUtilCallBack<S, T> callBack) {
    List<T> list = new ArrayList<>(sources.size());
    for (S source : sources) {
        T t = target.get();
        copyProperties(source, t);
        list.add(t);
        if (callBack != null) {
            // 回调
            callBack.callBack(source, t);
        }
    }
    return list;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  • 新增函数式接口
@FunctionalInterface
public interface BeanCopyUtilCallBack <S, T> {

    /**
     * 定义默认回调方法
     * @param t
     * @param s
     */
    void callBack(S t, T s);
}

1
2
3
4
5
6
7
8
9
10
11

# 减少字段

减少字段,用自带的方法即可实现

 Page<User> page = new Page<>(1, 2);
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.select(User::getId,User::getName);
        Page<User> userPage = userMapper.selectPage(page, queryWrapper);
        userPage.getRecords().forEach(System.out::println);
1
2
3
4
5
6

queryWrapper.select();实现指定列。

# 自定义复杂连表查询

在实际开发中,常常需要多表联合查询,那此时,我们编写自定义的sql时,mapper文件中,可以传递QueryWrapper参数,以及Page参数吗,或者说该如何实现。

# 多表查询

# 映射别名跟ResultMap

如果多表查询的表名,跟VO类中的名不同,此时可以考虑使用resultMap进行转换。

11
1

# 额外的参数

  • 简单场景:若只有 1-2 个参数,可以直接用 @Param("key") 分开传递。
  • 复杂场景:优先使用 DTO 对象 替代 Map,提升代码健壮性和可维护性。
<select id="selectUserPage" resultType="com.example.vo.UserVo">
    SELECT * FROM user
    WHERE 1 = 1
    <if test="param.userName != null and param.userName != ''">
        AND name LIKE CONCAT('%', #{param.userName}, '%')
    </if>
    <if test="param.minAge != null">
        AND age >= #{param.minAge}
    </if>
    <if test="param.maxAge != null">
        AND age <= #{param.maxAge}
    </if>
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
  • Mapper定义
public interface UserMapper extends BaseMapper<User> {
    // 使用对象作为参数(替代 Map)
    Page<UserVo> selectUserPage(
        Page<UserVo> page, 
        @Param("param") UserQueryParam param // 替换为自定义对象
    );
}
1
2
3
4
5
6
7

# 注意事项

# 关于别名

多表查询时,对于返回的结果,使用别名是,不能加t1.ass,(t1为表的别名),只能用一个字段名 ass。

上次更新: 2025/05/21, 15:29:11
对接第三方接口的注意事项
数据加密与安全

← 对接第三方接口的注意事项 数据加密与安全→

最近更新
01
面向切面跟自定义注解的结合
05-22
02
时间跟其他数据的序列化
05-19
03
数据加密与安全
05-17
更多文章>
Theme by Vdoing | Copyright © 2023-2025 EffectTang
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式