五、MybatisPlus-进阶使用-Service接口(2)-自定义service

474 阅读4分钟

本文是系列文章,目录:
一、MybatisPlus-基本使用
二、MybatisPlus-进阶使用-条件构造器
三、MybatisPlus-进阶使用-自定义sql
四、MybatisPlus-进阶使用-Service接口(1)-基本使用
五、MybatisPlus-进阶使用-Service接口(2)-自定义service
六、MybatisPlus-进阶使用-Service接口(3)- 批量新增
七、MybatisPlus-进阶使用-逻辑删除
八、MybatisPlus-进阶使用-枚举处理器
九、MybatisPlus-进阶使用-JSON类型处理器
十、MybatisPlus-进阶使用-配置文件加密
十一、MybatisPlus-插件功能-分页插件(1)
十二、MybatisPlus-插件功能-分页插件(2)-通用分页封装
十三、MybatisPlus-插件功能-乐观锁插件
十四、MybatisPlus-插件功能-sql性能分析
十五、MybatisPlus-自动填充字段
MybatisPlus-问题汇总

自定义Service

上一章节中,我们的接口都是可以在controller中实现,无需编写service代码。但是对于一些业务逻辑比较复杂的接口,需要我们在service自定义实现

例如下面的需求:

  • 根据id扣减用户余额

需求分析:

  1. 判断用户状态是否正常
  2. 判断用户余额是否充足
  3. 修改用户余额

对于这个需求,我们就不能再controller层直接调用IService提供的方法来直接修改余额,应该在service层进行逻辑判断后再做修改,另外更新余额需要自定义SQL,也要在mapper中来实现。因此,我们除了要编写controller以外,具体的业务还要在service和mapper中编写。

实现步骤:

  1. userMapper.java
    添加deductMoneyById方法
@Update("UPDATE user SET balance = balance - #{money} WHERE id = #{id}")
void deductMoneyById(@Param("id") Long id, @Param("money") Integer money);
  1. UserService.java
    添加deductBalance方法
package com.pino.demo.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.pino.demo.domain.po.User;

public interface IUserService extends IService<User> {
    void deductBalance(Long id, Integer money);
}
  1. UserServiceImpl实现类
    实现deductBalance方法
package com.pino.demo.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pino.demo.domain.po.User;
import com.pino.demo.mapper.UserMapper;
import com.pino.demo.service.IUserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Override
    public 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);
    }
}
  1. UserController
@PutMapping("{id}/deduction/{money}")
@ApiOperation("扣减用户余额")
public void deductBalance(@PathVariable("id") Long id, @PathVariable("money")Integer money){
    userService.deductBalance(id, money);
}

5.swapper测试

Lambda

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

需求一:通过复杂查询条件查询用户

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

实现方式一、

  1. 定义一个查询条件实体,UserQuery实体:
package com.pino.demo.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. UserController中定义一个controller方法:
@GetMapping("/list")
@ApiOperation("根据id集合查询用户")
public List<UserVO> queryUsers(UserQuery query){
    // 1.组织条件
    String username = query.getName();
    Integer status = query.getStatus();
    Integer minBalance = query.getMinBalance();
    Integer maxBalance = query.getMaxBalance();
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    // 加入非空判断意思就是当条件成立时才会添加这个查询条件,类似Mybatis的mapper.xml文件中的<if>标签
    wrapper.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.po转换为vo
    return BeanUtil.copyToList(users, UserVO.class);
}

实现方式二、
Service中对LambdaQueryWrapperLambdaUpdateWrapper的用法进一步做了简化。我们无需自己通过new的方式来创建Wrapper,而是直接调用lambdaQuerylambdaUpdate方法:
基于Lambda查询:

@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.po转换为vo
    return BeanUtil.copyToList(users, UserVO.class);
}

lambdaQuery方法中除了可以构建条件,还需要在链式编程的最后添加一个list(),这是在告诉MP我们的调用结果需要是一个list集合。这里不仅可以用list(),可选的方法有:

  • .one():最多1个结果
  • .list():返回集合结果
  • .count():返回计数结果

MybatisPlus会根据链式编程的最后一个方法来判断最终的返回结果。

需求二:如果扣减后余额为0,则将用户status修改为冻结状态

改造根据id修改用户余额的接口,如果扣减后余额为0,则将用户status修改为冻结状态。

package com.pino.demo.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pino.demo.domain.po.User;
import com.pino.demo.mapper.UserMapper;
import com.pino.demo.service.IUserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Override
    public 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.扣减余额
       int remainBalance = user.getBalance() - money;
       lambdaUpdate()
             .set(User::getBalance, remainBalance) // 更新余额
             .set(remainBalance == 0, User::getStatus, 2) // 动态判断,是否更新status
             .eq(User::getId, id)
             .eq(User::getBalance, user.getBalance()) // 乐观锁
             .update();
    }
}