MybatisPlus使用指南

server/2024/9/22 13:46:29/

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接口

java">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元的人。代码如下:

java">@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,代码如下:

java">@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,代码如下:

java">@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

java">@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语句:

java"> @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:

java">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:

java">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

java">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无需注入

java">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

java">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

java">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实体:

java">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方法:

java">@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

java">@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查询用户的接口,查询用户的同时,查询出用户对应的所有地址改造;

java">    @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批量查询用户的接口,查询用户的同时,查询出用户对应的所有地址;

java"> 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)

测试

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

在这里插入图片描述

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

在这里插入图片描述

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

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

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

4. 插件功能

4.1 分页插件

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

配置分页插件

在这里插入图片描述

编写一个分页查询的测试

java">    @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具体代码如下

java">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:是否升序

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

然后让UserQuery继承这个实体:

java">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具体代码如下

java">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具体代码如下

java">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中定义分页查询用户的接口

java">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方法

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

在UserServiceImpl中实现该方法

java">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);}
}

http://www.ppmy.cn/server/100859.html

相关文章

机器学习-卷积神经网络(CNN)

机器学习-卷积神经网络&#xff08;CNN&#xff09; 1. 卷积神经网络的基本概念1.1 卷积层&#xff08;Convolutional Layer&#xff09;1.1.1 卷积操作1.1.2 特征图&#xff08;Feature Map&#xff09; 1.2 激活函数&#xff08;Activation Function&#xff09;1.2.1 ReLU&a…

滑动窗口记录左右的最大值

前言&#xff1a;看到这个题目的时候分析了一下&#xff0c;就是最大值问题&#xff0c;但是要注意分类讨论 以后遇到离散化的问题&#xff0c;还可以开一个map来记录存在的点&#xff0c;免得二分查找的点不存在 #include<bits/stdc.h> using namespace std;const int …

AWS认证SAA-C03每日一题

本题库由云计算狂魔微信公众号分享。 【SAA-C03助理级解决方案架构师认证】 A company hosts an application on AWS Lambda functions that are invoked by an Amazon API Gateway API. The Lambda functions save customer data to an Amazon Aurora MySQL database Wheneve…

Unity 6 预览版正式发布

Unity 6 预览版发布啦&#xff0c;正式版本将于今年晚些时候正式发布&#xff01; 下载链接&#xff1a; https://unity.com/releases/editor/whats-new/6000.0.0 Unity 6 预览版是 Unity 6 开发周期的最后一个版本&#xff0c;在去年 11 月 Unite 大会上&#xff0c;我们宣…

【Next】全局样式和局部样式

不同于 nuxt &#xff0c;next 的样式绝大部分都需要手动导入。 全局样式 使用 sass 先安装 npm i sass -D 。 我们可以定义一个 styles 文件&#xff0c;存放全局样式。 variables.scss $fs30: 30px;mixin border() {border: 1px solid red; }main.scss use ./variables …

AI芯片:高性能卷积计算中的数据复用

随着深度学习的飞速发展&#xff0c;对处理器的性能要求也变得越来越高&#xff0c;随之涌现出了很多针对神经网络加速设计的AI芯片。卷积计算是神经网络中最重要的一类计算&#xff0c;本文分析了高性能卷积计算中的数据复用&#xff0c;这是AI芯片设计中需要优化的重点之一&a…

旅行商问题变体:欧几里德平面中线段最小连接算法

问题描述 假设在欧几里德平面上有有限多条线段&#xff0c;如何将它们连接起来&#xff0c;形成一条最小长度的线段链&#xff1f; 首先&#xff0c;自然可以穷举所有情况&#xff0c;找到最优解。还可以采用动态规划、贪心算法找到局部最优解。 另外&#xff0c;则将其作为T…

tcpdump入门——四次挥手

客户端断开tcp连接&#xff1a; 数据包分析&#xff1a; 上面抓到的四次挥手包确实展示了 TCP 连接终止的过程&#xff0c;但观察到的包顺序和标志位可能会和经典的四次握手示例稍有不同&#xff0c;这是因为在实际网络中&#xff0c;TCP 连接的终止过程可能会有一些优化或变化…