MybatisPlus - 扩展功能

文章目录

目标:

  • 代码生成
  • 静态工具
  • 逻辑删除
  • 每局处理器
  • JSON处理器

1.代码生成




这个自己试试叭!

2.静态工具

跟IService的很像,但是IService中的方法都是非静态的,所以我们要自定义接口并且继承它,继承它的过程中还要指定泛型,泛型就是实体类的类型,为什么要执行实体类的类型?因为要通过反射获取字节码得到表信息才能增删改查。而Db都是静态的。类上是没有泛型的或者说静态的方法是没有办法读取到泛型的,因此Db上是没有泛型的,那么如何去做增删改查呢?所以你发现它的方法都需要我们传递一个额外的参数-字节码。

查地址的时候要注入user,查user的时候要注入地址,出现了循环依赖,那么我们就可以通过这个静态工具来解决。

AddressVO

java 复制代码
@Data
@ApiModel(description = "收货地址VO")
public class AddressVO{

    @ApiModelProperty("id")
    private Long id;

    @ApiModelProperty("用户ID")
    private Long userId;

    @ApiModelProperty("省")
    private String province;

    @ApiModelProperty("市")
    private String city;

    @ApiModelProperty("县/区")
    private String town;

    @ApiModelProperty("手机")
    private String mobile;

    @ApiModelProperty("详细地址")
    private String street;

    @ApiModelProperty("联系人")
    private String contact;

    @ApiModelProperty("是否是默认 1默认 0否")
    private Boolean isDefault;

    @ApiModelProperty("备注")
    private String notes;
}

UserVO

java 复制代码
@Data
@ApiModel(description = "用户VO实体")
public class UserVO {

    @ApiModelProperty("用户id")
    private Long id;

    @ApiModelProperty("用户名")
    private String username;

    @ApiModelProperty("详细信息")
    private String info;

    @ApiModelProperty("使用状态(1正常 2冻结)")
    private Integer status;

    @ApiModelProperty("账户余额")
    private Integer balance;

    private List<AddressVO> addresses;
}

出现循环依赖可以使用静态工具

java 复制代码
public UserVO queryUserAndAddressById(Long id) {
        //1.查询用户
        User user = this.getById(id);
        if(user==null || user.getStatus()!=1){
            throw new RuntimeException("用户状态异常");
        }

        //2.查询地址
        List<Address> addresses = Db.lambdaQuery(Address.class).eq(Address::getUserId, id).list();
        //3.封装返回值
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        if(addresses!=null && addresses.size()>0){
            userVO.setAddresses(BeanUtil.copyToList(addresses, AddressVO.class));
        }
        return userVO;
    }

第二题

java 复制代码
 @ApiOperation("根据id批量查询用户接口")
    @PostMapping("/users")
    public List<UserVO> queryUser(@RequestParam("ids") List<Long> ids){
        return userService.queryUserAndAddressByIds(ids);
    }
java 复制代码
 public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {
        //1.查询用户
        List<User> users = listByIds(ids);
        if(users==null || users.size()!=ids.size()){
            throw new RuntimeException("用户状态异常");
        }
        //2.查询地址
        //2.1 获取用户id集合
        List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
        //2.2 查询地址
        List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();
        //2.3 转换Address的PO为VO
        List<AddressVO> addressVOList = BeanUtil.copyToList(addresses, AddressVO.class);
        //2.4 梳理地址集合,分类整理,相同用户的地址放在一起 分组

        Map<Long, List<AddressVO>> addressMap = new HashMap<>(0);
        if(CollUtil.isNotEmpty(addressVOList)){
            addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));
        }

        //3.封装返回值
        List<UserVO>list = new ArrayList<>(users.size());
        for (User user : users) {
            //3.1 转换User的PO为VO
            UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
            list.add(userVO);
            userVO.setAddresses(addressMap.get(user.getId()));
        }
        return list;
    }
3.逻辑删除

有一些数据是非常重要的,不能直接删除


我配完之后写了一个测试类测试一下:

java 复制代码
@SpringBootTest
class IAddressServiceTest {

    @Autowired
    private IAddressService addressService;
    @Test
    void testLogicDelete(){
        addressService.removeById(60L);
        Address address = addressService.getById(60L);
        System.out.println(address);
    }

}



4.枚举处理器

这里我们会涉及到枚举类型跟int类型之间的转换问题,其实也不仅仅是这一个;类型,我们java中所有的数据类型都要跟数据库的类型做转换,可能我们平时都没有主动转换过,但是我们没有做过并不代表没有,我们所认为的岁月静好,只不过是有人在替我们负重前行,底层都是由mybatis帮我们完成,mybatis如何实现类型转换呢?

我们这里使用MybatisEnum TypeHandler,分两步使用,我们得告诉mp那个属性是对应数据库的字段,用注解@EnumValue

第二步:让它生效

记得VO也要改,但是返回就会以枚举项返回,我们的数据往前端返回是由SpringMVC处理的,SpringMVC处理JSON用的是Jackson,它提供了一个注解来表明返回枚举中那个值进行返回@JsonValue

5.JSON处理器


但是mybatis没有能力帮我们做userInfo跟JSON数据类型的转换,所以我们只能自己来

我们使用JacksonTypeHandler实现类

没有全局配置,只能一个个配.现在这里面出现了对象嵌套,User中又出现了info

往往就需要去定义resultMap,但是我们又不想定义

准备实体:

插件功能

最常见,我们一般可以用pageHelper,但是mp也提供了

这里分为两个小节

  • 分页插件
  • 通用分页实体



配置

java 复制代码
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 这里可以添加多个插件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        paginationInnerInterceptor.setMaxLimit(1000L);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}

测试类:

java 复制代码
 @Test
    void testPageQuery(){
        int pageNo = 1;
        int pageSize = 2;
        //1.准备分页条件
        //1.1分页条件
        Page<User>page = new Page<>(pageNo, pageSize);
        //1.2排序条件
        page.addOrder(OrderItem.desc("id"));
        //2.执行分页查询
        Page<User> result = userService.page(page);
        //3.输出结果
        result.getRecords().forEach(System.out::println);
        System.out.println("总记录数:" + result.getTotal());
        System.out.println("总页数:" + result.getPages());
        System.out.println("当前页:" + result.getCurrent());
        System.out.println("是否有前一页:" + result.hasPrevious());
        System.out.println("是否有下一页:" + result.hasNext());

    }

返回值:

通用分页实体

封装一个实体:

java 复制代码
import lombok.Data;

@Data
public class PageQuery {
    private Integer pageNo;
    private Integer pageSize;
    private String sortBy;
    private Boolean isAsc;
}
java 复制代码
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel(description = "用户查询条件实体")
public class UserQuery extends PageQuery {
    @ApiModelProperty("用户名关键字")
    private String name;
    @ApiModelProperty("用户状态:1-正常,2-冻结")
    private Integer status;
    @ApiModelProperty("余额最小值")
    private Integer minBalance;
    @ApiModelProperty("余额最大值")
    private Integer maxBalance;
}

定义一个统一分页结果,我们说不定以后在微服务中也会使用到所以可以定义在dto包

java 复制代码
@Data
public class PageDTO<T> {
    private Long total;
    private Long pages;
    private List<T> list;
}

接口声明:

java 复制代码
    @ApiOperation("根据复杂条件分页查询用户接口")
    @GetMapping("/page")
    public PageDTO<UserVO> queryUsersPage(UserQuery query){
        return userService.queryUsersPage(query);
    }
java 复制代码
 public PageDTO<UserVO> queryUsersPage(UserQuery query) {
        //1.构建查询条件
        String name = query.getName();
        Integer status = query.getStatus();
        Page<User> page = Page.of(query.getPageNo(), query.getPageSize());
        if(StrUtil.isNotBlank(query.getSortBy())){
            page.addOrder(new OrderItem(query.getSortBy(), query.getIsAsc()));
        }else{
            //默认排序
            page.addOrder(new OrderItem("update_time"  , false));
        }

        //2.分页查询
        Page<User> p = lambdaQuery().
                like(name != null, User::getUsername, name)
                .eq(status != null, User::getStatus, status)
                .page(page);
        //3.转换PO为VO
        PageDTO<UserVO> dto = new PageDTO<>();
        dto.setTotal(p.getTotal());
        dto.setPages(p.getPages());
        List<User> records = p.getRecords();
        if(CollUtil.isEmpty(records)){
            dto.setList(new ArrayList<>());
            return dto;
        }
        //3.1 转换User的PO为VO
        dto.setList(BeanUtil.copyToList(records, UserVO.class));
        //3.2 封装地址信息
        //4.返回
        return dto;
    }

通用分页实体与MP转换

很多代码跟业务关系不大,比较通用

java 复制代码
@Data
public class PageQuery {
    private Integer pageNo = 1;
    private Integer pageSize = 5;
    private String sortBy;
    private Boolean isAsc = true;

    public <T> Page<T> toMpPage(OrderItem ...items){
        Page<T> page = Page.of(pageNo, pageSize);
        if(StrUtil.isNotBlank(sortBy)){
            page.addOrder(new OrderItem(sortBy, isAsc));
        }else if(items!= null && items.length > 0){
            //默认排序
            page.addOrder(items);
        }
        return page;
    }

    public <T> Page<T> toMpPage(String sortBy, Boolean isAsc){
        return toMpPage(new OrderItem(sortBy, isAsc));
    }

    public <T> Page<T> toMpPageDefaultByCreatTime(){
        return toMpPage(new OrderItem("create_time",false));
    }


    public <T> Page<T> toMpPageDefaultByUpdateTime(){
        return toMpPage(new OrderItem("update_time",false));
    }
}
java 复制代码
import java.util.ArrayList;
import java.util.List;

@Data
public class PageDTO<T> {
    private Long total;
    private Long pages;
    private List<T> list;

    public static <PO,VO> PageDTO<VO> of(Page<PO> p,Class<VO> voClass){
        PageDTO<VO> dto = new PageDTO<>();
        dto.setTotal(p.getTotal());
        dto.setPages(p.getPages());
        List<PO> records = p.getRecords();
        if(CollUtil.isEmpty(records)){
            dto.setList(new ArrayList<>());
            return dto;
        }
        //3.1 转换User的PO为VO
        dto.setList(BeanUtil.copyToList(records, voClass));
        //3.2 封装地址信息
        //4.返回
        return dto;

    }
}

最终:

java 复制代码
  public PageDTO<UserVO> queryUsersPage(UserQuery query) {
        //1.构建查询条件
        String name = query.getName();
        Integer status = query.getStatus();
        Page<User> page = query.toMpPage();

        //2.分页查询
        Page<User> p = lambdaQuery().
                like(name != null, User::getUsername, name)
                .eq(status != null, User::getStatus, status)
                .page(page);
        //3.转换PO为VO
        return PageDTO.of(p,  UserVO.class);
    }

但是要记住Beanutil的使用要求User,UserVo的属性名要相同,如果不同需要自己完成转换,那能不能封装一个方法别的方法你帮我写好但是从PO到VO的转换我自己来写

java 复制代码
public class PageDTO<T> {
    private Long total;
    private Long pages;
    private List<T> list;

    public static <PO,VO> PageDTO<VO> of(Page<PO> p, Function<PO,VO> converter){
        PageDTO<VO> dto = new PageDTO<>();
        dto.setTotal(p.getTotal());
        dto.setPages(p.getPages());
        List<PO> records = p.getRecords();
        if(CollUtil.isEmpty(records)){
            dto.setList(new ArrayList<>());
            return dto;
        }
        //3.1 转换User的PO为VO

        dto.setList(records.stream().map(converter).collect(Collectors.toList()));
        //3.2 封装地址信息
        //4.返回
        return dto;

    }
}
java 复制代码
public PageDTO<UserVO> queryUsersPage(UserQuery query) {
        //1.构建查询条件
        String name = query.getName();
        Integer status = query.getStatus();
        Page<User> page = query.toMpPage();

        //2.分页查询
        Page<User> p = lambdaQuery().
                like(name != null, User::getUsername, name)
                .eq(status != null, User::getStatus, status)
                .page(page);
        //3.转换PO为VO
        return PageDTO.of(p, user->{
            //1.拷贝基础属性
            UserVO vo = BeanUtil.copyProperties(user, UserVO.class);
            //2.处理特殊逻辑
            vo.setUsername(vo.getUsername().substring(0,vo.getUsername().length()-2)+"**");
            return vo;
        });
    }

完结啦~~

相关推荐
找了一圈尾巴7 分钟前
Spring Boot 日志管理(官网文档解读)
java·spring boot
升讯威在线客服系统7 分钟前
如何通过 Docker 在没有域名的情况下快速上线客服系统
java·运维·前端·python·docker·容器·.net
s:1031 小时前
【框架】参考 Spring Security 安全框架设计出,轻量化高可扩展的身份认证与授权架构
java·开发语言
南山十一少4 小时前
Spring Security+JWT+Redis实现项目级前后端分离认证授权
java·spring·bootstrap
427724006 小时前
IDEA使用git不提示账号密码登录,而是输入token问题解决
java·git·intellij-idea
chengooooooo6 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
李长渊哦6 小时前
常用的 JVM 参数:配置与优化指南
java·jvm
计算机小白一个6 小时前
蓝桥杯 Java B 组之设计 LRU 缓存
java·算法·蓝桥杯
Tirzano7 小时前
springsecurity自定义认证
spring boot·spring
南宫生9 小时前
力扣每日一题【算法学习day.132】
java·学习·算法·leetcode