微服务day01

news/2024/11/5 11:20:08 标签: 微服务, java, 前端

MybatisPlus

Mp入门

基本步骤

引入MybatisPlus依赖,代替Mybatis依赖

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

定义Mapper接口并继承BaseMapper

java">public interface UserMapper extends BaseMapper<User> {
}

常见注解

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

  • 类名驼峰转下划线作为表名
  • 名为id的字段作为主键
  • 变量名驼峰转下划线作为表的字段名

  • @TableName:用来指定表名
  • @TableId:用来指定表中的主键字段信息
  • @TableField:用来指定表中的普通字段信息

IdType枚举

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

使用@TableField的常见场景:

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

小结:

MybatisPlus是如何获取实现CRUD的数据库表信息的?

  • 默认以类名驼峰转下划线作为表名
  • 默认把名为id的字段作为主键
  • 默认把变量名驼峰转下划线作为表的字段名

MybatisPlus的常用注解有哪些?

  • @TableName:指定表名称及全局配置
  • @TableId:指定id字段及相关配置
  • @TableField:指定普通字段及相关配置

IdType的常见类型有哪些?

  • AUTO、ASSIGN_ID、INPUT 使用

@TableField的常见场景是?

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

常见配置

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

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true #开启下划线和驼峰映射
  global-config:
    db-config:
      logic-delete-field: flag # 全局逻辑删除的实体字段名(配置后可以忽略不配置步骤二)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
      update-strategy: not_null #更新策略(只更新非空字段)默认值
      id-type: assign_id #id 使用雪花算法生成
  type-aliases-package: com.itheima.mp.domain.po # 别名扫描包
  mapper-locations: classpath*:mapper/*.xml

具体可参考官方文档:使用配置 | MyBatis-Plus (baomidou.com)

基本步骤小结:

MyBatisPlus使用的基本流程是什么?

  1. 引入起步依赖
  2. 自定义Mapper基础BaseMapper
  3. 在实体类上添加注解声明 表信息
  4. 在application.yml中根据需要添加配置

核心功能

条件构造器

条件构造器的小结

条件构造器的用法:

  • QueryWrapper和LambdaQueryWrapper通常用来构建select、delete、update的where条件部分
  • UpdateWrapper和LambdaUpdateWrapper通常只有在set语句比较特殊才使用
  • 尽量使用LambdaQueryWrapper和LambdaUpdateWrapper,避免硬编码
自定义SQL

实现:

java">    void testBalesById(){
        //定义要修改的数据
        List<Long> ids = List.of(1L, 2L,4L);
        int amount = 200;
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(User::getId, ids);
        //自定义SQL方法调用
        userMapper.updateBalanceByIds(wrapper, amount);
    }
java"> void updateBalanceByIds(@Param("ew") LambdaQueryWrapper<User> wrapper,@Param("amount") int amount);
    <update id="updateBalanceByIds">
        update user set balance = balance - #{amount} ${ew.customSqlSegment}
    </update>
Server接口用法

实例:

接口

java">public interface UserService extends IService<User> {
}

 实现类

java">@org.springframework.stereotype.Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

}

 测试类

java">
@SpringBootTest
class UserUserServiceImplTest {
    @Autowired
    private UserService service;

    //新建数据
    @Test
    public void test(){
        User user = new User();
        user.setId(6L);
        user.setUsername("laozhang");
        user.setPassword("123");
        user.setPhone("18688990011");
        user.setBalance(200);
        user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        service.save(user);
    }

}
案例:

java">@Api(tags = "用户管理接口")
@RestController
@RequestMapping("/users")
@RequiredArgsConstructor //必要的构造函数 ,Lombok注解
public class UserController {

//    @Autowired //由于不推荐字段注入,所以使用构造函数进行注入
    //final 表示该属性是必须的,则RequiredArgsConstructor会将其加入构造函数中
    private final UserService userService;
    @PostMapping
    @ApiOperation("新增用户")
    public void saveUser(@RequestBody UserFormDTO userdto){
        User user = new User();
        BeanUtil.copyProperties(userdto,user);
        userService.save(user);
    }

    //删除yh
    @DeleteMapping("/{id}")
    @ApiOperation("删除用户")
    public void deleteUser(@ApiParam("用户id") @PathVariable Long id){
        userService.removeById(id);
    }

    @GetMapping("/{id}")
    @ApiOperation("根据id查询用户")
    public UserVO queryUserById(@ApiParam("用户id") @PathVariable Long id){
        User user = userService.getById(id);
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user,userVO);
        return userVO;
    }

    @GetMapping
    @ApiOperation("根据id查询用户列表")
    public List<UserVO> queryUserByIds(@ApiParam("用户id集合") @RequestParam("ids") List<Long> ids){
        List<User> list = userService.listByIds(ids);
        List<UserVO> userVOS = BeanUtil.copyToList(list, UserVO.class);
        return userVOS;
    }

    @PutMapping("/{id}/deduction/{money}")
    @ApiOperation("根据id扣减余额")
    public void updataByid(@ApiParam("用户id")@PathVariable("id")int id,@ApiParam("扣除金额")@PathVariable("money") int money){
        userService.updatamoneyByid(id,money);
    }

}
java">public interface UserService extends IService<User> {
    void updatamoneyByid(int id, int money);
}
java">@org.springframework.stereotype.Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Override
    public void updatamoneyByid(int id, int 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.扣减余额
        baseMapper.deductMoneyById(id, money);
    }
}
java">    void deductMoneyById(int id, int money);
    <update id="deductMoneyById">
        update user set balance = balance - #{money} where id = #{id}
    </update>
案例:IService的lambda查询

java">
    @Override
    public List<UserVO> queryUserByCondition(UserQuery userQuery) {
        LambdaQueryWrapper<User> wrapper = new QueryWrapper<User>().lambda()
                .eq(userQuery.getName()!=null, User::getUsername, userQuery.getName())
                .eq(userQuery.getStatus() != null, User::getStatus, userQuery.getStatus())
                .lt(userQuery.getMinBalance() != null, User::getBalance, userQuery.getMinBalance())
                .gt(userQuery.getMaxBalance() != null, User::getBalance, userQuery.getMaxBalance());
        return BeanUtil.copyToList( userMapper.selectList(wrapper), UserVO.class);
    }

java">    @Override
    public void updatamoneyByid(int id, int 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.扣减余额
//        baseMapper.deductMoneyById(id, money);
        int i = user.getBalance() - money;
        LambdaUpdateWrapper<User> eq = new UpdateWrapper<User>()
                .lambda()
                .set(User::getBalance, i)
                .set(i == 0, User::getStatus, 2)
                .set(User::getBalance, user.getBalance()) //添加乐观锁,即在修改之前判断数据是否被其他线程修改
                                                          //  如果两数的值相等则可判断未被修改
                .eq(User::getId, id);
        this.update(eq);

    }
IService批量新增

普通批处理

java">@Test
void testSaveOneByOne() {
    long b = System.currentTimeMillis();
    for (int i = 1; i <= 100000; i++) {
        userService.save(buildUser(i));
    }
    long e = System.currentTimeMillis();
    System.out.println("耗时:" + (e - b));
}

private User buildUser(int i) {
    User user = new User();
    user.setUsername("user_" + i);
    user.setPassword("123");
    user.setPhone("" + (18688190000L + i));
    user.setBalance(2000);
    user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
    user.setCreateTime(LocalDateTime.now());
    user.setUpdateTime(user.getCreateTime());
    return user;
}

mp的批处理

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

修改项目中的application.yml文件,在jdbc的url后面添加参数&rewriteBatchedStatements=true:

spring: datasource: url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true driver-class-name: com.mysql.cj.jdbc.Driver username: root password: MySQL123

扩展功能:

代码生成功能

静态工具

        静态工具可以避免循环依赖

需求一:

java">    @GetMapping("/{id}")
    @ApiOperation("根据id查询用户")
    public UserVO queryUserById(@ApiParam("用户id") @PathVariable Long id){
        UserVO userVO = userService.queryUserandaddresById(id);
        return userVO;
    }
java">    UserVO queryUserandaddresById(Long id);
java">    @Override
    public UserVO queryUserandaddresById(Long id) {
        //根据id查询用户信息
        User user = getById(id);
        if (user == null|| user.getStatus() == 2){
            throw new RuntimeException("用户状态异常");
        }
        //根据id查询地址信息
        //使用静态工具来进行处理
        List<Address> list = Db.lambdaQuery(Address.class).eq(Address::getUserId, id).list();

        // 封装VO
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        //判断地址是否为空
        if (CollUtil.isNotEmpty(list)){
            userVO.setAddressList(BeanUtil.copyToList(list, AddressVO.class));
        }


        return userVO;
    }

需求二:

java">    @GetMapping
    @ApiOperation("根据id查询用户列表")
    public List<UserVO> queryUserByIds(@ApiParam("用户id集合") @RequestParam("ids") List<Long> ids){
//        List<User> list = userService.listByIds(ids);
//        List<UserVO> userVOS = BeanUtil.copyToList(list, UserVO.class);
        List<UserVO> userVOS =  userService.queryUserandaddresByIds(ids);
        return userVOS;
    }
java">    public List<UserVO> queryUserandaddresByIds(List<Long> ids) {
        List<User> users = listByIds(ids);
        if (CollUtil.isEmpty(users)){
            throw new RuntimeException("用户不存在");
        }
        //获取用户id的集合
        List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());

        List<Address> addressList = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();

        if (CollUtil.isEmpty(addressList)){
            throw new RuntimeException("地址信息不存在");
        }
        //将集合按照用户id合并
        List<AddressVO> addressVOlist = BeanUtil.copyToList(addressList, AddressVO.class);

        List<UserVO> userVOlist = BeanUtil.copyToList(users, UserVO.class);

        //使用Stream流的分组功能,根据id进行分组
        Map<Long, List<AddressVO>> collect = addressVOlist.stream().collect(Collectors.groupingBy(AddressVO::getUserId));
        userVOlist.forEach(userVO -> userVO.setAddressList(collect.get(userVO.getId())));

        return userVOlist;
    }

需求三:

java">@RestController
@RequestMapping("/address")
@RequiredArgsConstructor
@Api(tags = "收货地址管理接口")
public class AddressController {

    private final IAddressService addressService;

    //根据用户id查询收货地址
    @ApiOperation("根据用户id查询地址")
    @GetMapping("/{userId}")
    public List<AddressVO> queryAddressByUserId(@ApiParam("用户id") @PathVariable Long userId)
    {
        List<AddressVO> addressVOS = addressService.queryAddressByUserId(userId);
        return addressVOS;
    }
}
java">@Service
public class AddressServiceImpl extends ServiceImpl<AddressMapper, Address> implements IAddressService {

    @Override
    public List<AddressVO> queryAddressByUserId(Long userId) {
        //根据用户id查询收货地址
        LambdaQueryWrapper<Address>  queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Address::getUserId,userId);
        List<Address> addressList = list(queryWrapper);
        //判断用户状态
        User user = Db.getById(userId, User.class);
        if (user.getStatus() == 2){
            throw new RuntimeException("用户状态异常");
        }
        return BeanUtil.copyToList(addressList, AddressVO.class);
    }
}
逻辑删除

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true #开启下划线和驼峰映射
  global-config:
    db-config:
      logic-delete-field: deleted # 全局逻辑删除的实体字段名(配置后可以忽略不配置步骤二)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
      update-strategy: not_null #更新策略(只更新非空字段)默认值
      id-type: assign_id #id 使用雪花算法生成
  type-aliases-package: com.itheima.mp.domain.po # 别名扫描包
  mapper-locations: classpath*:mapper/*.xml
java">package com.itheima.mp.controller;

import com.itheima.mp.domain.po.Address;
import com.itheima.mp.service.IAddressService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class AddressControllerTest {
    @Autowired
    private IAddressService addressService;
    @Test
    public void deleteAddress(){
        addressService.removeById(59);
    }

    @Test
    public void queryAddress(){
        Address addressServiceById = addressService.getById(59);
        System.out.println("address:"+addressServiceById);
    }

}
枚举处理器

使用步骤

  1. 在枚举类型中的价值属性添加 @EnumValue 注解
  2. 在配置文件中配置枚举处理器

mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
java">@Getter
public enum UserStatus {


    NORMAL(1,"正常"),

    FREEZE(2,"冻结")
    ;
    @EnumValue //用于指示mp要将此枚举值存储到数据库中
    private Integer value;
    @JsonValue //用于指示此枚举值在json中返回,否则返回的是枚举名称,而不是枚举值,
                // 枚举值是数据库存储的值,而枚举名称是java代码中定义的
                //JsonValue为序列化,EnumValue为反序列化
                // JsonValue为Jackson注解,用于告诉springMvc要返回前端的数据
    private String desc;
    UserStatus(Integer value, String desc) {
        this.value = value;
        this.desc = desc;
    }
}

修改po和vo

java">    /**
     * 使用状态(1正常 2冻结)
     */
    private UserStatus status;

JSON处理器

java">@Data
@NoArgsConstructor
@AllArgsConstructor(staticName = "of")//定义有参构造名称为of
public class UserInfo {
    private Integer age;
    private String intro;
    private String gender;
}
java">package com.itheima.mp.domain.po;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.itheima.mp.enums.UserStatus;
import lombok.Data;

import java.time.LocalDateTime;

@Data
@TableName(autoResultMap = true,value = "user")
public class User {

    /**
     * 用户id
     */
    private Long id;

    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;

    /**
     * 注册手机号
     */
    private String phone;

    /**
     * 详细信息
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private UserInfo info;

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

    /**
     * 账户余额
     */
    private Integer balance;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 更新时间
     */
    private LocalDateTime updateTime;
}
java">package com.itheima.mp.domain.vo;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.itheima.mp.domain.po.UserInfo;
import com.itheima.mp.enums.UserStatus;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.List;

@Data
@ApiModel(description = "用户VO实体")
@TableName(autoResultMap = true)
public class UserVO {
    
    @ApiModelProperty("用户id")
    private Long id;
    
    @ApiModelProperty("用户名")
    private String username;
    
    @ApiModelProperty("详细信息")
    @TableField(typeHandler = JacksonTypeHandler.class)
    private UserInfo info;

    @ApiModelProperty("使用状态(1正常 2冻结)")
    private UserStatus status;
    
    @ApiModelProperty("账户余额")
    private Integer balance;

    @ApiModelProperty("地址列表")
    private List<AddressVO> addressList;
}
插件功能

分页插件

java">package com.itheima.mp.config;

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.Configuration;

@Configuration
public class MybatieConfig {
    //mybatis-plus分页插件
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        //创建核心拦截器
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //添加分页拦截器
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        //添加拦截器配置
        paginationInnerInterceptor.setMaxLimit(100L);//查询最大值
        //加入核心拦截器
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}
java">    @Test
    public void test2(){
        //分页查询测试
        int pageNum = 1;
        int pageSize = 10;

        Page<User> page = new Page<>(pageNum, pageSize);
        //添加分页查询的排序条件
        //先按照第一个排序,在排第二个
        page.addOrder(new OrderItem("balance",true));
        page.addOrder(new OrderItem("id",false));

        Page<User> page1 = service.page(page);

        //展示数据
        long total = page1.getTotal();
        System.out.println("total:"+total);
        System.out.println("current:"+page1.getCurrent());
        System.out.println("size:"+page1.getSize());
        page1.getRecords().forEach(System.out::println);
    }
通用分页实体
案例:简单分页查询

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

开发接口:

java">package com.itheima.mp.controller;

import com.itheima.mp.domain.dto.PageDTO;
import com.itheima.mp.domain.query.PageQuery;
import com.itheima.mp.domain.vo.UserVO;
import com.itheima.mp.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    @GetMapping("/page")
    public PageDTO<UserVO> queryUsersPage(UserQuery query){
        return userService.queryUsersPage(query);
    }

    // 。。。 略
}
java">@Override
public PageDTO<UserVO> queryUsersPage(PageQuery query) {
    // 1.构建条件
    // 1.1.分页条件
    Page<User> page = Page.of(query.getPageNo(), query.getPageSize());
    // 1.2.排序条件
    if (query.getSortBy() != null) {
        page.addOrder(new OrderItem(query.getSortBy(), query.getIsAsc()));
    }else{
        // 默认按照更新时间排序
        page.addOrder(new OrderItem("update_time", false));
    }
    // 2.查询
    page(page);
    // 3.数据非空校验
    List<User> records = page.getRecords();
    if (records == null || records.size() <= 0) {
        // 无数据,返回空结果
        return new PageDTO<>(page.getTotal(), page.getPages(), Collections.emptyList());
    }
    // 4.有数据,转换
    List<UserVO> list = BeanUtil.copyToList(records, UserVO.class);
    // 5.封装返回
    return new PageDTO<UserVO>(page.getTotal(), page.getPages(), list);
}

改造PageQuery实体

java">package com.itheima.mp.domain.query;

import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;

@Data
public class PageQuery {
    private Integer pageNo;
    private Integer pageSize;
    private String sortBy;
    private Boolean isAsc;

    public <T>  Page<T> toMpPage(OrderItem ... orders){
        // 1.分页条件
        Page<T> p = Page.of(pageNo, pageSize);
        // 2.排序条件
        // 2.1.先看前端有没有传排序字段
        if (sortBy != null) {
            p.addOrder(new OrderItem(sortBy, isAsc));
            return p;
        }
        // 2.2.再看有没有手动指定排序字段
        if(orders != null){
            p.addOrder(orders);
        }
        return p;
    }

    public <T> Page<T> toMpPage(String defaultSortBy, boolean isAsc){
        return this.toMpPage(new OrderItem(defaultSortBy, isAsc));
    }

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

    public <T> Page<T> toMpPageDefaultSortByUpdateTimeDesc() {
        return toMpPage("update_time", false);
    }
}
java">// 1.构建条件
Page<User> page = query.toMpPageDefaultSortByCreateTimeDesc();

.改造PageDTO实体

java">package com.itheima.mp.domain.dto;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageDTO<V> {
    private Long total;
    private Long pages;
    private List<V> list;

    /**
     * 返回空分页结果
     * @param p MybatisPlus的分页结果
     * @param <V> 目标VO类型
     * @param <P> 原始PO类型
     * @return VO的分页对象
     */
    public static <V, P> PageDTO<V> empty(Page<P> p){
        return new PageDTO<>(p.getTotal(), p.getPages(), Collections.emptyList());
    }

    /**
     * 将MybatisPlus分页结果转为 VO分页结果
     * @param p MybatisPlus的分页结果
     * @param voClass 目标VO类型的字节码
     * @param <V> 目标VO类型
     * @param <P> 原始PO类型
     * @return VO的分页对象
     */
    public static <V, P> PageDTO<V> of(Page<P> p, Class<V> voClass) {
        // 1.非空校验
        List<P> records = p.getRecords();
        if (records == null || records.size() <= 0) {
            // 无数据,返回空结果
            return empty(p);
        }
        // 2.数据转换
        List<V> vos = BeanUtil.copyToList(records, voClass);
        // 3.封装返回
        return new PageDTO<>(p.getTotal(), p.getPages(), vos);
    }

    /**
     * 将MybatisPlus分页结果转为 VO分页结果,允许用户自定义PO到VO的转换方式
     * @param p MybatisPlus的分页结果
     * @param convertor PO到VO的转换函数
     * @param <V> 目标VO类型
     * @param <P> 原始PO类型
     * @return VO的分页对象
     */
    public static <V, P> PageDTO<V> of(Page<P> p, Function<P, V> convertor) {
        // 1.非空校验
        List<P> records = p.getRecords();
        if (records == null || records.size() <= 0) {
            // 无数据,返回空结果
            return empty(p);
        }
        // 2.数据转换
        List<V> vos = records.stream().map(convertor).collect(Collectors.toList());
        // 3.封装返回
        return new PageDTO<>(p.getTotal(), p.getPages(), vos);
    }
}

化简:

java">@Override
public PageDTO<UserVO> queryUserByPage(PageQuery query) {
    // 1.构建条件
    Page<User> page = query.toMpPageDefaultSortByCreateTimeDesc();
    // 2.查询
    page(page);
    // 3.封装返回
    return PageDTO.of(page, UserVO.class);
}
java">@Override
public PageDTO<UserVO> queryUserByPage(PageQuery query) {
    // 1.构建条件
    Page<User> page = query.toMpPageDefaultSortByCreateTimeDesc();
    // 2.查询
    page(page);
    // 3.封装返回
    return PageDTO.of(page, user -> {
        // 拷贝属性到VO
        UserVO vo = BeanUtil.copyProperties(user, UserVO.class);
        // 用户名脱敏
        String username = vo.getUsername();
        vo.setUsername(username.substring(0, username.length() - 2) + "**");
        return vo;
    });
}


http://www.niftyadmin.cn/n/5739405.html

相关文章

命令kill

kill命令用于终止进程 kill [options] <PID> options 选项 kill -9 要强制终止进程 默认情况下&#xff0c;kill 命令发送的是终止信号&#xff08;SIGTERM&#xff0c;信号编号 15&#xff09;&#xff0c;大多数进程在接收到这个信号后会正常结束。 如果进程没有响应…

arm64-v8a 和 armeabi-v7a 有啥区别?

ARM64-v8a 和 ARMEABI-v7a 是 Android 平台上两种不同的 ARM 架构&#xff0c;用于支持应用程序的运行。它们之间有几个关键的区别&#xff1a; 1. 架构类型 ARM64-v8a&#xff1a;代表的是 64 位的 ARM 架构&#xff08;ARMv8-A&#xff09;。它能够处理更大范围的地址空间和…

angular实现list列表和翻页效果

说明&#xff1a;angular实现list列表和翻页效果 上一页 当前页面 下一页 效果图&#xff1a; step1: E:\projectgood\ajnine\untitled4\src\app\car\car.component.css .example-form-fields {display: flex;align-items: flex-start; }mat-list-item{background: antiquew…

MongoDB笔记02-MongoDB基本常用命令

文章目录 一、前言二、数据库操作2.1 选择和创建数据库2.2 数据库的删除 3 集合操作3.1 集合的显式创建3.2 集合的隐式创建3.3 集合的删除 四、文档基本CRUD4.1 文档的插入4.1.1 单个文档插入4.1.2 批量插入 4.2 文档的基本查询4.2.1 查询所有4.2.2 投影查询&#xff08;Projec…

接口测试(十)jmeter——关联(正则表达式提取器)

一、正则表达式 常用的元字符 元字符&#xff1a;用来匹配相关字符 万能匹配表达式&#xff1a; .*? 所有log结尾的文件&#xff1a;*.log 代码说明.匹配除换行符以外的任意字符\w匹配字母或数字或下划线或汉字\s匹配任意的空白符\d匹配数字\b匹配单词的开始或结束^匹配字符…

基于Prometheus的client_golang库实现应用的自定义可观测监控

文章目录 1. 安装client_golang库2. 编写可观测监控代码3. 运行效果4. jar、graalvm、golang编译运行版本对比 前文使用javagraalvm实现原生应用可观测监控&#xff1a; prometheus client_java实现进程的CPU、内存、IO、流量的可观测&#xff0c;但是部分java依赖包使用了复杂…

基于SpringBoot的母婴商城的设计与实现

一、项目背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规范化管理。这样的大环境让那些止步不前&#xff0c;…

oauth2登录,单点登录

常见的 单系统cookie登陆&#xff0c;session登陆&#xff0c;jwt(json web token)。 oauth2 登录 OAuth 2.0 是目前最流行的授权机制&#xff0c;用来授权第三方应用&#xff0c;获取用户数据。学习文章 以一个例子来说&#xff0c;我住在一个大型小区&#xff0c;有门禁系…