五天SpringCloud计划——DAY1之mybatis-plus的使用

server/2024/11/27 2:12:55/

一、引言

   咱也不知道为啥SpringCloud课程会先教mybatis-plus的使用,但是教都教了,就学了吧,学完之后觉得mybatis-plus中的一些方法还是很好用了,本文作为我学习mybatis-plus的总结提升,希望大家看完之后也可以熟悉mybatis-plus的使用

二、mybatis-plus

1.依赖引入

在xml文件中引入mybatis-plus依赖

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

注:引入这个依赖就代表吧mybatis的依赖随便引入引入进来了,可以删除你引入mybatis依赖

2.继承BaseMapper

之所以我们可以使用mybatis-plus中简单的单表CRUD方法,是因为mybatis-plus提供了相应的方法类BaseMapper,而我们的mapper只需要继承BaseMapper即可使用其中的方法

注:这里要指定泛型,如<User>这样才能知道你增删改查的对象是什么类型,User和数据库中的字段相对应

java">package com.itheima.mp.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.mp.domain.po.User;public interface UserMapper extends BaseMapper<User> {
}

3.使用基本的CRUD方法

java">package com.itheima.mp.mapper;import com.itheima.mp.domain.po.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.time.LocalDateTime;
import java.util.List;@SpringBootTest
class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testvoid testInsert() {User user = new User();user.setId(5L);user.setUsername("Lucy");user.setPassword("123");user.setPhone("18688990011");user.setBalance(200);user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userMapper.insert(user);}@Testvoid testSelectById() {User user = userMapper.selectById(5L);System.out.println("user = " + user);}@Testvoid testSelectByIds() {List<User> users = userMapper.selectBatchIds(List.of(1L, 2L, 3L, 4L, 5L));users.forEach(System.out::println);}@Testvoid testUpdateById() {User user = new User();user.setId(5L);user.setBalance(20000);userMapper.updateById(user);}@Testvoid testDelete() {userMapper.deleteById(5L);}
}

代码中

1.userMapper.insert(user)          新增方法

2.userMapper.selectById(5L);     根据id单个查询全部信息

3.userMapper.selectBatchIds(List.of(1L, 2L, 3L, 4L, 5L));  根据id批量查询信息

4.userMapper.updateById(user);  根据id修改信息,这里默认指修改有值的部分,即balance

5.userMapper.deleteById(5L);  根据id删除信息

这些方法见名知意,也是很好记,如果仔细看测试输出,会发现其在底层是自动生成了相应的CRUD方法的,如下

11:05:01  INFO 15524 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
11:05:02  INFO 15524 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
11:05:02 DEBUG 15524 --- [           main] c.i.mp.mapper.UserMapper.selectById      : ==>  Preparing: SELECT id,username,password,phone,info,status,balance,create_time,update_time FROM user WHERE id=?
11:05:02 DEBUG 15524 --- [           main] c.i.mp.mapper.UserMapper.selectById      : ==> Parameters: 5(Long)
11:05:02 DEBUG 15524 --- [           main] c.i.mp.mapper.UserMapper.selectById      : <==      Total: 1
user = User(id=5, username=Lucy, password=123, phone=18688990011, info={"age": 21}, status=1, balance=20000, createTime=Fri Jun 30 11:02:30 CST 2023, updateTime=Fri Jun 30 11:02:30 CST 2023)

4.BaseMapper<User>中的<User>的讲究

看完上面的讲解,大家肯定会疑问,mybatis-plus是如何通过我指定的<User>泛型,找到我相应的数据库的表的,现在就给大家解开这个谜题

其实,在你的User实体类的定义时是有讲究的

比如我的User就是这样的

java">package com.itheima.mp.domain.po;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.itheima.mp.domain.vo.AddressVO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.time.LocalDateTime;
import java.util.List;@Data
@TableName("user")
public class User {
//@TableField使用场景
//  1.成员变量名与数据库名称不一致
//  2.成员变量以is开头而且是布尔值  isMarried
//  3.成员变量名与数据库关键字冲突  order/*** 用户id*/@TableId(value = "id",type = IdType.AUTO)private Long id;/*** 用户名*/@TableField("username")private String username;/*** 密码*/private String password;/*** 注册手机号*/private String phone;/*** 详细信息*/private String info;/*** 使用状态(1正常 2冻结)*/private Integer status;/*** 账户余额*/private Integer balance;/*** 创建时间*/private LocalDateTime createTime;/*** 更新时间*/private LocalDateTime updateTime;@ApiModelProperty("用户的收货地址")private List<AddressVO> address;
}

默认情况下

  • MybatisPlus会把PO实体的类名驼峰转下划线作为表名

  • MybatisPlus会把PO实体的所有变量名驼峰转下划线作为表的字段名,并根据变量类型推断字段类型

  • MybatisPlus会把名为id的字段作为主键

注:名词解释PO,指实体类

可以发现里面有很多的注解,也就是这些注解在起作用,下面给大家讲解一下这些注解

1.@TableName("user"),指定实体类名对应的表名,也就是User实体类就对应user表

2.@TableId(value = "id",type = IdType.AUTO),指定主键对应的字段,type中的type = IdType.AUTO,代表主键自增

还有其他的type,这里说明一下

AUTO

数据库 ID 自增

NONE

无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)

INPUT

insert 前自行 set 主键值

ASSIGN_ID

分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)

ASSIGN_UUID

分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)

3.@TableField("username")指定对象属性对应的表中字段,用到它有三种情况

  • 成员变量名与数据库字段名不一致

  • 成员变量是以isXXX命名,按照JavaBean的规范,MybatisPlus识别字段时会把is去除,这就导致与数据库不符。

  • 成员变量名与数据库一致,但是与数据库的关键字冲突。使用@TableField注解给字段名添加转义字符:``

5.更加复杂的数据库操作

这里指更加复杂的where条件,因为前文都是简单的根据id怎么样,根据id列表怎么样,但是如果指定其他字段查询又该怎么办呢,这里就是为了解决这个问题

在解决这个问题之前,给大家介绍几个条件构造的抽象类,就是这些抽象类里面可以装我们的条件,然后就可以用这些条件去作为where条件

接下来给大家介绍一下其中常用的几个抽象类

1)QueryWrapper

下面是一个使用QueryWrapper的例子,用来查询出名字中带o的,存款大于等于1000元的人。

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

其中的wrapper便是一个条件构造器,其中构造了三个条件:

1..select("id", "username", "info", "balance")

表示要查找id、username、info、balance四个字段

2..like("username", "o")

表示模糊查询,即username中带o

3..ge("balance", 1000)

表示balance的值大于1000

之后调用userMapper.selectList(wrapper);查询结果列表,将我们的条件构造器wrapper传入进去

让我们再举一个例子

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

java">@Test
void testUpdateByQueryWrapper() {// 1.构建查询条件 where name = "Jack"QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", "Jack");// 2.更新数据,user中非null字段都会作为set语句User user = new User();user.setBalance(2000);userMapper.update(user, wrapper);
}

这里包含了两部分,怎么改,改哪个:

怎么改---

就像前文讲到的updateById(user),创建一个对象,mybatis-plus默认修改其中有值的字段

改哪里---

这时候就得请出我们的QueryWrapper了,构造条件username为Jack

2)UpdateWrapper

这里也给大家举例

更新id为1,2,4的用户的余额,扣200

java">@Test
void testUpdateWrapper() {List<Long> ids = List.of(1L, 2L, 4L);// 1.生成SQLUpdateWrapper<User> wrapper = new UpdateWrapper<User>().setSql("balance = balance - 200") // SET balance = balance - 200.in("id", ids); // WHERE id in (1, 2, 4)// 2.更新,注意第一个参数可以给null,也就是不填更新字段和数据,// 而是基于UpdateWrapper中的setSQL来更新userMapper.update(null, wrapper);
}

大家可以看到这个需求,它需要自定义SQL语句,即"balance = balance - 200",这句需要加在sql语句中set的后面,UpdateWrapper便提供了这种功能

3)LambdaQueryWrapper

无论是QueryWrapper还是UpdateWrapper在构造条件的时候都需要写死字段名称,会出现字符串魔法值。这在编程规范中显然是不推荐的。

于是出现了LambdaQueryWrapper和LambdaUpdateWrapper,他们可以通过反射获取属性名,并不需要写死

代码如下

java">@Test
void testLambdaQueryWrapper() {// 1.构建条件 WHERE username LIKE "%o%" AND balance >= 1000QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.lambda().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);
}

这里的User::getId便代替了id

4)自定义SQL

在企业中,通常SQL语句维护在持久层,所以我们写在业务层的方法是不被允许的,所以我们来改造一下我们的代码

源代码---

java">@Test
void testUpdateWrapper() {List<Long> ids = List.of(1L, 2L, 4L);// 1.生成SQLUpdateWrapper<User> wrapper = new UpdateWrapper<User>().setSql("balance = balance - 200") // SET balance = balance - 200.in("id", ids); // WHERE id in (1, 2, 4)// 2.更新,注意第一个参数可以给null,也就是不填更新字段和数据,// 而是基于UpdateWrapper中的setSQL来更新userMapper.update(null, wrapper);
}

改造之后的代码---

java">@Test
void testCustomWrapper() {// 1.准备自定义查询条件List<Long> ids = List.of(1L, 2L, 4L);QueryWrapper<User> wrapper = new QueryWrapper<User>().in("id", ids);// 2.调用mapper的自定义方法,直接传递WrapperuserMapper.deductBalanceByIds(200, wrapper);
}
java">package com.itheima.mp.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.mp.domain.po.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.Param;public interface UserMapper extends BaseMapper<User> {@Select("UPDATE user SET balance = balance - #{money} ${ew.customSqlSegment}")void deductBalanceByIds(@Param("money") int money, @Param("ew") QueryWrapper<User> wrapper);
}

这里需要注意三点

1.在int money前加@Param("money")是为了确保money接收的是传来的money

2.在QueryWrapper<User> wrapper)前要加@Param("ew"),这样才可以识别到是一个条件构造器

3.${ew.customSqlSegment},这是字符串拼接,写法是固定的

这里我其实有一个疑问,如果SQL语句维护在持久层,那么UpdateWrapper的setSql是否还有用的必要,或者说UpdateWrapper是否还有用的必要

5)多表关联查询

理论上来讲MyBatisPlus是不支持多表查询的,不过我们可以利用Wrapper中自定义条件结合自定义SQL来实现多表查询的效果。

例如,我们要查询出所有收货地址在北京的并且用户id在1、2、4之中的用户

我们可以这样实现

查询条件这样来构建:

java">@Test
void testCustomJoinWrapper() {// 1.准备自定义查询条件QueryWrapper<User> wrapper = new QueryWrapper<User>().in("u.id", List.of(1L, 2L, 4L)).eq("a.city", "北京");// 2.调用mapper的自定义方法List<User> users = userMapper.queryUserByWrapper(wrapper);users.forEach(System.out::println);
}

然后在UserMapper中自定义方法:

java">@Select("SELECT u.* FROM user u INNER JOIN address a ON u.id = a.user_id ${ew.customSqlSegment}")
List<User> queryUserByWrapper(@Param("ew")QueryWrapper<User> wrapper);
6)小总结

这部分内容比较多,我总结一下要点

mybatis-plus处理“更复杂的数据库操作”主要是通过条件构造器来实现的,个人觉得最好用的是LambdaQueryWrapper,因为其比较全面,包括反射,条件构造,在更新的方法也可以用到它

而条件构造器主要是构造where之后的内容,比如我们所讲到的自定义sql,字符串拼接的也是where部分的内容

6.Service接口

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

  • save:新增

  • remove:删除

  • update:更新

  • get:查询单个结果

  • list:查询集合结果

  • count:计数

  • page:分页查询

其实学到这里的时候我就在想,BaseMapper已经够全面了,为啥要来一个IService,我这里猜测一下,是为了迎合三层架构(瞎猜的)

这里的学习方法就和学习BaseMapper很像了

1)继承

首先,定义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 {
}

这样就可以使用mybatis-plus准备好的方法了

2)CRUD

又来到了我们的增删改查环节,实现下面四个接口噢

编号

接口

请求方式

请求路径

请求参数

返回值

1

新增用户

POST

/users

用户表单实体

2

删除用户

DELETE

/users/{id}

用户id

3

根据id查询用户

GET

/users/{id}

用户id

用户VO

4

根据id批量查询

GET

/users

用户id集合

用户VO集合

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.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;import java.util.List;@Api(tags = "用户管理接口")
@RequiredArgsConstructor
@RestController
@RequestMapping("users")
public class UserController {private final IUserService userService;@PostMapping@ApiOperation("新增用户")public void saveUser(@RequestBody UserFormDTO userFormDTO){// 1.转换DTO为POUser user = BeanUtil.copyProperties(userFormDTO, User.class);// 2.新增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){// 1.查询用户User user = userService.getById(userId);// 2.处理voreturn BeanUtil.copyProperties(user, UserVO.class);}@GetMapping@ApiOperation("根据id集合查询用户")public List<UserVO> queryUserByIds(@RequestParam("ids") List<Long> ids){// 1.查询用户List<User> users = userService.listByIds(ids);// 2.处理voreturn BeanUtil.copyToList(users, UserVO.class);}
}

这里的CRUD方法和BaseMapper的用法相似,只是名称不一致

1.userService.save(user)                    新增用户

2.userService.removeById(userId)      根据id删除用户

3.userService.getById(userId)              根据id查询用户

4.userService.listByIds(ids)                   根据id列表查询用户

这里有需要注意的方法

1.BeanUtil.copyProperties(userFormDTO, User.class)  字段映射

2.BeanUtil.copyToList(users, UserVO.class)  批量字段映射

3.@RequiredArgsConstructor+private final IUserService userService;

   这里注入userService,是一种更推荐的写法

3)controller+service+mapper

下面尝试实现根据id扣减用户余额

我们发现在UserController中好像实现不了这个功能,因为牵扯到业务逻辑的代码我们要放在service层去实现,不然代码就太乱了,而且牵扯到了自定义sql,还要用到mapper层

业务逻辑如下

  • 判断用户状态是否正常

  • 判断用户余额是否充足

 1.UserController,这里不需要处理业务逻辑,所以直接调用service

java">@PutMapping("{id}/deduction/{money}")
@ApiOperation("扣减用户余额")
public void deductBalance(@PathVariable("id") Long id, @PathVariable("money")Integer money){userService.deductBalance(id, money);
}

 2.这里是接口哈

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> {void deductBalance(Long id, Integer money);
}

3.实现类 

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.mapper.UserMapper;
import com.itheima.mp.service.IUserService;
import org.springframework.stereotype.Service;@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {@Overridepublic void deductBalance(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.扣减余额baseMapper.deductMoneyById(id, money);}
}

 4.mapper,这里是自定义sql拼接的地方

java">@Update("UPDATE user SET balance = balance - #{money} WHERE id = #{id}")
void deductMoneyById(@Param("id") Long id, @Param("money") Integer money);
4)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;
}

我们有两种方法去实现这个功能

1.LambdaQueryWrapper

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

2.lambdaQuery

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();// 2.查询用户List<User> users = userService.lambdaQuery().like(username != null, User::getUsername, username).eq(status != null, User::getStatus, status).ge(minBalance != null, User::getBalance, minBalance).le(maxBalance != null, User::getBalance, maxBalance).list();// 3.处理voreturn BeanUtil.copyToList(users, UserVO.class);
}

我只能说,这个简单的有些过分了,大家可以自己看一下

7.代码生成

这部分学到了一个代码生成器的使用

我是不怎么喜欢用这个,大家想用的话可以用用

8.静态工具

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

那么问题来了,我们为什么要用它,这里我给出一个解释,因为懒,不想多次注入多个service,同时循环依赖

那我们来用一下吧,改造根据id用户查询的接口,查询用户的同时返回用户收货地址列表

1.controller

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

2.service 

java">package com.itheima.mp.service;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);
}
java">@Override
public UserVO queryUserAndAddressById(Long userId) {// 1.查询用户User user = getById(userId);if (user == null) {return null;}// 2.查询收货地址List<Address> addresses = Db.lambdaQuery(Address.class).eq(Address::getUserId, userId).list();// 3.处理voUserVO userVO = BeanUtil.copyProperties(user, UserVO.class);userVO.setAddresses(BeanUtil.copyToList(addresses, AddressVO.class));return userVO;
}

其实很多时候什么代码放在controller什么代码放在service都是主观感觉,我就得就是三部分代码能完成的就不用service,只需要定义,数据库,返回三部分,每一部分一句代码,当然是个人感觉

这里有要注意的一点

使用Db的方法时,需要多加一个Address.class,得让他知道你对应的实体类是谁

9.逻辑删除

先给大家说一下什么是逻辑删除以及如何实现逻辑删除

为什么要逻辑删除

比如你在淘宝的消费记录你删除了,那么你就看不到了,但是这个数据还得给商家看等等,所以不能真正的删除,他只是你看不到了

如何逻辑删除

对应其实现,只是在你的数据库中加了一个is_deleted字段,不删除为0,删除就为1

对于mybatis-plus很简单,只需要在application.yml中配置逻辑删除字段

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

之后执行删除操作时,会修改底层代码为逻辑删除

注:只有MybatisPlus生成的SQL语句才支持自动的逻辑删除,自定义SQL需要自己手动处理逻辑删除。

10.通用枚举

这里给大家将一下为何要使用枚举

比如用户的账号状态,有正常冻结两种,但是我们为了代码的可维护性,要在数据库存0,1,但是你又希望在数据的传输和查看过程中,一直是正常和冻结,这时就要使用枚举了

1.首先,我们要定义一个枚举类

java">package com.itheima.mp.enums;import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;@Getter
public enum UserStatus {NORMAL(1, "正常"),FREEZE(2, "冻结");private final int value;private final String desc;UserStatus(int value, String desc) {this.value = value;this.desc = desc;}
}

2.然后把User类中的status字段改为UserStatus 类型

3.在application.yaml文件中添加配置

java">mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

4.两个注解

MybatisPlus提供了@EnumValue注解来标记枚举属性

不传输json格式时会传输枚举的名字

在UserStatus枚举中通过@JsonValue注解标记JSON序列化时展示的字段

传输json类型时会传输枚举的值

11.JSON类型处理器

如果我们有个数据库的字段里面存储的时json类型的字符串时就会出现一种问题

需要在写入数据库时手动转为String,再读取数据库时,手动转换为对象,这会非常麻烦。

所以mybatis-plus提供了一种非常方便的工具JacksonTypeHandler处理器

下面教大家如何去使用它

比如现在有一个字段info,它存储的内容是这样的

java">package com.itheima.mp.domain.po;import lombok.Data;@Data
public class UserInfo {private Integer age;private String intro;private String gender;
}

那么,我们需要在它对应的实体类里面加入如下注解

这样便可以自动执行数据的转换了

12.配置加密

用不到,嘿嘿,不写了

13.分页插件

这里直接展示成品

1.首先配置一下分页插件

java">@Configuration
public class MybatisConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//      1.创建分页插件PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
//      2.分页查询上限paginationInnerInterceptor.setMaxLimit(1000L);interceptor.addInnerInterceptor(paginationInnerInterceptor);return interceptor;}
}

2.整几个分页需要的类

1)PageDTO<T>

java">package com.itheima.mp.domain.dto;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.vo.UserVO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.Collections;
import java.util.List;@Data
@ApiModel("分页结果")
public class PageDTO<T> {@ApiModelProperty("总条数")private Integer total;@ApiModelProperty("总页数")private Integer pages;@ApiModelProperty("结果")private List<T> list;public static <PO,VO> PageDTO<VO> of(Page<PO> p,Class<VO> clazz){PageDTO<VO> dto = new PageDTO<>();dto.setTotal((int) p.getTotal());dto.setPages((int) p.getPages());List<PO> records=p.getRecords();if(CollUtil.isEmpty(records)){dto.setList(Collections.emptyList());return dto;}dto.setList(BeanUtil.copyToList(records,clazz));return dto;}}

2)PageQuery 

java">package com.itheima.mp.domain.query;import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.mp.domain.po.User;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
@ApiModel(description = "分页查询条件实体")
public class PageQuery {@ApiModelProperty("页码")private Integer pageNo=1;@ApiModelProperty("每页数量")private Integer pageSize=5;@ApiModelProperty("排序字段")private String orderBy;@ApiModelProperty("是否升序")private Boolean isAsc=true;public <T> Page<T> toMpPage(OrderItem ... items) {Page<T> page=Page.of(pageNo,pageSize);if(StrUtil.isNotBlank(orderBy)) {page.addOrder(new OrderItem(orderBy, isAsc));}else if(items!=null){page.addOrder(items);}return page;}public <T> Page<T> toMpPage(String defaultSortBy ,Boolean defaultAsc) {return toMpPage(new OrderItem(defaultSortBy,defaultAsc));}public <T> Page<T> toMpPageDefaultSortByCreateTime(OrderItem ... items) {return toMpPage(new OrderItem("create_time",false));}public <T> Page<T> toMpPageDefaultSortByUpdateTime(OrderItem ... items) {return toMpPage(new OrderItem("update_time",false));}}

3)直接使用

java">   @Overridepublic PageDTO<UserVO> queryUsersPage(UserQuery query) {String name=query.getName();Integer status=query.getStatus();
//        1.构建查询条件Page<User> page =query.toMpPageDefaultSortByUpdateTime();
//        2.分页查询Page<User> p=lambdaQuery().like(name!=null,User::getUsername,name).eq(status!=null,User::getStatus,status).page(page);
//        3.封装vo结果return PageDTO.of(p,UserVO.class);}

三、结语

丸辣,怎么天就黑了了,本来还打算吧Docker学了的

能学完就把博客发出来吧,我尽量

不知道下一篇文章是

五天SpringCloud计划——DAY1之Docker的使用

还是

五天SpringCloud计划——DAY2之Docker的使用


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

相关文章

[debug]不同的window连接ubuntu的vscode后无法正常加载kernel

不同的window连接ubuntu后vscode后无法正常加载kernel 进入conda环境重新安装kernel&#xff1a; pip uninstall ipython jupyter ipykernel pip install ipython jupyter ipykernel -i https://pypi.tuna.tsinghua.edu.cn/simple

uniapp+vue2重新进入小程序就清除缓存,设备需要重新扫码

代码 app.vue页面 <script>export default {onLaunch: function() {uni.removeStorageSync(equiId)}} </script>

裸金属服务器能够帮助企业解决哪些问题?

随着网络科技的快速发展&#xff0c;企业业务也在不断的进行扩张和复杂化&#xff0c;传统的服务已经无法满足企业对于高性能和高稳定性的需求&#xff0c;而裸金属服务器则能够帮助企业来解决这一问题&#xff0c;下面我们就来具体看一下吧&#xff01; 裸金属服务器能够允许应…

python VS c++

一、语法特点 Python&#xff1a; 语法简洁、优雅&#xff0c;代码可读性极强&#xff0c;采用缩进来表示代码块&#xff0c;摒弃了像 C 那样使用大括号的传统方式&#xff0c;使得代码看上去十分清晰简洁。例如&#xff1a; ​ if 5 > 3:print("5大于3") elif 5 …

HarmonyOS NEXT应用元服务开发Intents Kit(意图框架服务)习惯推荐方案开发者测试

意图框架向开发者提供真机测试能力&#xff0c;即开发者可连接设备进行调测。开发者完成代码开发之后&#xff0c;功能正式上架应用市场前&#xff0c;可以在HarmonyOS NEXT设备上面进行自验证&#xff0c;打磨体验。真机测试分为三个步骤&#xff1a;基础信息提供&#xff0c;…

vim 一次注释多行 的几种方法

在 Vim 中一次注释多行是一个常见操作。可以使用以下方法根据你的具体需求选择合适的方式&#xff1a; 方法 1&#xff1a;手动插入注释符 进入正常模式&#xff1a; 按 Esc 确保进入正常模式。 选择需要注释的多行&#xff1a; 移动到第一行&#xff0c;按下 Ctrlv 进入可视块…

springboot集成shiro和前后端分离配置

一&#xff0c;springboot集成shiro 1&#xff0c;导入依赖 <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.4.0</version></dependency>2&#xff0c;Real…

react项目初始化配置步骤

1.npx create-react-app 项目名称 vue项目同理 2.去编辑器市场安装所需插件&#xff0c;例如ESlint以及Prettier-Code formatter formatiing-toggle 3.在项目中安装 ESLint 和 Prettier 及相关插件&#xff1a; 3.1&#xff1a; npm install --save-dev eslint prettier 3.2…