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

自己做的网站打开超慢/b2b免费发布平台

自己做的网站打开超慢,b2b免费发布平台,西宁市网站建设公司推荐,做网站被网监叫去很多次文章目录 MyBatisPlus 快速入门第一步:引入 MyBaitsPlus 起步依赖第二步:自定义的 Mapper 继承 BaseMapper 接口新增相关修改相关删除相关查询相关 Mp 使用示例 MyBaitsPlus 常见注解MP 实体类与数据库信息约定Mp 实体类与数据库信息约定不符合解决方法…

文章目录

  • ` MyBatisPlus` 快速入门
    • 第一步:引入 `MyBaitsPlus` 起步依赖
    • 第二步:自定义的 `Mapper` 继承 `BaseMapper` 接口
      • 新增相关
      • 修改相关
      • 删除相关
      • 查询相关
    • `Mp` 使用示例
  • `MyBaitsPlus` 常见注解
    • `MP` 实体类与数据库信息约定
    • `Mp` 实体类与数据库信息约定不符合解决方法
    • `MP` 自定义常见配置
  • `MyBatisPlus` 条件构造器
    • `AbstractWrapper` 公共方法
      • 比较条件
      • 模糊查询
      • 范围条件
      • 逻辑条件
      • 注意事项
      • 高级特性
    • `QueryWrapper` 特有方法
    • **`UpdateWrapper`** 特有方法
    • `LambdaWrapper` 示例
  • `MyBatisPlus` 自定义 `SQL`
  • `MyBatisPlus` 的 `IService` 接口
    • `IService` 接口使用
      • 第一步:`Service` 接口实现 `IService<T>`
      • 第二步:`Service` 实现类继承 `ServiceImpl<M extends BaseMapper<T>, T>`
      • 第三步:编写 `SQL`
    • `IService` 开发基础业务接口
      • `UserController` 层
      • `USerService` 接口
      • `UserService` 实现类
      • `UserMapper` 层
    • `IService` 的 `Lambda` 查询与更改
      • **常用条件方法**
      • `Iservice` 中的 `LambdaQuery`
      • `Iservice` 中的 `LambdaUpdate`
      • `IService` 批量新增
        • 普通 `for` 方案
        • `Mp` 批量处理方案
        • `Mp` 批量处理配合 `rewriteBatchedStatements=true`
    • 新增数据
    • 删除数据
    • 修改数据
    • 查询数据
    • 统计与分页
    • 链式操作(高级)
  • `MyBatisPlus` 拓展功能
    • `MP` 代码生成器
      • 安装插件
      • 使用
    • `Mp` 静态工具
      • 示例一
      • 示例二
    • `MP` 逻辑删除
    • `Mp` 枚举处理器
    • `Mp` 的 `Json` 处理器
    • `Mp` 插件功能
      • `Mp` 分页插件基本使用
      • `Mp` 通用分页查询
      • `MP` 通用分页实体改造

MyBatisPlus 快速入门

第一步:引入 MyBaitsPlus 起步依赖


在这里插入图片描述

第二步:自定义的 Mapper 继承 BaseMapper 接口


BaseMapper 接口提前定义好了一大堆增删改查的方法

注意:泛型为对应实体类

在这里插入图片描述

新增相关

  • insert (T entity)
INSERT INTO {表名} 
({字段1}, {字段2}, ...) 
VALUES (#{entity.属性1}, #{entity.属性2}, ...)

修改相关

  • updateById(T entity)
UPDATE {表名} 
SET {字段1}=#{entity.属性1}, {字段2}=#{entity.属性2}, ... 
WHERE id = #{entity.id}
  • update(T entity, Wrapper<T> wrapper)\
UPDATE {表名} 
SET {字段1}=#{entity.属性1}, {字段2}=#{entity.属性2}, ... 
WHERE {wrapper动态生成的条件}

删除相关

  • deleteById(Serializable id)
DELETE FROM {表名} WHERE id = #{id}
  • deleteByMap(Map<String, Object> map)
DELETE FROM {表名} 
WHERE {map中的键值对条件} 
-- 例如:name = 'John' AND age = 25
  • deleteBatchIds(Collection<?> ids)
DELETE FROM {表名} 
WHERE id IN (id1, id2, id3...)

查询相关

  • selectById(Serializable id)
SELECT * FROM {表名} WHERE id = #{id}
  • selectBatchIds(Collection<?> ids)
SELECT * FROM {表名} 
WHERE id IN (id1, id2, id3...)
  • selectOne(Wrapper<T> wrapper)
SELECT * FROM {表名} 
WHERE {wrapper动态生成的条件} 
LIMIT 1
  • selectList(Wrapper<T> wrapper)
SELECT * FROM {表名} 
WHERE {wrapper动态生成的条件}

Mp 使用示例

 	//增@Testvoid testInsert() {User user = new User();//user.setId(5L);user.setUsername("ErGouZi");user.setPassword("123");user.setPhone("18688990013");user.setBalance(200);user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userMapper.insert(user);}//查@Testvoid testQueryByIds() {List<User> users = userMapper.selectBatchIds(List.of(1L, 2L, 3L, 4L));users.forEach(System.out::println);}//改@Testvoid testUpdateById() {User user = new User();user.setId(5L);user.setBalance(20000);userMapper.updateById(user);}//查@Testvoid testSelectById() {User user = userMapper.selectById(5L);System.out.println("user = " + user);}   //删@Testvoid testDeleteUser() {userMapper.deleteById(5L);}  

MyBaitsPlus 常见注解

MP 实体类与数据库信息约定


在这里插入图片描述

Mp 实体类与数据库信息约定不符合解决方法


实体类表名字段和数据库约定不符

  • 加上对应的 @TableName@TableId, TbaleField

主键自增长问题

  • 没用 type 默认采用雪花算法

  • 数据库配置了 AUTO_INCREMENT,实体类必须标注 @TableId(type = IdType.AUTO)

  • 数据库未配置 AUTO_INCREMENT,可以选择 INPUT 或者 ASSIGN_ID

实体类 is 开头问题

  • 实体类 isMarried,数据库 is_Married 符合映射规则。但是 Java 中会忽略 is 所以还是需要手动加上 @TableField

字段名和数据库关键字冲突问题

  • 比如下面的 order。和数据库关键字冲突,所以笔记加上 ```飘号。

实体类有,数据库没有的字段问题

  • 使用 @TableField(exist = false)

在这里插入图片描述

MP 自定义常见配置


全局 id 配置配了,我们字段可以不用配置 type = ....

图中除了 type-aliases-package 其他都是默认值

MyBatisPlus 条件构造器

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

 @Testvoid testQueryWrapper() {// 1.构建查询条件QueryWrapper<User> warpper = new QueryWrapper<User>().select("id", "username", "info", "balance").like("username", "o").ge("balance", 1000);// 2.查询userMapper.selectList(warpper);}

AbstractWrapper 公共方法

比较条件


  • eq(R column, Object val)column = val
  • ne(R column, Object val)column ≠ val
  • gt(R column, Object val)column > val
  • ge(R column, Object val)column ≥ val
  • lt(R column, Object val)column < val
  • le(R column, Object val)column ≤ val

模糊查询

  • like(R column, Object val)column LIKE '%val%'
  • notLike(R column, Object val)column NOT LIKE '%val%'
  • likeLeft(R column, Object val)column LIKE '%val(左模糊)
  • likeRight(R column, Object val)column LIKE 'val%'(右模糊)

范围条件

  • between(R column, Object val1, Object val2)BETWEEN val1 AND val2
  • notBetween(R column, Object val1, Object val2)NOT BETWEEN
  • in(R column, Object... values)in(...)

逻辑条件

  • and()AND 连接多个条件
  • or()OR 连接多个条件
  • nested() → 嵌套条件

注意事项

  1. 链式调用:通过 . 连接多个条件(默认 AND 逻辑)
  2. 防 SQL 注入:优先使用 LambdaQueryWrapper 避免字段名硬编码
  3. 性能优化:避免在循环中频繁创建 Wrapper 对象
  4. 空值处理eq(null, val) 会忽略条件,需手动判空

高级特性

  • 实体绑定setEntity(T entity) 自动从实体类提取条件
  • 字段过滤columnsSqlInjectFilter() 防止非法字段注入
  • Lambda 支持LambdaQueryWrapper 提供类型安全的字段引用(如 User::getName

QueryWrapper 特有方法


  • select(String... columns)SELECT column1, column2(指定返回字段)

  • allEq(Map<R, V> params) → 批量等值匹配(如 column1=val1 AND column2=val2

  @Testvoid testQueryWrapper() {// 1.构建查询条件QueryWrapper<User> warpper = new QueryWrapper<User>().select("id", "username", "info", "balance").like("username", "o").ge("balance", 1000);// 2.查询List<User> users = userMapper.selectList(warpper);users.forEach(System.out::println);}
 @Testvoid testUpdateByQueryWrapper2() {// 1. 要更新的信息User user = new User();user.setBalance(2000);// 2. 更新的条件QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username", "jack");// 3. 执行更行int update = userMapper.update(user, wrapper);}

UpdateWrapper 特有方法


  • set(String column, Object value)SET column = value
  • setSql(String sql) → 直接拼接 SET 语句(如 SET balance = balance + 100
 @Testvoid testQueryWrapper2() {User user = new User();UpdateWrapper<User> wrapper = new UpdateWrapper<User>().set("balance", 2000).eq("username", "jack");int update = userMapper.update(user, wrapper);}
 @Testvoid testUpdateWrapper() {User user = new User();UpdateWrapper<User> wrapper = new UpdateWrapper<User>().setSql("balance = balance - 200").in("id", 1, 2, 3);userMapper.update(user, wrapper);}

LambdaWrapper 示例


在这里插入图片描述

    @Testvoid testLambdaQueryWrapper() {LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>().select(User::getId, User::getUsername, User::getInfo, User::getBalance).like(User::getUsername, "o").ge(User::getBalance, 1000);}
 .select(User::getId, User::getUsername, User::getInfo, User::getBalance) 转为常规 Lambda 底层是 Functionnew Function<Long, User>() {@Overridepublic Long apply(User user) {return user.getId()}}    .select(user -> user.getId(), user -> user.getUsername(), user -> user.getInfo(), user -> user.getBalance());

MyBatisPlus 自定义 SQL

很多公司数据库代码不能写在业务层。所以我们可以写好复杂条件,然后去数据库层拼接

在这里插入图片描述

 @Testvoid testCustomSqlUpdate() {// 1.更新条件List<Long> ids = List.of(1L, 2L, 4L);int amount = 200;// 2.定义条件QueryWrapper<User> wrapper = new QueryWrapper<User>().in("id", ids);// 3.调用自定义SQL方法userMapper.updateBalanceByIds(wrapper, amount);}
public interface UserMapper extends BaseMapper<User> {//这里条件必须叫 ewvoid updateBalanceByIds(@Param("ew") QueryWrapper<User> wrapper,@Param("amount") int amount);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mp.mapper.UserMapper"><update id="updateBalanceByIds"><!--  ${ew.customSQlSegment} 固定写法 拼接条件 这里是 in(...)--><!-- UPDATE tb_user SET balance = balance - ? WHERE (id IN (?,?,?))-->UPDATE tb_user SET balance = balance - #{amount} ${ew.customSQlSegment}</update></mapper>

MyBatisPlusIService 接口

IService 接口使用


我们自己的接口需要继承 Iservice 接口,我们自己的实现类需要继承 ServiceImpl

在这里插入图片描述

第一步:Service 接口实现 IService<T>

//IService<T> T 是实体类 entity
public interface IUserService extends IService<User> {}

第二步:Service 实现类继承 ServiceImpl<M extends BaseMapper<T>, T>

//ServiceImpl<Mapper的类型, 实体类entity>
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService{}

第三步:编写 SQL

@SpringBootTest
class IUserServiceTest {@Autowiredprivate IUserService userservice;@Testvoid testSaveUser() {User user = new User();//user.setId(5L);user.setUsername("LiLei");user.setPassword("123");user.setPhone("18688990013");user.setBalance(200);user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userservice.save(user);}@Testvoid testQuery() {List<User> users = userservice.listByIds(List.of(1L, 2L, 4L));users.forEach(System.out::println);}}

IService 开发基础业务接口


在这里插入图片描述

UserController

@Api(tags  = "用户管理接口")
@RequestMapping("/users")
@RestController
//对一开始需要初始化的变量去做构造函数。配合注解
@RequiredArgsConstructor
public class UserController {//final 必须要初始化。这里建议在构造函数初始化, 自动注入private final IUserService userService;@ApiOperation("新增用户接口")@PostMappingpublic void saveUser(@RequestBody UserFormDTO userDTO) {// 1. 把DTO拷贝到PO 从哪里拷贝到哪里User user = BeanUtil.copyProperties(userDTO, User.class);// 2. 新增userService.save(user);}@ApiOperation("根据id删除用户接口")@DeleteMapping("{id}")public void deleteUserById(@ApiParam("用户id") @PathVariable("id") Integer id) {userService.removeById(id);}@ApiOperation("根据id查询用户接口")@GetMapping("{id}")public UserVO queryUserById(@ApiParam("用户id") @PathVariable("id") Integer id) {// 1. 查询用户 POUser user = userService.getById(id);// 2. 把 PO 拷贝到 VOreturn BeanUtil.copyProperties(user, UserVO.class);}@ApiOperation("根据id批量查询用户接口")@GetMappingpublic List<UserVO> queryUserById(@ApiParam("用户id的集合") @RequestParam("ids") List<Long> ids) {// 1. 查询用户 POList<User> users = userService.listByIds(ids);// 2. 把 PO 拷贝到 VO// 把原始list 里面的对象拷贝到新的list 里面 转为别的类型return BeanUtil.copyToList(users, UserVO.class);}@ApiOperation("扣减用户余额接口")@DeleteMapping("{id}/deduction/{money}")public void deductBalance(@ApiParam("用户id") @PathVariable("id") Integer id,@ApiParam("扣减的金额") @PathVariable("money") Integer money) {userService.deductMoneyById(id, money);}
}

USerService 接口

public interface IUserService extends IService<User> {/*** 扣减用户余额* @param id* @param money*/void deductMoneyById(Integer id, Integer money);
}

UserService 实现类

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService{/*** 扣减用户余额* @param id* @param money*/@Overridepublic void deductMoneyById(Integer 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("余额不足");}// Service 实现类可直接用 baseMapper 调用 Mapper 方法,无需手动注入。 因为 extends ServiceImpl// 4.扣减余额 update tb_user set balance = balance - ? where id = ?baseMapper.deductBalanceById(id, money);}}

UserMapper

public interface UserMapper extends BaseMapper<User> {@Update("update tb_user set balance = balance - #{money} where id = #{id}")void deductBalanceById(@Param("id") Integer id, @Param("money") Integer money);
}

IServiceLambda 查询与更改


常用条件方法

方法SQL 等价说明示例
eq()column = value等于.eq(User::getStatus, 1)
ne()column <> value不等于.ne(User::getRole, "admin")
gt()column > value大于.gt(User::getAge, 18)
ge()column >= value大于等于.ge(User::getScore, 60)
lt()column < value小于.lt(User::getBalance, 1000)
le()column <= value小于等于.le(User::getBalance, maxBalance)
like()column LIKE '%value%'模糊匹配.like(User::getName, "Tom")
between()column BETWEEN min AND max范围查询.between(User::getAge, 20, 30)
in()column IN (v1, v2...)包含在集合中.in(User::getId, idsList)

Iservice 中的 LambdaQuery

动态查询

在这里插入图片描述

  • 原始 MyBatis

在这里插入图片描述

  • MyBaitsPlus 改造
//就是动态SQL
@Overridepublic List<User> queryUsers(String name, Integer status, Integer minBalance, Integer maxBalance) {List<User> users = lambdaQuery().like(name != null, User::getUsername, name)//第一个参数条件,第二个参数要查询的字段 username,第三个参数要传进来匹配的值 username 的值			.like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status).between(minBalance != null && maxBalance != null, // 强制参数共存User::getBalance, minBalance, maxBalance)		.list();//- .one():最多1个结果//- .list():返回集合结果//- .count():返回计数结果return users;}

Iservice 中的 LambdaUpdate

在这里插入图片描述

  • 传统 xml
<update id="updateUserBalanceAndStatus">UPDATE tb_user<set>balance = #{remainBalance},<if test="remainBalance == 0">status = 2,</if></set>WHEREid = #{id}AND balance = #{user.balance} <!-- 乐观锁:基于旧值校验 -->
</update>
  • LambdaUpdate 改造
   	@Override@Transactionalpublic void deductMoneyById(Integer 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("余额不足");}// Service 实现类可直接用 baseMapper 调用 Mapper 方法,无需手动注入。 因为 extends ServiceImpl// 4.扣减余额 update tb_user set balance = balance - ? where id = ?int remainBalance = user.getBalance() - money;lambdaUpdate().set(User::getBalance, remainBalance).set(remainBalance == 0, User::getStatus, 2).eq(User::getId, id).eq(User::getBalance, user.getBalance()) //乐观锁 用户的 balance = 查到的 balance 乐观锁校验.update();}

IService 批量新增

在这里插入图片描述

普通 for 方案

这种方案会发起 10000 次网络请求,mysql 内部有执行 10000 次查询。效率最低,不推荐

    @Testprivate User buildUser(int i) {User user = new User();user.setUsername("user_" + i);user.setPassword("123");user.setPhone("" + (186889900L + i));user.setBalance(2000);user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());return user;}@Testvoid testSaveOneByOne() {long b = System.currentTimeMillis();for (int i = 0; i < 1000; i++) {userservice.save(buildUser(i));}long e = System.currentTimeMillis();System.out.println("耗时:" + (e - b));}
Mp 批量处理方案

这里我们每1000 条数据就发送一次网络请求过去。然后 MySQL 再逐条执行。效率还是差一点

  @Testprivate User buildUser(int i) {User user = new User();user.setUsername("user_" + i);user.setPassword("123");user.setPhone("" + (186889900L + i));user.setBalance(2000);user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());return user;}@Testvoid testSaveOneByOne() {long b = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {userservice.save(buildUser(i));}long e = System.currentTimeMillis();System.out.println("耗时:" + (e - b));}@Testvoid testSaveBatch() {// 我们每次批量插入 1000 条数据, 插入 100此机 10万条数据List<User> list = new ArrayList<>(1000);long b = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {// 2.添加一个 userlist.add(buildUser(i));// 3.每1000条批量插入一次 1000条数据之后打包到  mysql 。也就是 1000条数据只用一次网络请求if (i % 1000 == 0) {userservice.saveBatch(list);// 4.清空集合 准备下一批数据list.clear();}}long e = System.currentTimeMillis();System.out.println("耗时:" + (e - b));}
Mp 批量处理配合 rewriteBatchedStatements=true

这里我们每1000 条数据就发送一次网络请求过去。然后将多态 SQL 合并未一条 MySQL 只执行一次。效率最高

INSERT INTO user ( username, password, phone, info, balance, create_time, update_time )
VALUES 
(user_1, 123, 18688190001, "", 2000, 2023-07-01, 2023-07-01),
(user_2, 123, 18688190002, "", 2000, 2023-07-01, 2023-07-01),
(user_3, 123, 18688190003, "", 2000, 2023-07-01, 2023-07-01),
(user_4, 123, 18688190004, "", 2000, 2023-07-01, 2023-07-01);
  • 配置文件 yaml
//配置rewriteBatchedStatements=true
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=truedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: Ting123321
  • 代码
  @Testprivate User buildUser(int i) {User user = new User();user.setUsername("user_" + i);user.setPassword("123");user.setPhone("" + (186889900L + i));user.setBalance(2000);user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());return user;}@Testvoid testSaveOneByOne() {long b = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {userservice.save(buildUser(i));}long e = System.currentTimeMillis();System.out.println("耗时:" + (e - b));}@Testvoid testSaveBatch() {// 我们每次批量插入 1000 条数据, 插入 100此机 10万条数据List<User> list = new ArrayList<>(1000);long b = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {// 2.添加一个 userlist.add(buildUser(i));// 3.每1000条批量插入一次 1000条数据之后打包到  mysql 。也就是 1000条数据只用一次网络请求if (i % 1000 == 0) {userservice.saveBatch(list);// 4.清空集合 准备下一批数据list.clear();}}long e = System.currentTimeMillis();System.out.println("耗时:" + (e - b));}

新增数据


  • save(T): 新增单条数据 → 返回操作是否成功 (boolean)
  • saveBatch(Collection<T>): 批量新增 → 返回是否成功
  • saveBatch(Collection<T>, int batchSize): 指定批次大小的批量新增

删除数据


  • removeById(Serializable id): 根据 ID 删除单条数据
  • removeByMap(Map条件): 根据 Map 条件删除
  • removeByIds(Collection<?> ids): 批量删除(根据 ID 集合)
  • removeBatchByIds(Collection<?>, int batchSize): 指定批次大小的批量删除

修改数据


  • updateById(T): 根据 ID 修改单条数据 → 返回是否成功
  • saveOrUpdate(T): 存在则更新,否则新增(单条)
  • saveOrUpdateBatch(Collection<T>): 批量新增或更新

查询数据


  • getById(Serializable id): 根据 ID 查询单条 → 返回实体 (T)
  • getOne(Wrapper<T>条件): 根据条件查询单条 → 返回实体
  • listByIds(Collection<?> ids): 根据 ID 集合批量查询 → 返回列表 (List<T>)
  • listByMap(Map条件): 根据 Map 条件查询 → 返回列表

统计与分页


  • count(): 统计总数据量 → 返回 long
  • count(Wrapper<T>条件): 根据条件统计 → 返回 long
  • page(): 分页查询(需配合分页参数使用)

链式操作(高级)


  • lambdaQuery(): 链式 Lambda 条件查询(如 lambdaQuery().eq(...).list()
  • lambdaUpdate(): 链式 Lambda 条件更新(如 lambdaUpdate().set(...).eq(...)

MyBatisPlus 拓展功能

MP 代码生成器


在使用MybatisPlus以后,基础的MapperServicePO代码相对固定,重复编写也比较麻烦。因此MybatisPlus官方提供了代码生成器根据数据库表结构生成POMapperService等相关代码。只不过代码生成器同样要编码使用,也很麻烦。

在这里插入图片描述

安装插件

在这里插入图片描述

使用

  • 首先需要配置配置数据库地址

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

  • 然后选择 Code Generator,填写信息

在这里插入图片描述

在这里插入图片描述

Mp 静态工具


在这里插入图片描述

示例一

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

  • 收货地址 VO
@Data
@ApiModel(description = "收货地址VO")
public class AddressVO{@ApiModelProperty("id")private Long id;@ApiModelProperty("用户ID")private Long userId;@ApiModelProperty("省")private String province;@ApiModelProperty("市")private String city;@ApiModelProperty("县/区")private String town;@ApiModelProperty("手机")private String mobile;@ApiModelProperty("详细地址")private String street;@ApiModelProperty("联系人")private String contact;@ApiModelProperty("是否是默认 1默认 0否")private Boolean isDefault;@ApiModelProperty("备注")private String notes;
}
  • 用户 VO
    • 注意添加一个地址属性 List<AddressVO> addresses
@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
    @ApiOperation("根据id查询用户接口")@GetMapping("{id}")public UserVO queryUserById(@ApiParam("用户id") @PathVariable("id") Integer id) {return userService.queryUserAndAddressById(id);}
  • UserServiceImpl
    @Overridepublic UserVO queryUserAndAddressById(Integer id) {// 1.查询用户User user = getById(id);if (user == null || user.getStatus() == 2) {throw new RuntimeException("用户状态异常!");}// 2.查询地址List<Address> addresses = Db.lambdaQuery(Address.class).eq(Address::getUserId, id).list();// 3.封装 VO// 3.1.转User的PO为VOUserVO userVO = BeanUtil.copyProperties(user, UserVO.class);// 3.2.转地址VOif(CollUtil.isNotEmpty(addresses)) {List<AddressVO> addressVos = BeanUtil.copyToList(addresses, AddressVO.class);userVO.setAddresses(addressVos);}return userVO;}

示例二

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

  • 收货地址 VO
@Data
@ApiModel(description = "收货地址VO")
public class AddressVO{@ApiModelProperty("id")private Long id;@ApiModelProperty("用户ID")private Long userId;@ApiModelProperty("省")private String province;@ApiModelProperty("市")private String city;@ApiModelProperty("县/区")private String town;@ApiModelProperty("手机")private String mobile;@ApiModelProperty("详细地址")private String street;@ApiModelProperty("联系人")private String contact;@ApiModelProperty("是否是默认 1默认 0否")private Boolean isDefault;@ApiModelProperty("备注")private String notes;
}
  • 用户 VO
    • 注意添加一个地址属性 List<AddressVO> addresses
@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
    @ApiOperation("根据id查询用户接口")@GetMapping("{id}")public UserVO queryUserById(@ApiParam("用户id") @PathVariable("id") Integer id) {return userService.queryUserAndAddressById(id);}
  • UserServiceImpl
    @Overridepublic List<UserVO> queryUserAndAddressByIds(List<Long> ids) {// 1.查询用户List<User> users = listByIds(ids);if(CollUtil.isEmpty(users)) {return Collections.emptyList();}// 2.查询地址// 2.1.获取用户id集合List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());// 2.2.根据用户id查询地址List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();// 2.3.转换地址VOList<AddressVO> addressVOList = BeanUtil.copyToList(addresses, AddressVO.class);// 2.4.梳理地址集合, 分类整理, 相同用户的放入一个集合中Map<Long, List<AddressVO>> addressMap = new HashMap<>(0);if (CollUtil.isNotEmpty(addressVOList)) {addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));}// 3.转换VO返回List<UserVO> list = new ArrayList<>(users.size());for (User user : users) {// 3.1.转User的PO为VOUserVO vo = BeanUtil.copyProperties(user, UserVO.class);list.add(vo);// 3.2.转换Address的PO为VOvo.setAddresses(addressMap.get(user.getId()));}return list;}

MP 逻辑删除


或者直接在字段上面标注 @TableLogic 注解

在这里插入图片描述

在这里插入图片描述

  • 配置逻辑删除字段
mybatis-plus:mapper-locations: classpath*:mapper/*.xmlglobal-config:db-config:id-type: autologic-delete-field: deleted #配置逻辑删除字段
  • 正常操作就进行逻辑删除

@SpringBootTest
class IAddressServiceTest {@Autowiredprivate IAddressService addressService;@Testvoid testLogicDelete() {// 1. 删除addressService.removeById(59L);// 2. 查询Address adress = addressService.getById(59L);System.out.println("address = " + adress);}
}

在这里插入图片描述

Mp 枚举处理器


status这种字段我们一般会定义一个枚举,做业务判断的时候就可以直接基于枚举做比较。但是我们数据库采用的是int类型,对应的PO也是Integer。因此业务操作时必须手动把枚举Integer转换,非常麻烦。因此,MybatisPlus提供了一个处理枚举的类型转换器,可以帮我们把枚举类型与数据库类型自动转换。@EnumValue 表示把哪个字段往数据库写

在这里插入图片描述

  • 定义枚举类
@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;}
}
  • 修改 User POJO 枚举字段为枚举类型
@Data
@ApiModel(description = "用户VO实体")
public class UserVO {@ApiModelProperty("用户id")private Long id;@ApiModelProperty("用户名")private String username;@ApiModelProperty("详细信息")private String info;//这里改为枚举类型@ApiModelProperty("使用状态(1正常 2冻结)")private UserStatus status;@ApiModelProperty("账户余额")private Integer balance;@ApiModelProperty("用户的收获地址")private List<AddressVO> addresses;
}
  • 枚举类中用 EnumValue 标记哪个字段的值作为数据库的值
public enum UserStatus {NORMAL(1, "正常"),FROZEN(2, "异常");@EnumValueprivate final int value;private final String desc;UserStatus(int value, String desc) {this.value = value;this.desc = desc;}
}
  • 配置枚举处理器
mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
  • 枚举类用 @JsonValue 标记 JSON 序列化时展示的字段
    • 如果没标记默认用枚举值
public enum UserStatus {NORMAL(1, "正常"),FROZEN(2, "异常");@EnumValueprivate final int value;@JsonValueprivate final String desc;UserStatus(int value, String desc) {this.value = value;this.desc = desc;}
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

MpJson 处理器


我们数据库User表中有一个 info 字段,是 JSON 类型吗,而对应 User 实体类的字段确实 String 类型,这样一来 info 属性要转来转去很麻烦。所以可以用 Mp 中的 JacksonTypeHandler 处理器自动处理

在这里插入图片描述

  • 定义一个单独的实体类和 Info 字段匹配
@Data
@NoArgsConstructor
//生成一个静态工厂方法调用全参构造
@AllArgsConstructor(staticName = "of")
public class UserInfo {private Integer age;private String intro;private String gender;
}
  • User 实体类修改字段类型为 UserInfo 类型,并声明类型处理器,同时声明自动映射
@Data
//声明自动映射
@TableName(value = "tb_user", autoResultMap = true)
public class User {/*** 用户id*/@TableId(type = IdType.AUTO)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;
}
  • 测试
    @Testvoid testInsert() {User user = new User();//user.setId(5L);user.setUsername("ErGouZi");user.setPassword("123");user.setPhone("18688990013");user.setBalance(200);//这里正常插入数据就行,自动转为 JSON 类型user.setInfo(UserInfo.of(24, "英文老师", "female"));user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userMapper.insert(user);}

Mp 插件功能


Mp 分页插件基本使用

  • 新建配置类,配置分页插件
@Configuration
public class MyBatisConfig {@Beanpublic MybatisPlusInterceptor myPlusInterceptor() {// 初始化核心插件MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 1.创建分页插件PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);// 1.1配置分页上限paginationInnerInterceptor.setMaxLimit(1000L);// 2.添加分页插件interceptor.addInnerInterceptor(paginationInnerInterceptor);//如果要添加其他插件,就先创建出来然后add进去就行return interceptor;}
}
  • 开始分页查询
   @Testvoid testPageQuery() {int pageNo = 1, pageSize = 2;// 1.准备分页条件Page<User> page = Page.of(pageNo, pageSize);// 1.1. 添加排序条件:按照 balance 升序排序,相同再按照 id 升序排序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);long pages = p.getPages();System.out.println("总页数:" + pages);List<User> records = p.getRecords();records.forEach(System.out::println);}

Mp 通用分页查询

  • UserQuery:分页查询条件的实体,包含分页、排序参数、过滤条件
  • PageDTO:分页结果实体,包含总条数、总页数、当前页数据
  • UserVO:用户页面视图实体
  • 创建 PageQuery 分页条件类,并让 UserQuery 继承
    • pageNo:页码
    • pageSize:每页数据条数
    • sortBy:排序字段
    • isAsc:是否升序

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

@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {@ApiModelProperty("页码")private Long pageNo;@ApiModelProperty("页码")private Long pageSize;@ApiModelProperty("排序字段")private String sortBy;@ApiModelProperty("是否升序")private Boolean isAsc;
}
@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;
}
  • UserVO
@Data
@ApiModel(description = "用户VO实体")
public class UserVO {@ApiModelProperty("用户id")private Long id;@ApiModelProperty("用户名")private String username;@ApiModelProperty("详细信息")private UserInfo info;@ApiModelProperty("使用状态(1正常 2冻结)")private UserStatus status;@ApiModelProperty("账户余额")private Integer balance;@ApiModelProperty("用户的收获地址")private List<AddressVO> addresses;
}
  • 分页实体 PageDTO
@Data
@ApiModel(description = "分页结果")
public class PageDTO<T> {@ApiModelProperty("总条数")private Long total;@ApiModelProperty("总页数")private Long pages;@ApiModelProperty("集合")private List<T> list;
}
  • Controller
 @ApiOperation("根据复杂条件分页查询接口")@GetMapping("/page")public PageDTO<UserVO> queryUsersPage(UserQuery query) {return userService.queryUserPage(query);}
  • UserServiceImpl
  /*** 根据复杂条件分页查询接口* @param query* @return*/@Overridepublic PageDTO<UserVO> queryUserPage(UserQuery query) {String name = query.getName();Integer status = query.getStatus();// 1.构建查询条件// 1.1.分页条件Page<User> page = Page.of(query.getPageNum(), query.getPageSize());if (StrUtil.isNotBlank(query.getSortBy())) {//不为空page.addOrder(new OrderItem(query.getSortBy(), query.getIsAsc()));} else {//为空, 默认按照更新时间排序page.addOrder(new OrderItem("update_time", false));}// 2.分页查询lambdaQuery().like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status).page(page);// 3.封装VO结果PageDTO<UserVO> dto = new PageDTO<>();// 3.1. 设置总条数dto.setTotal(page.getTotal());// 3.2. 设置总页数dto.setPages(page.getPages());// 3.3. 设置当前页数据List<User> records = page.getRecords();if (CollUtil.isEmpty(records)) {dto.setList(Collections.emptyList());return dto;}// 3.4 拷贝 user 的VOList<UserVO> vos = BeanUtil.copyToList(records, UserVO.class);dto.setList(vos);// 4.返回return dto;}

MP 通用分页实体改造

  • PageQuery
@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {@ApiModelProperty("页码")private Integer pageNum = 1;@ApiModelProperty("每页条数")private Integer pageSize = 5;@ApiModelProperty("排序字段")private String sortBy;@ApiModelProperty("是否升序")private Boolean isAsc = true;public <T> Page<T> toMpPage(OrderItem ... items) {// 1.分页条件Page<T> page = Page.of(pageNum, pageSize);// 2.排序条件if (StrUtil.isNotBlank(sortBy)) {//不为空page.addOrder(new OrderItem(sortBy, isAsc));} else if(items != null){//为空, 默认按照更新时间排序page.addOrder(items);}return page;}public <T> Page<T> toMoPage(String defaultSortBy, Boolean defaultAsc) {return toMpPage(new OrderItem("create_time", defaultAsc));}public <T> Page<T> toMoPageDefaultSortByCreateTime() {return toMpPage(new OrderItem("create_time", false));}public <T> Page<T> toMoPageDefaultSortByUpdateTime() {return toMpPage(new OrderItem("update_time", false));}}
  • PageDTO
@Data
@ApiModel(description = "分页结果")
public class PageDTO<T> {@ApiModelProperty("总条数")private Long total;@ApiModelProperty("总页数")private Long pages;@ApiModelProperty("集合")private List<T> list;public static <PO, VO> PageDTO<VO> of(Page<PO> p, Function<PO, VO> convertor) {PageDTO<VO> dto = new PageDTO<>();// 3.1. 设置总条数dto.setTotal(p.getTotal());// 3.2. 设置总页数dto.setPages(p.getPages());// 3.3. 设置当前页数据List<PO> records = p.getRecords();if (CollUtil.isEmpty(records)) {dto.setList(Collections.emptyList());return dto;}// 4 拷贝 user 的VOdto.setList(records.stream().map(convertor).collect(Collectors.toList()));// 4.返回return dto;}}
  • UserServiceImpl
  @Overridepublic PageDTO<UserVO> queryUserPage(UserQuery query) {String name = query.getName();Integer status = query.getStatus();// 1.构建查询条件Page<User> page = query.toMoPageDefaultSortByUpdateTime();// 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, user -> {// 1.拷贝基础属性UserVO vo = BeanUtil.copyProperties(user, UserVO.class);// 2.处理特殊逻辑vo.setUsername(user.getUsername().substring(0, vo.getUsername().length() -2) + "**");return vo;});}
http://www.whsansanxincailiao.cn/news/30237924.html

相关文章:

  • 怎么理解网站开发/考研培训班集训营
  • 网站如何添加qq客服/办公软件速成培训班
  • 注册过域名后怎么建设网站/爱站seo工具包官网
  • 东莞三合一网站制作/如何在百度上发表文章
  • 天津做网站排名/培训学校资质办理条件
  • 山西省建设厅政务中心网站/网络营销的策略包括
  • 网站搭建哪家公司最好/网店推广策划书
  • 企业营销型网站建设公司/网站免费网站免费优化优化
  • 做企业网站要怎么设计方案/杭州网站设计
  • 企业门户网站建设情况/线上销售平台有哪些
  • 平面设计资料网站/结构优化设计
  • 做适合漫画网站的图片/网络服务商主要包括哪些
  • asp.net做的网站要放到网上空间去要放哪些文件上去/英文外链平台
  • 智能网站推广软件/seo排名点击器曝光行者seo
  • 90设计网站官网首页/企业网站定制
  • 点击图片是网站怎么做/雷神代刷推广网站
  • 开源 网站开发框架/无锡百度推广代理公司
  • 监控网站建设需要多少钱/站长统计app软件下载官网安卓
  • 涂料网站模版/跨境电商平台有哪些
  • 炒股网站怎么做/seo关键词排名注册价格
  • 套图吧wordpress/常州seo外包
  • 人人建站网/如何自己建个网站
  • 网站建设租用服务器/seo基础理论
  • 供应网站建设公司评价/微信朋友圈推广文案
  • 两学一做网站专栏/域名服务器ip地址查询
  • 17一起做网站普宁站/好看的网页设计作品
  • wordpress做淘宝客网站/百度关键词如何优化
  • 链接转换器/全网搜索引擎优化
  • 网站建设中排名掉了/临沂网站建设方案服务
  • cms开源网站管理系统/汕头seo不错