当前位置: 首页 > news >正文

MybatisPlus使用指南

MybatisPlus

  • 1. 快速入门
    • 1.1 入门案例
    • 1.2 常见注解
    • 1.3 常见配置
  • 2. 核心功能
    • 2.1 条件构造器
    • 2.2 自定义SQL
    • 2.3 Service接口
  • 3. 扩展功能
    • 3.1 代码生成
    • 3.2 静态工具
    • 3.3 逻辑删除
  • 4. 插件功能
    • 4.1 分页插件
    • 4.2 通用分页实体

在这里插入图片描述

1. 快速入门

1.1 入门案例

步骤一:引入MybatisPlus的起步依赖
MyBatisPlus官方提供了starter,其中集成了Mybatis和MybatisPlus的所有功能,并且实现了自动装配效果。
因此我们可以用MybatisPlus的starter代替Mybatis的starter:

 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version>
</dependency>

步骤二:定义Mapper继承MybaitsPlus提供的BaseMapper接口

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.mp.domain.po.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper
public interface UserMapper extends BaseMapper<User> {
}

注:BaseMapper中已经定义了常用的CURD方法

在这里插入图片描述

步骤三:调用接口中的方法进行测试

在这里插入图片描述在这里插入图片描述

1.2 常见注解

MyBatisPlus通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。

在这里插入图片描述

MybatisPlus中比较常用的几个注解如下:

  1. @TableName: 用来指定表明
  2. @TableId: 用来指定表中的主键字段信息
  3. @TableField: 用来指定表中的普通字段信息

在这里插入图片描述

IdType枚举

  • AUTO: 数据库自增长
  • INPUT: 通过set方法自行输入
  • ASSIGN_ID: 分配ID,接口IdentifierGenerator的方法nextId来生成id,默认实现类为DefaultIdentifierGenerator雪花算法

使用@TableFidle的常见场景

  • 成员变量名与数据库字段名不一致
  • 成员变量名以is开头,且是布尔值
  • 成员变量名与数据库关键字冲突
  • 成员变量不是数据库字段

1.3 常见配置

MyBatisPlus的配置项继承了MyBatis原生配置和一些自己特有的配置。例如:

mybatis-plus:mapper-locations: classpath*:mapper/**/*.xml # Mapper.xml文件地址,默认值type-aliases-package: com.itheima.mp.domain.po # 别名扫描包configuration:map-underscore-to-camel-case: true  # 是否开启下户线和驼峰的映射cache-enabled: false # 是否开启二级缓存global-config:db-config:id-type: assign_id  # id为雪花算法生成update-strategy: not_null # 更新策略

2. 核心功能

2.1 条件构造器

刚才的案例中都是以id为条件的简单CRUD,一些复杂条件的SQL语句就要用到一些更高级的功能了。

在这里插入图片描述

参数中的Wrapper就是条件构造的抽象类,其下有很多默认实现,继承关系如图:

在这里插入图片描述

Wrapper的子类AbstractWrapper提供了where中包含的所有条件构造方法:

在这里插入图片描述

而QueryWrapper在AbstractWrapper的基础上拓展了一个select方法,允许指定查询字段

在这里插入图片描述

而UpdateWrapper在AbstractWrapper的基础上拓展了一个set方法,允许指定SQL中的SET部分

在这里插入图片描述

QueryWrapper:无论是修改、删除、查询,都可以使用QueryWrapper来构建查询条件。查询:查询出名字中带o的,存款大于等于1000元的人。代码如下:

@SpringBootTest
public class UserWrapperTest {@ResourceUserMapper userMapper;@Testvoid testQueryWrapper(){// 1.构建查询条件 where name like "%o%" AND balance >= 1000QueryWrapper<User> wrapper = new QueryWrapper<User>().select("id", "username", "info", "balance").like("username", "o").ge("balance", 1000);// 2. 查询数据List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);}

UpdateWrapper

更新用户名为jack的用户的余额为2000,代码如下:

@SpringBootTest
public class UserWrapperTest {@ResourceUserMapper userMapper;@Testvoid testUpdateWrapper(){// 1.构建查询条件 set balance = 20000 where name = "Jack"UpdateWrapper<User> wrapper = new UpdateWrapper<User>().setSql("balance = 2000").eq("username", "jack");// 2. 查询数据int update = userMapper.update(null, wrapper);System.out.println(update);}
}

更新id为1,2,4的用户的余额,扣200,代码如下:

@SpringBootTest
public class UserWrapperTest {@ResourceUserMapper userMapper;@Testvoid testUpdateBatchWrapper(){// 1.构建查询条件UpdateWrapper<User> wrapper = new UpdateWrapper<User>().setSql("balance = balance - 200")  // SET balance = balance - 200.in("id",List.of(1L, 2L, 4L)); // // WHERE id in (1, 2, 4)// 2. 查询数据,注意第一个参数可以给null,也就是不填更新字段和数据,而是基于UpdateWrapper中的setSQL来更新int update = userMapper.update(null, wrapper);System.out.println(update);}}

无论是QueryWrapper还是UpdateWrapper在构造条件的时候都需要写死字段名称,会出现字符串魔法值。这在编程规范中显然是不推荐的。那怎么样才能不写字段名,又能知道字段名呢?其中一种办法是基于变量的gettter方法结合反射技术。因此我们只要将条件对应的字段的getter方法传递给MybatisPlus,它就能计算出对应的变量名了。而传递方法可以使用JDK8中的方法引用和Lambda表达式。
因此MybatisPlus又提供了一套基于Lambda的Wrapper,包含两个:

  • LambdaQueryWrapper
  • LambdaUpdateWrapper

分别对应QueryWrapper和UpdateWrapper

@SpringBootTest
public class UserWrapperTest {@ResourceUserMapper userMapper;@Testvoid testLambdaQueryWrapper(){// 1.构建查询条件 where name like "%o%" AND balance >= 1000LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>().select(User::getId, User::getUsername, User::getInfo, User::getBalance).like(User::getUsername, "o").ge(User::getBalance, 1000);// 2. 查询数据List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);}@Testvoid testLambdaUpdateWrapper(){// 1.构建查询条件LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<User>().setSql("balance = 2000").eq(User::getUsername, "jack");// 2. 查询数据int update = userMapper.update(null, wrapper);System.out.println(update);}
}

2.2 自定义SQL

在演示UpdateWrapper的案例中,我们在代码中编写了更新的SQL语句:

 @Testvoid testUpdateBatchWrapper(){// 1.构建查询条件UpdateWrapper<User> wrapper = new UpdateWrapper<User>().setSql("balance = balance - 200")  // SET balance = balance - 200.in("id",List.of(1L, 2L, 4L)); // // WHERE id in (1, 2, 4)// 2. 查询数据,注意第一个参数可以给null,也就是不填更新字段和数据,而是基于UpdateWrapper中的setSQL来更新int update = userMapper.update(null, wrapper);System.out.println(update);}

这种写法在某些企业也是不允许的,因为SQL语句最好都维护在持久层,而不是业务层。MybatisPlus提供了自定义SQL功能,先利用Wrapper来构建复杂的where条件,再结合Mapper.xml或注解自己编写SQL语句。

核心思想:将where条件使用Wrapper来构建,然后在Mapper.xml进行调用即可

在这里插入图片描述

2.3 Service接口

MybatisPlus不仅提供了BaseMapper,还提供了通用的Service接口及默认实现,封装了一些常用的service模板方法。
通用接口为IService,默认实现为ServiceImpl,其中封装的方法可以分为以下几类:

  • save:新增
  • remove:删除
  • update:更新
  • get:查询单个结果
  • list:查询集合结果
  • count:计数
  • page:分页查询
    在这里插入图片描述

在这里插入图片描述

  • 自定义Service接口继承IService接口
  • 自定义Service实现类,实现自定义接口并集成ServiceImpl类

由于Service中经常需要定义与业务有关的自定义方法,因此我们不能直接使用IService,而是自定义Service接口,然后继承IService以拓展方法。同时,让自定义的Service实现类继承ServiceImpl,这样就不用自己实现IService中的接口了。
首先,定义IUserService,继承IService:

package com.itheima.mp.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.mp.domain.po.User;public interface IUserService extends IService<User> {// 拓展自定义方法
}

然后,编写UserServiceImpl类,继承ServiceImpl,实现UserService:

package com.itheima.mp.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.po.service.IUserService;
import com.itheima.mp.mapper.UserMapper;
import org.springframework.stereotype.Service;@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>                                                                                           implements IUserService {
}

接下来实现下面5个接口:

在这里插入图片描述

首先引入依赖

<!--swagger-->
<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi2-spring-boot-starter</artifactId><version>4.1.0</version>
</dependency>
<!--web-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

然后需要配置swagger信息:

knife4j:enable: trueopenapi:title: 用户管理接口文档description: "用户管理接口文档"email: xxxxxconcat: xxxxurl: xxxxversion: v1.0.0group:default:group-name: defaultapi-rule: packageapi-rule-resources:- com.itheima.mp.controller

导入相关的UserVo、UserDTO、UserFormDTO(前端传入参数较多的时候封装成类)

UserController

package com.itheima.mp.controller;import cn.hutool.core.bean.BeanUtil;
import com.itheima.mp.domain.dto.UserFormDTO;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.vo.UserVO;
import com.itheima.mp.service.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;/*** @author Mr.Lu* @version 1.0* @date 2024-08-13 20:57*/@RequestMapping("/users")
@RestController
@Slf4j
@Api(tags = "用户管理接口")
public class UserController {@Resourceprivate IUserService userService;@PostMapping@ApiOperation("新增用户")public void saveUser(@RequestBody UserFormDTO userFormDTO){User user = new User();BeanUtil.copyProperties(userFormDTO, user);userService.save(user);}@DeleteMapping("/{id}")@ApiOperation("删除用户")public void removeUserById(@PathVariable("id") Long userId){userService.removeById(userId);}@GetMapping("/{id}")@ApiOperation("根据id查询用户")public UserVO queryUserById(@PathVariable("id") Long userId){User user = userService.getById(userId);UserVO userVO = new UserVO();BeanUtil.copyProperties(user, userVO);return userVO;}@GetMapping@ApiOperation("根据ids查询批量用户")public List<UserVO> queryUserByIds(@RequestParam("ids") List<Long> ids){List<User> users = userService.listByIds(ids);List<UserVO> userVOS = BeanUtil.copyToList(users, UserVO.class);return userVOS;}@PutMapping("/{id}/deduction/{money}")@ApiOperation("根据id更新金额")public void deduction(@PathVariable("id") Long id, @PathVariable Integer money){userService.deduction(id, money);}}

UserServiceImpl

特别注意:ServiceImpl已经注入了badeMapper(泛型指定为userMapper),所以可以直接调用mapper无需注入

package com.itheima.mp.service.impl;import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.mapper.UserMapper;
import com.itheima.mp.service.IUserService;
import org.springframework.stereotype.Service;/*** @author Mr.Lu* @version 1.0* @date 2024-08-13 20:53*/@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {@Overridepublic void deduction(Long id, Integer money) {// 1.查询用户User user = getById(id);// 2.判断用户状态if (user == null || user.getStatus() == 2) {throw new RuntimeException("用户状态异常");}// 3.判断用户余额if (user.getBalance() < money) {throw new RuntimeException("用户余额不足");}// 4.扣减余额LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<User>().eq(User::getId, id);baseMapper.deduction(money, warpper);}
}

IUserService

package com.itheima.mp.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.mp.domain.po.User;/*** @author Mr.Lu* @version 1.0* @date 2024-08-13 20:52*/public interface IUserService extends IService<User> {void deduction(Long id, Integer money);
}

UserMapper

package com.itheima.mp.mapper;import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.mp.domain.po.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;@Mapper
public interface UserMapper extends BaseMapper<User> {@Update("update tb_user set balance = balance - #{money} ${ew.customSqlSegment}")void deduction(@Param("money")Integer money, @Param("ew")LambdaUpdateWrapper<User> wrapper);
}

IService中还提供了Lambda功能来简化我们的复杂查询及更新功能。我们通过两个案例来学习一下。

案例一:实现一个根据复杂条件查询用户的接口,查询条件如下:

  • name:用户名关键字,可以为空
  • status:用户状态,可以为空
  • minBalance:最小余额,可以为空
  • maxBalance:最大余额,可以为空

可以理解成一个用户的后台管理界面,管理员可以自己选择条件来筛选用户,因此上述条件不一定存在,需要做判断。

首先定义一个查询条件实体,UserQuery实体:

package com.itheima.mp.domain.query;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
@ApiModel(description = "用户查询条件实体")
public class UserQuery {@ApiModelProperty("用户名关键字")private String name;@ApiModelProperty("用户状态:1-正常,2-冻结")private Integer status;@ApiModelProperty("余额最小值")private Integer minBalance;@ApiModelProperty("余额最大值")private Integer maxBalance;
}

在UserController中定义一个controller方法:

@GetMapping("/list")
@ApiOperation("根据id集合查询用户")
public List<UserVO> queryUsers(UserQuery query){// 1.组织条件String username = query.getName();Integer status = query.getStatus();Integer minBalance = query.getMinBalance();Integer maxBalance = query.getMaxBalance();LambdaQueryWrapper<User> wrapper = new QueryWrapper<User>().lambda().like(username != null, User::getUsername, username).eq(status != null, User::getStatus, status).ge(minBalance != null, User::getBalance, minBalance).le(maxBalance != null, User::getBalance, maxBalance);// 2.查询用户List<User> users = userService.list(wrapper);// 3.处理voreturn BeanUtil.copyToList(users, UserVO.class);
}

在组织查询条件的时候,我们加入了 username != null 这样的参数,意思就是当条件成立时才会添加这个查询条件,类似Mybatis的mapper.xml文件中的标签。

案例二:批量新增,修改项目中的application.yml文件,在jdbc的url后面添加参数&rewriteBatchedStatements=true

@Test
void testSaveBatch() {// 准备10万条数据List<User> list = new ArrayList<>(1000);long b = System.currentTimeMillis();for (int i = 1; i <= 100000; i++) {list.add(buildUser(i));// 每1000条批量插入一次if (i % 1000 == 0) {userService.saveBatch(list);list.clear();}}long e = System.currentTimeMillis();System.out.println("耗时:" + (e - b));
}

3. 扩展功能

3.1 代码生成

在这里插入图片描述
在这里插入图片描述

3.2 静态工具

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

在这里插入图片描述

1. 改造根据id查询用户的接口,查询用户的同时,查询出用户对应的所有地址改造;

    @Overridepublic UserVO queryUserAndAddress(Long userId) {// 1. 查询用户信息User user = (User) Db.getById(userId, User.class);// 2. 判断用户是否存在if(user == null) return null;// 3. 查询用户地址List<Address> address = Db.lambdaQuery(Address.class).eq(Address::getUserId, userId).list();// 类型转换UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);List<AddressVO> addressVOList = BeanUtil.copyToList(address, AddressVO.class);userVO.setAddresses(addressVOList);return userVO;}

2. 根据id批量查询用户的接口,查询用户的同时,查询出用户对应的所有地址;

 public List<UserVO> queryUsersAndAddresses(List<Long> ids) {// 1. 批量查询用户List<User> users = Db.listByIds(ids, User.class);if(CollUtil.isEmpty(users)){return Collections.emptyList();}users.forEach(System.out::println);// 2. 查询地址// 需要重新获取userIds,不能再直接使用ids, userIds保证都是存在的用户List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();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));}// 3. 转换VO返回List<UserVO> list = new ArrayList<>(users.size());for(User user : users){UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);userVO.setAddresses(addressMap.get(user.getId()));list.add(userVO);}return list;}

3.3 逻辑删除

对于一些比较重要的数据,我们往往会采用逻辑删除的方案,即:

  • 在表中添加一个字段标记数据是否被删除
  • 当删除数据时把标记置为true
  • 查询时过滤掉标记为true的数据

一旦采用了逻辑删除,所有的查询和删除逻辑都要跟着变化,非常麻烦。开启了逻辑删除功能以后,我们就可以像普通删除一样做CRUD,基本不用考虑代码逻辑问题。还是非常方便的。

然后给Address实体添加deleted字段

在这里插入图片描述

在application.yml中配置逻辑删除字段

mybatis-plus:global-config:db-config:logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)logic-delete-value: 1 # 逻辑已删除值(默认为 1)logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

测试

    @Testvoid testDeleteByLogic() {// 删除方法与以前没有区别addressService.removeById(59L);}

在这里插入图片描述

 @Testvoid testQuery() {List<Address> list = addressService.list();list.forEach(System.out::println);}

在这里插入图片描述

逻辑删除本身也有自己的问题,比如:

  • 会导致数据库表垃圾数据越来越多,从而影响查询效率
  • SQL中全都需要对逻辑删除字段做判断,影响查询效率

因此,我不太推荐采用逻辑删除功能,如果数据不能删除,可以采用把数据迁移到其它表的办法

4. 插件功能

4.1 分页插件

在未引入分页插件的情况下,MybatisPlus是不支持分页功能的,IService和BaseMapper中的分页方法都无法正常起效。
所以,我们必须配置分页插件。

配置分页插件

在这里插入图片描述

编写一个分页查询的测试

    @Testvoid testPage(){int pageNo = 1, pageSize = 2;// 1. 分页参数Page<User> page = Page.of(pageNo, pageSize);// 1.1 设置排序条件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);}

在这里插入图片描述

4.2 通用分页实体

现在要实现一个用户分页查询的接口,接口规范如下:

在这里插入图片描述

返回值

在这里插入图片描述

需要定义3个实体

  • UserQuery:分页查询条件的实体,包含分页、排序参数、过滤条件

  • PageDTO:分页结果实体,包含总条数、总页数、当前页数据

  • UserVO:用户页面视图实体

UserQuery具体代码如下

package com.itheima.mp.domain.query;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
@ApiModel(description = "用户查询条件实体")
public class UserQuery {@ApiModelProperty("用户名关键字")private String name;@ApiModelProperty("用户状态:1-正常,2-冻结")private Integer status;@ApiModelProperty("余额最小值")private Integer minBalance;@ApiModelProperty("余额最大值")private Integer maxBalance;
}

其中缺少的仅仅是分页条件,而分页条件不仅仅用户分页查询需要,以后其它业务也都有分页查询的需求。因此建议将分页查询条件单独定义为一个PageQuery实体:

PageQuery是前端提交的查询参数,一般包含四个属性:

  • pageNo:页码

  • pageSize:每页数据条数

  • sortBy:排序字段

  • isAsc:是否升序

@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {@ApiModelProperty("页码")private Long pageNo;@ApiModelProperty("页码")private Long pageSize;@ApiModelProperty("排序字段")private String sortBy;@ApiModelProperty("是否升序")private Boolean isAsc;
}

然后让UserQuery继承这个实体:

package com.itheima.mp.domain.query;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;@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;
}

PageDTO具体代码如下

package com.itheima.mp.domain.dto;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.List;@Data
@ApiModel(description = "分页结果")
public class PageDTO<T> {@ApiModelProperty("总条数")private Long total;@ApiModelProperty("总页数")private Long pages;@ApiModelProperty("集合")private List<T> list;
}

UserVO具体代码如下

package com.itheima.mp.domain.vo;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.List;@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;@ApiModelProperty("用户使用地址")private List<AddressVO> addresses;
}

开发接口

在UserController中定义分页查询用户的接口

package com.itheima.mp.controller;import cn.hutool.core.bean.BeanUtil;
import com.itheima.mp.domain.dto.PageDTO;
import com.itheima.mp.domain.dto.UserFormDTO;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.query.UserQuery;
import com.itheima.mp.domain.vo.UserVO;
import com.itheima.mp.service.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;@RequestMapping("/users")
@RestController
@Slf4j
@Api(tags = "用户管理接口")
public class UserController {@Resourceprivate IUserService userService;@GetMapping("/page")@ApiOperation("分页查询")public PageDTO<UserVO> queryUsersPage(UserQuery query){return userService.queryUsersPage(query);}
}

在IUserService中创建queryUsersPage方法

public interface IUserService extends IService<User> {PageDTO<UserVO> queryUsersPage(UserQuery query);
}

在UserServiceImpl中实现该方法

package com.itheima.mp.service.impl;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.itheima.mp.domain.dto.PageDTO;
import com.itheima.mp.domain.po.Address;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.query.UserQuery;
import com.itheima.mp.domain.vo.AddressVO;
import com.itheima.mp.domain.vo.UserVO;
import com.itheima.mp.mapper.UserMapper;
import com.itheima.mp.service.IUserService;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;import java.util.*;
import java.util.stream.Collectors;@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {@Overridepublic PageDTO<UserVO> queryUsersPage(UserQuery query) {// 1. 构造条件// 1.1 分页条件int pageNo = query.getPageNo();int pageSize = query.getPageSize();Page<User> page = Page.of(pageNo, pageSize);// 1.2 排序条件if(query.getSortBy() != null){page.addOrder(new OrderItem(query.getSortBy(), query.getIsAsc()));} else {// 默认按照更新时间排序page.addOrder(new OrderItem("update_time", false));}// 2. 查询// userService.page(page),由于是userService类自身的方法,所以不用再写userService// 2.1 不带筛选条件的// Page<User> p = page(page);// 2.2 带筛选条件的Page<User> p = lambdaQuery().like(query.getName() != null, User::getUsername, query.getName()).eq(query.getStatus() != null, User::getStatus, query.getStatus()).ge(query.getMaxBalance() != null, User::getBalance, query.getMinBalance()).lt(query.getMinBalance() != null, User::getBalance, query.getMaxBalance()).page(page);// 3. 数据校验是否合法List<User> users = p.getRecords();if(users == null || users.size() <= 0){// 无数据,返回空结果return new PageDTO<>(p.getTotal(), p.getPages(), Collections.emptyList());}// 4. 有数据转换List<UserVO> list = BeanUtil.copyToList(users, UserVO.class);// 5 返回封装结果return new PageDTO<>(p.getTotal(), p.getPages(), list);}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • git上传本地代码到新建分支
  • 00067期 matlab中的asv文件
  • Vue 3 中的观察者效果:从 watch 到 watchEffect、watchSyncEffect 和 watchPostEffect
  • 超全面!Midjourney用户手册中文版!详解模型、命令、参数与高级用法
  • MySQL 数据库经验总结
  • HttpUtils工具类(一)常见的HttpUtils工具类及如何自定义java的http连接池
  • 【机器学习】CNN的基本架构模块
  • 观察者模式和MQ是什么关系
  • Python利用openpyxl复制Excel文件且保留样式—另存为副本(附完整代码)
  • 零售业务产品系统应用架构设计(二)
  • 一伴app相亲交友源码开发
  • 新手常见错误:java.lang.NumberFormatException: For input string: “xxxx“
  • GD32 MCU内部温度传感器如何使用,以及适合哪种应用场景?
  • BQ27441初始化配置程序,电压、SOC等参数读取程序
  • 玩转单例模式
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • [译]CSS 居中(Center)方法大合集
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • Apache的基本使用
  • centos安装java运行环境jdk+tomcat
  • JS函数式编程 数组部分风格 ES6版
  • Laravel5.4 Queues队列学习
  • laravel5.5 视图共享数据
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 前端技术周刊 2019-01-14:客户端存储
  • 区块链技术特点之去中心化特性
  • 如何将自己的网站分享到QQ空间,微信,微博等等
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • 正则学习笔记
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • 如何在招聘中考核.NET架构师
  • ​一些不规范的GTID使用场景
  • #07【面试问题整理】嵌入式软件工程师
  • #if和#ifdef区别
  • #pragma预处理命令
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (2)空速传感器
  • (30)数组元素和与数字和的绝对差
  • (Forward) Music Player: From UI Proposal to Code
  • (纯JS)图片裁剪
  • (二)丶RabbitMQ的六大核心
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (计算机网络)物理层
  • (十三)MipMap
  • (转)菜鸟学数据库(三)——存储过程
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • .gitignore文件---让git自动忽略指定文件
  • .net core 连接数据库,通过数据库生成Modell
  • .NET Core中的去虚
  • .NET 漏洞分析 | 某ERP系统存在SQL注入
  • .NET编程C#线程之旅:十种开启线程的方式以及各自使用场景和优缺点
  • .NET构架之我见