2025年Mybatis plue(二) 扩展功能、插件功能

Mybatis plue(二) 扩展功能、插件功能扩展功能 P12 扩展功能 代码生成器 方法一 mybatisplus 官方文档中的代码生成配置 方法二 插件 mybatsx 方法三 插件 mybatisplus P13 DB 静态工具 iservice 中的方法是非静态的 db 方法是静态的 静态方法无法读取到类的泛型的 也就无法知道实体类类型

大家好,我是讯享网,很高兴认识大家。

扩展功能

P12 扩展功能-代码生成器

  • 方法一:mybatisplus官方文档中的代码生成配置
  • 方法二:插件mybatsx
  • 方法三:插件mybatisplus

P13 DB静态工具

iservice中的方法是非静态的,db方法是静态的。

静态方法无法读取到类的泛型的,也就无法知道实体类类型、表信息,可以看到方法中都需要传额外参数,即实体类的字节码,以得到相关信息。

例如:可能会存在两个service相互注入的情况,即循环依赖,如何解决?

使用静态工具进行解决,(静态工具和iservice用法差不多,就是额外传入字节码),但是这样能够避免注入service,避免了循环依赖。(当然也可以不适用iservice中的方法,也可以使用mapper中的方法)

示例:根据用户id查询用户信息,以及用户地址信息并返回;

@Override public UserVO queryUserAndAddressById(Long id){ // 查询用户信息 User user = getById(id); if (user == null || user.getStatus() == UserStatus.FROZEN){ throw new RuntimeException("用户状态异常"); } UserVO userVO = BeanUtil.copyProperties(user, UserVO.class); // 查询用户地址,地址表一个用户多个地址 // 使用lambdaquery,避免相互依赖,使用DB静态方法 List<Address> addresses = Db.lambdaQuery(Address.class) .eq(Address::getUserId, id) .list(); if (CollUtil.isNotEmpty(addresses)){ userVO.setAddresses(BeanUtil.copyToList(addresses, AddressVO.class)); } return userVO; // 没有自己写sql就实现了业务操作 } 

讯享网

P14 扩展功能-DB静态工具2

例如:实现批量查询用户,同时查询出用户地址信息。

注意查询地址信息,需要先获取用户的id集合,参数ids就是一个集合,如果以后再遇到这种,可以使用stream流从用户对象从获取到用户id的结合,例如:

List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());

讯享网@Override public List<UserVO> queryUserAndAddressByIds(List<Long> ids){ // 查询用户 List<User> users = listByIds(ids); if (CollUtil.isEmpty(users)){ return Collections.emptyList(); } // 方法参数传入的ids可能为空 List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList()); // 查询地址 List<Address> addresses = Db.lambdaQuery(Address.class) .in(Address::getUserId, userIds) .list(); // 转换地址VO List<AddressVO> addressVOList = BeanUtil.copyToList(addresses, AddressVO.class); // 将用户地址分组, Map<Long, List<AddressVO>> addressMap = new HashMap<>(0); if (CollUtil.isNotEmpty(addressVOList)){ addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId)); // 依据用户id进行分组 } // 转为VO返回 List<UserVO> list = new ArrayList<>(users.size()); for (User user : users){ UserVO userVO = BeanUtil.copyProperties(user, UserVO.class); list.add(userVO); userVO.setAddresses(addressMap.get(user.getId())); } return list; } 

P15 扩展功能-逻辑删除

逻辑删除就是基于代码逻辑模拟删除效果,但并不会真正删除数据

  • 在表中添加一个字段标记数据是否被删除
  • 当删除数据时置该字段为1
  • 查询时只查询标记为0的数据

这种功能mybatisplus已经提供了,直接帮我们在底层自动修改CRUD语句,在application.yaml中配置逻辑删除的字段名和值即可。

例如:

mybatis-plus: type-aliases-package: com.itheima.mp.domain.po # 别名扫描包 global-config: db-config: id-type: auto # 配置id生成的策略,如果是雪花算法就是assign_id logic-delete-field: deleted # 配置逻辑删除字段 update-strategy: not_null # 更新策略,只更新非空字段 

逻辑删除也会存在问题:

  • 垃圾数据越来越多
  • sql中全都需要对逻辑删除字段进行判断,影响查询效率

替代方案,采用数据迁移的方式

P16 扩展功能-枚举处理器

使用枚举类型。

问题:java中的枚举类型与数据库中的int类型相互转换问题。这个问题是mybatis实现的。

mybatisplus加入了几个类型处理器,就有MybatisEnumTypeHandler。


讯享网

先配置:

讯享网mybatis-plus: configuration: default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler 

加注解:

@EnumValue private final int value; // 对应数据库中的值 

我们定义的枚举类是UserStatus,修改用户实体类中的status的类型为这个枚举类型而不是int类型。

讯享网 / * 使用状态(1正常 2冻结) */ private UserStatus status; 

枚举返回前端默认是枚举项的名字,返回给前端的显示值,使用注解jsonvalue,可以自定义返回

@JsonValue private final String desc; 

P17 扩展功能-JSON处理器

mybatis plus还提供了AbstractJsonTypeHandler转换器,实现java和json的转换

例如数据库中info字段存储的json类型,如下图:

在这里插入图片描述

在java中使用这类数据,如果读取到再将字符串转换为可用的数据比较麻烦,可以考虑定义一个这种json格式的实体,然后使其变成这个对象,mybatis没有提供这个类型处理器,mybatis plus提供了。

在这里插入图片描述

例如:

讯享网 / * 详细信息 */ @TableField(typeHandler = JacksonTypeHandler.class) // 定义类型处理器 private UserInfo info; 

还要开启自动的结果映射

@Data @TableName(value = "user", autoResultMap = true) // 自动结果映射 public class User { 

插件功能

mybatis plus提供的内置拦截器有:

在这里插入图片描述

P18 分页插件

之间使用了PageHelper,

使用mybatis plus中的分页插件,首先配置,

讯享网@Configuration public class MyBatisConfig { @Bean // 声明一个bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 创建核心插件 ,可以往里面加插件 // 1.创建分页插件 PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);// 分页内置拦截器 paginationInnerInterceptor.setMaxLimit(1000L);// 最多1000条 // 2.添加分页插件 interceptor.addInnerInterceptor(paginationInnerInterceptor); // 可以添加插件 return interceptor; } } 

使用分页的API,返回page结果

在这里插入图片描述

使用示例:

 @Test void testPageQuery() { int pageNo = 1, pageSize = 2; // 1.准备分页条件 // 1.1.分页条件 Page<User> page = Page.of(pageNo, pageSize); // 创建page对象 // 1.2.排序条件 page.addOrder(new OrderItem("balance", true)); page.addOrder(new OrderItem("id", true)); // 2.分页查询 Page<User> p = userService.page(page); // 3.解析 long total = p.getTotal(); System.out.println("total = " + total); long pages = p.getPages(); System.out.println("pages = " + pages); List<User> users = p.getRecords(); users.forEach(System.out::println); } 

P19 通用分页实体

例如:
在这里插入图片描述

从接收处理到业务逻辑实现到返回。

如果单独在UserDTO中实现,加入AddressDTO中也有分页需求,又要写。所以可以设计统一的分页查询请求,即公共分页类。

讯享网@Data @ApiModel(description = "分页查询实体") public class PageQuery { @ApiModelProperty("页码") private Integer pageNo = 1; @ApiModelProperty("页码") private Integer pageSize = 5; @ApiModelProperty("排序字段") private String sortBy; @ApiModelProperty("是否升序") private Boolean isAsc = true; public <T> Page<T> toMpPage(OrderItem ... items){ // 1.分页条件 Page<T> page = Page.of(pageNo, pageSize); // 2.排序条件 if(StrUtil.isNotBlank(sortBy)){ // 不为空 page.addOrder(new OrderItem(sortBy, isAsc)); }else if(items != null){ // 为空,默认排序 page.addOrder(items); } return page; } public <T> Page<T> toMpPage(String defaultSortBy, Boolean defaultAsc){ return toMpPage(new OrderItem(defaultSortBy, defaultAsc)); } public <T> Page<T> toMpPageDefaultSortByCreateTime(){ return toMpPage(new OrderItem("create_time", false)); } public <T> Page<T> toMpPageDefaultSortByUpdateTime(){ return toMpPage(new OrderItem("update_time", false)); } } 

userquery继承这个分页查询实体即可。

可以定义pageDTO,

@Data @ApiModel(description = "分页结果") public class PageDTO<T> { @ApiModelProperty("总条数") private Long total; @ApiModelProperty("总页数") private Long pages; @ApiModelProperty("集合") private List<T> list; // 泛型T,不知道具体哪种类型 public static <PO, VO> PageDTO<VO> of(Page<PO> p, Class<VO> clazz){ PageDTO<VO> dto = new PageDTO<>(); // 1.总条数 dto.setTotal(p.getTotal()); // 2.总页数 dto.setPages(p.getPages()); // 3.当前页数据 List<PO> records = p.getRecords(); if (CollUtil.isEmpty(records)) { dto.setList(Collections.emptyList()); return dto; } // 4.拷贝user的VO dto.setList(BeanUtil.copyToList(records, clazz)); // 5.返回 return dto; } public static <PO, VO> PageDTO<VO> of(Page<PO> p, Function<PO, VO> convertor){ PageDTO<VO> dto = new PageDTO<>(); // 1.总条数 dto.setTotal(p.getTotal()); // 2.总页数 dto.setPages(p.getPages()); // 3.当前页数据 List<PO> records = p.getRecords(); if (CollUtil.isEmpty(records)) { dto.setList(Collections.emptyList()); return dto; } // 4.拷贝user的VO dto.setList(records.stream().map(convertor).collect(Collectors.toList())); // 5.返回 return dto; } } 
小讯
上一篇 2025-03-07 20:17
下一篇 2025-04-10 11:07

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/38403.html