一.微服务入门
1.认识

二.MyBatisPlus
1.入门
1.案例

以下是mybaits的写法:

现在需要修改为mybatisplus。
步骤:


修改详细步骤:

2.注意BaseMapper泛型为实体类的类型:
随后进行单元测试:
原来的mybatis:

mybaits的单元测试:

mybaitplus:

发现mybatsplus的单元测试:

直接调用了父basemapper里面的方法,增删改查并不需要自己写。
较为复杂的也能生成:

2.常见注解
mp通过扫描实体类并基于反射获取实体类信息作为数据库表信息。

如果不一样或者是自己想要修改,即违背约定,则需要使用注解:
主键名不一致,即不叫id但是与id差不多用处,需要加上注解:

普遍字段信息有一个需要注意的点,即字段名中第一个为is,类型为布尔值。如isMarried,他是布尔值,这种字段会将is去掉在做为变量名,所以一定需要加上注解。


3.常见配置

配置的话直接去官网查阅。选择配置:

或者是idea自动提示:

2.核心功能
1.条件构造器

基于queryWrapper的查询:

以上是手写的sql语句,如果使用mp:

将查询条件写在service中:

如果是特殊的更新,比如:

写法:使用setSql进行手写sql语句:

lambdaWrapper也差不多,但为什么要用lambda:
减少硬编码。
最大区别就是将函数,或者说字段写进去而不是直接写个"id"什么的写死:

2.自定义sql

案例:完全手写sql

mp:


其实就是mp很擅长进行where查询的部分,<foreach>这一步直接使用in来代替。而sql语句前半部分则不一定。大多数场景mp都能完成,但少部分比如在原有值的基础上进行操作,即动态:
实现需要三步:



3.service接口


详细:


会报错,因为我们不想实现所有方法而是直接使用:

案例

简单业务:
全部代码-只需在controller就能完成,前提是不是复杂业务:
@Api("用户管理接口")
@RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserController {
//注入service
private final IUserService userService;
@PostMapping
@ApiOperation("新增用户接口")
public void saveUser(@RequestBody UserFormDTO userFormDTO){
//1.将dto拷贝成po
User user = BeanUtil.copyProperties(userFormDTO, User.class);
//2.新增
userService.save(user);
}
@ApiOperation("删除用户接口")
@DeleteMapping("{id}")
public void DeleteUserById(@ApiParam("用户id") @PathVariable("id") Long id){
userService.removeById(id);
}
@ApiOperation("查询用户接口")
@GetMapping("{id}")
public UserVO queryUserById(@ApiParam("用户id") @PathVariable("id") Long id){
//查询用户po
User user = userService.getById(id);
//将po拷贝到vo
return BeanUtil.copyProperties(user,UserVO.class);
}
@ApiOperation("批量查询用户接口")
@GetMapping("{id}")
public List<UserVO> queryUserByIds(@ApiParam("用户id") @RequestParam("ids") List<Long> ids){
//查询用户po
List<User> users = userService.listByIds(ids);
//将po拷贝到vo
return BeanUtil.copyToList(users,UserVO.class);
}
复杂业务:
@ApiOperation("扣减用户余额")
@PutMapping("/{id}/deduction/{money}")
public void deleteMoneyById(@PathVariable("id") Long id,
@PathVariable("money") Integer money){
userService.deductBaalance(id,money);
}
impl:
@Override
public void deductBaalance(Long id, Integer money) {
//1.查询用户,根据id查询,方法就在service,不用注入,或者注入mapper,即basemapper.方法名
User user = this.getById(id);
//2。校验用户状态
if (user==null||user.getStatus()==2){
throw new RuntimeException("异常");
}
//3.检验余额充足
if (user.getBalance()<money){
throw new RuntimeException("余额不足");
}
//4.扣减
baseMapper.debuctBalance(id,money);
}
mapper:
@Update("UPDATE user SET balance = balance-#{money} where id = #{id}")
void debuctBalance(@Param("id") Long id,@Param("money") Integer money);
4.Lambda查询

@ApiOperation("批量复杂查询用户接口")
@GetMapping("list")
public List<UserVO> queryusersds(UserQuery userQuery){
//查询用户po
List<User> users = userService.queryusers(userQuery.getName(),userQuery.getStatus(),userQuery.getMinBalance(),userQuery.getMaxBalance());
//将po拷贝到vo
return BeanUtil.copyToList(users,UserVO.class);
}
impl:
@Override
public List<User> queryusers(String name, Integer status, Integer minBalance, Integer maxBalance) {
List<User> list = lambdaQuery()
.like(name != null, User::getUsername, name)
.eq(status != null, User::getUsername, name)
.gt(minBalance != null, User::getUsername, name)
.lt(maxBalance != null, User::getUsername, name)
.list();
return list;
}

like,eq,lt,gt代表着不同的条件,模糊查询大于小于等于等等等等。
最后.list是查询多个目标,单个目标写.on。分页.page。计数.count。


5.批量新增

3.扩展功能
1.代码开发
正常来说代码开发需要准备实体类,加上注解后再写对应的mapper,然后是service接口,最后写实现类。

其实大部分代码是固定的,只有类变化其他跟着变。那么其实可以根据表的信息来自动生成一些代码。这就是代码生成:

步骤:引入api依赖
写生成代码的代码
如果不想这样,毕竟太麻烦了。可以使用从mybatisx,是一款idea的插件。
或者是使用另外一款插件:mybatisplus

步骤:
下载完插件后会出现一个选项:

点击codegenerator并进行配置:

2.静态工具

方法名和iservice差不多,但是实现方式略有不同。(静态和非静态)
iservice是非静态的,所以我们需要自定义接口并且继承,指定泛型类型为实体类类型。
但是静态工具,由于静态方法是无法读取到泛型的,这就导致无法知道实体类。所以方法都需要传递一个额外的参数,必须传递class字节码。只有save和update不需要。
但是为什么要用静态工具呢?看案例:

根据需求发现,需求1想要完成需要在userservice中注入addressservice,而需求3则是需要在addresservice中注入userservice,这就出现循环依赖的情况,为了解决就可以使用静态工具。
Db选择这个包:

controller,需求1:

impl:
//静态方法
@Override
public UserVO queryUserAndAddressById(Long id) {
//1.查询用户
User user = getById(id);
if (user ==null||user.getStatus()==2){
throw new RuntimeException("异常");
}
//2.查询地址,这是一个复杂查询,两种方法:注入service以及静态方法Db
List<Address> addresses = Db.lambdaQuery(Address.class)
.eq(Address::getUserId, id).list();
//3.封装vo
//先将userpo为vo
UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
//if判断中是工具包自带的判断方法
if (CollUtil.isEmpty(addresses)){
List<AddressVO> addressVOS = BeanUtil.copyToList(addresses, AddressVO.class);
userVO.setAddress(addressVOS);
}
return userVO;
}
需要注意的是po转换成vo,而将address转成vo则是因为uservo中是addressvo的集合。
if判断中是工具包自带的判断方法 if (CollUtil.isEmpty(addresses
批量查询:
需要注意的是,即使我们查到的是ids,但是最好根据用户id查询用户地址之前先再获取id集合,因为传入的ids中可能不存在某个id

如何将相同用户的地址放在同一个集合,可以用for循环,可以用stream流:

groupingBy(要分的类,根据什么分),Map<Long,List<AddressVo>>这个long就是map的key,即用户的id


此处用in而不是eq的原因就是查出来的id不止一个

3.逻辑删除

所以逻辑删除sql字段应该为update:

而且不需要我们自己手动修改:


可以使用,但是逻辑删除本身也有缺点:

4.枚举处理器

这样虽然方便,但是有一个问题:在数据库中status还是int类型,而po为枚举类型,假如做操作,在status写什么呢,不可能写nomarl。而我们在进行查询的时候,会查询到status为数字,转成po用的却是枚举类型,数字怎么进行转换?
底层的自动转换都是mybatis:

而mp进行了扩展,有了很多类型的枚举处理器:

如何使用:
1.配置:

2.在枚举类使用注解标记:@EnumValue 来通知哪个是对应的

po:

impl:

vo:

经过测试,状态返回值显示normal:

那么能不能让返回值显示数字或者中文?
可以,这个与返回值有关。枚举默认在返回时以英文名(枚举项)进行返回。
如果想改变,就需要告诉程序,程序往前端进行返回是spring mvc处理,而springmvc处理底层是使用一个包,想要修改就是用注解来进行:@TsonValue
5.json处理器
解决json数据类型与java数据类型转换

JSON类型就是在进行数据库查询时,mysql提供的一些特殊的查询语法,本质就是一个字符串。
比如说此处info,在代码中
为string类型,不需要进行操作。
但是如果真正处理业务可能会比较麻烦,比如从数据库查询出来后取出里面的信息就不能取了,需要转换格式。
为了方便,可以定义一个新的实体,与info完全一致,如图:

然后就可以使用userinfo代替string类型:

只能自己自定义处理器进行转换:

只能使用注解:

4.插件功能

分页插件
配置:

想要添加其他插件只需要在
如图位置继续添加即可。
然后使用分页API。


示例:


true为升序,balance为金额,是字段
通用分页实体


先单独定义一个pagequery

如果其他query想要使用,直接继承pagequery,然后拓展也没问题。
然后就是返回值结果,一共有三个属性需求,并且定义为dto,因为其他组件也可能使用:

一定要加上泛型<T>来告诉类型是不确定的。
实现层:


、
但其实这样还是有点麻烦的,因为有两个地方:
1.拿去query对象构建分页条件时,需要把分页条件封装成page对象,然后再去做查询。封装过程太过麻烦,直接封装成工具类更为方便。
2.进行分页查询时进行返回值解析比较麻烦,也应该进行封装。



dto:
