MybatisPlus中静态工具DB的实现

 更新时间:2025年12月25日 09:24:21   作者:她说..  
本文主要介绍了使用MybatisPlus的Db静态工具类来避免Service之间的循环依赖问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

静态工具DB

有的时候Service之间也会相互调用,为了避免出现循环依赖问题,MybatisPlus提供一个静态工具类:Db,其中的一些静态方法与IService中方法签名基本一致,也可以帮助我们实现CRUD功能:

循环依赖的定义:

循环依赖(Circular Dependency) 是指 两个或多个组件(类、模块、包、服务等)之间存在直接或间接的相互依赖关系,形成一个闭环,导致系统无法正确初始化、编译或维护。

静态根据DB示例:

@Test
void testDbGet() {
    User user = Db.getById(1L, User.class);
    System.out.println(user);
}

@Test
void testDbList() {
    // 利用Db实现复杂条件查询
    List<User> list = Db.lambdaQuery(User.class)
            .like(User::getUsername, "o")
            .ge(User::getBalance, 1000)
            .list();
    list.forEach(System.out::println);
}

@Test
void testDbUpdate() {
    Db.lambdaUpdate(User.class)
            .set(User::getBalance, 2000)
            .eq(User::getUsername, "Rose");
}

Db.lambdaQuery(Address.class)中参数位置需要放实体类对象的字节码文件,通过传入实体类的class字节码,拿到字节码就能通过反射拿到实体类的相关信息,从而拿到注解上的信息诸如类名、表名等,以此实现CURD。

示例:

需求一

改造根据id用户查询的接口,查询用户的同时返回用户收货地址列表

(在userService中要注入addressService,需要查询收货地址列表)

首先,我们要添加一个收货地址的VO对象,用于视图返回给前端:

package com.itheima.mp.domain.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@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,添加一个地址属性,用来存储当前用户的地址列表属性:

@Data
@ApiModel(description = "用户VO实体")
public class UserVO {

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

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

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

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

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

    @ApiModelProperty("用户的收货地址")
    private List<AddressVO> addresses;
}

接下来,修改UserController中根据id查询用户的业务接口:

@GetMapping("/{id}")
@ApiOperation("根据id查询用户")
public UserVO queryUserById(@PathVariable("id") Long userId){
    // 基于自定义service方法查询
    return userService.queryUserAndAddressById(userId);
}

由于查询业务复杂,所以要在service层来实现。首先在IUserService中定义方法:

import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.vo.UserVO;

public interface IUserService extends IService<User> {
    void deduct(Long id, Integer money);

    UserVO queryUserAndAddressById(Long userId);
}

然后,在UserServiceImpl中实现该方法:

	@Override
	public UserVO queryUserAndAddressById(Long Id) {
		// 1.查询用户
		User user = this.getById(Id);
		if (user == null || user.getStatus()==UserStatus.FROZEN) {
			throw new RuntimeException("用户状态异常!");
		}
		// 2.查询收货地址
		List<Address> addresses = Db.lambdaQuery(Address.class)
				.eq(Address::getUserId, Id)
				.list();
		// 3.处理vo
		UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
		//转地址VO
		if (CollUtil.isNotEmpty(addresses)){
			userVO.setAddresses(BeanUtil.copyToList(addresses,AddressVO.class));
		}
		return userVO;
	}

BeanUtil.copyProperties :

将一个对象的属性值拷贝到另一个已存在的对象中(浅拷贝)。

 BeanUtil.copyToList:

将一个 List<源对象> 拷贝成一个新的 List<目标对象>,每个元素通过  copyProperties  创建新对象,因为是创建新对象,所以是一种深拷贝。

上面两个方法的第二个参数都可以是实体类的字节码,就比如user.class形式的格式,表示在项目运行的时候,会创建一个user的对象去接收源对象的数据,可以避免自己通过NEW关键字去创建对象接收数据。

在上面的代码中,在查询地址时,我们采用了Db的静态方法,因此避免了注入AddressService,减少了循环依赖的风险。即通过DB的lambdaQuery()方法,在参数中放我们要操作的实体类对象,我们可以避免循环依赖的问题,该方法会通过反射获取实体类的相关信息,然后根据我们的条件对当前实体类的表格进行CRUD操作,这种方式避免了注入依赖,也相当于避免了循环依赖。

需求二

根据id批量查询用户,并查询出用户对应的所有地址

controller层

	@GetMapping
	@ApiOperation("根据id批量查询用户接口")
	public List<UserVO> queryUserByIds(@ApiParam("用户id集合") @RequestParam("ids") List<Long> ids){
		return userService.queryUserAndAddressByIds(ids);
	}

 service层

	@Override
	public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {
		// 1.查询用户
		List<User> users = listByIds(ids);
		if (CollUtil.isEmpty(users)) {
			return Collections.emptyList();
		}
		// 2.查询地址
		// 2.1.获取用户id集合
		List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
		// 2.2.根据用户id查询地址
		List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();
		// 2.3.转换地址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.转换VO返回
		List<UserVO> list = new ArrayList<>(users.size());
		for (User user : users) {
			// 3.1.转换User的PO为VO
			UserVO vo = BeanUtil.copyProperties(user, UserVO.class);
			list.add(vo);
			// 3.2.转换地址VO
			vo.setAddresses(addressMap.get(user.getId()));
		}
		return list;
	}

 和查询单个用户的区别在于:根据id对查询出来的地址通过map来分组的实现逻辑。

到此这篇关于MybatisPlus中静态工具DB的实现的文章就介绍到这了,更多相关MybatisPlus 静态工具DB内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java通过value获取Map中key的三种实现过程

    Java通过value获取Map中key的三种实现过程

    本文介绍了三种通过Value值获取Map中的Key值的方法:循环法、Stream方法和ApacheCommonsCollections的BidiMap,每种方法都有其特点和适用场景,选择哪种方法应根据具体需求来决定
    2026-01-01
  • Java String字符串的常用使用方法

    Java String字符串的常用使用方法

    String是JDK提供的一个类,是引用类型,并不是基本的数据类型,String用于字符串操作,在之前学习c语言的时候,对于一些字符串,会初始化字符数组表示,本文给大家介绍Java String字符串的常用使用方法,感兴趣的朋友一起看看吧
    2025-04-04
  • Spring MVC的web.xml配置详解

    Spring MVC的web.xml配置详解

    这篇文章主要介绍了Spring MVC的web.xml配置详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • Java虚拟机使用jvisualvm工具远程监控tomcat内存

    Java虚拟机使用jvisualvm工具远程监控tomcat内存

    这篇文章主要介绍了Java虚拟机使用jvisualvm工具远程监控tomcat内存,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • Java编程swing组件JLabel详解以及使用示例

    Java编程swing组件JLabel详解以及使用示例

    这篇文章主要介绍了Java编程swing组件JLabel详解以及使用示例,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • Java中Vector、ArrayList、LinkedList的关系详细解析

    Java中Vector、ArrayList、LinkedList的关系详细解析

    这篇文章主要介绍了Java中Vector、ArrayList、LinkedList的关系详细解析,Vector和ArrayList底层均为Object数组,LinkedList底层是Node节点,Vector是线程安全(底层方法均添加synchronized),ArrayList、LinkedList是线程不安全(无锁),需要的朋友可以参考下
    2023-11-11
  • 搞懂JAVAObject中的hashCode()

    搞懂JAVAObject中的hashCode()

    今天小编就为大家分享一篇关于关于Object中equals方法和hashCode方法判断的分析,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2021-08-08
  • Spring Boot中配置定时任务、线程池与多线程池执行的方法

    Spring Boot中配置定时任务、线程池与多线程池执行的方法

    这篇文章主要给大家介绍了关于Spring Boot中配置定时任务、线程池与多线程池执行的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-09-09
  • response.sendRedirect()实现重定向(页面跳转)

    response.sendRedirect()实现重定向(页面跳转)

    在Java web开发中,使用response.sendRedirect()可实现重定向功能。本文将介绍如何使用该方法进行页面跳转,以及该方法的使用场景和注意事项,感兴趣的可以了解一下
    2023-04-04
  • Spring中的@Scheduled定时任务注解详解

    Spring中的@Scheduled定时任务注解详解

    这篇文章主要介绍了Spring中的@Scheduled定时任务注解详解,要使用@Scheduled注解,首先需要在启动类添加@EnableScheduling,启用Spring的计划任务执行功能,这样可以在容器中的任何Spring管理的bean上检测@Scheduled注解,执行计划任务,需要的朋友可以参考下
    2023-09-09

最新评论