MybatisPlus - 扩展功能
文章目录
- 目标:
- 1.代码生成
- 2.静态工具
- 3.逻辑删除
- 4.枚举处理器
- 5.JSON处理器
- 插件功能
目标:
- 代码生成
- 静态工具
- 逻辑删除
- 每局处理器
- JSON处理器
1.代码生成
这个自己试试叭!
2.静态工具
跟IService的很像,但是IService中的方法都是非静态的,所以我们要自定义接口并且继承它,继承它的过程中还要指定泛型,泛型就是实体类的类型,为什么要执行实体类的类型?因为要通过反射获取字节码得到表信息才能增删改查。而Db都是静态的。类上是没有泛型的或者说静态的方法是没有办法读取到泛型的,因此Db上是没有泛型的,那么如何去做增删改查呢?所以你发现它的方法都需要我们传递一个额外的参数-字节码。
查地址的时候要注入user,查user的时候要注入地址,出现了循环依赖,那么我们就可以通过这个静态工具来解决。
AddressVO
@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;
}
UserVO
@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;private List<AddressVO> addresses;
}
出现循环依赖可以使用静态工具
public UserVO queryUserAndAddressById(Long id) {//1.查询用户User user = this.getById(id);if(user==null || user.getStatus()!=1){throw new RuntimeException("用户状态异常");}//2.查询地址List<Address> addresses = Db.lambdaQuery(Address.class).eq(Address::getUserId, id).list();//3.封装返回值UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);if(addresses!=null && addresses.size()>0){userVO.setAddresses(BeanUtil.copyToList(addresses, AddressVO.class));}return userVO;}
第二题
@ApiOperation("根据id批量查询用户接口")@PostMapping("/users")public List<UserVO> queryUser(@RequestParam("ids") List<Long> ids){return userService.queryUserAndAddressByIds(ids);}
public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {//1.查询用户List<User> users = listByIds(ids);if(users==null || users.size()!=ids.size()){throw new RuntimeException("用户状态异常");}//2.查询地址//2.1 获取用户id集合List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());//2.2 查询地址List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();//2.3 转换Address的PO为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.封装返回值List<UserVO>list = new ArrayList<>(users.size());for (User user : users) {//3.1 转换User的PO为VOUserVO userVO = BeanUtil.copyProperties(user, UserVO.class);list.add(userVO);userVO.setAddresses(addressMap.get(user.getId()));}return list;}
3.逻辑删除
有一些数据是非常重要的,不能直接删除
我配完之后写了一个测试类测试一下:
@SpringBootTest
class IAddressServiceTest {@Autowiredprivate IAddressService addressService;@Testvoid testLogicDelete(){addressService.removeById(60L);Address address = addressService.getById(60L);System.out.println(address);}}
4.枚举处理器
这里我们会涉及到枚举类型跟int类型之间的转换问题,其实也不仅仅是这一个;类型,我们java中所有的数据类型都要跟数据库的类型做转换,可能我们平时都没有主动转换过,但是我们没有做过并不代表没有,我们所认为的岁月静好,只不过是有人在替我们负重前行,底层都是由mybatis
帮我们完成,mybatis
如何实现类型转换呢?
我们这里使用MybatisEnum TypeHandler,分两步使用,我们得告诉mp那个属性是对应数据库的字段,用注解@EnumValue
第二步:让它生效
记得VO也要改,但是返回就会以枚举项返回,我们的数据往前端返回是由SpringMVC处理的,SpringMVC处理JSON用的是Jackson,它提供了一个注解来表明返回枚举中那个值进行返回@JsonValue
5.JSON处理器
但是mybatis没有能力帮我们做userInfo跟JSON数据类型的转换,所以我们只能自己来
我们使用JacksonTypeHandler实现类
没有全局配置,只能一个个配.现在这里面出现了对象嵌套,User中又出现了info
往往就需要去定义resultMap,但是我们又不想定义
准备实体:
插件功能
最常见,我们一般可以用pageHelper,但是mp也提供了
这里分为两个小节
- 分页插件
- 通用分页实体
配置
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.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MyBatisConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 这里可以添加多个插件PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);paginationInnerInterceptor.setMaxLimit(1000L);interceptor.addInnerInterceptor(paginationInnerInterceptor);return interceptor;}
}
测试类:
@Testvoid testPageQuery(){int pageNo = 1;int pageSize = 2;//1.准备分页条件//1.1分页条件Page<User>page = new Page<>(pageNo, pageSize);//1.2排序条件page.addOrder(OrderItem.desc("id"));//2.执行分页查询Page<User> result = userService.page(page);//3.输出结果result.getRecords().forEach(System.out::println);System.out.println("总记录数:" + result.getTotal());System.out.println("总页数:" + result.getPages());System.out.println("当前页:" + result.getCurrent());System.out.println("是否有前一页:" + result.hasPrevious());System.out.println("是否有下一页:" + result.hasNext());}
返回值:
通用分页实体
封装一个实体:
import lombok.Data;@Data
public class PageQuery {private Integer pageNo;private Integer pageSize;private String sortBy;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;
}
定义一个统一分页结果,我们说不定以后在微服务中也会使用到所以可以定义在dto包
@Data
public class PageDTO<T> {private Long total;private Long pages;private List<T> list;
}
接口声明:
@ApiOperation("根据复杂条件分页查询用户接口")@GetMapping("/page")public PageDTO<UserVO> queryUsersPage(UserQuery query){return userService.queryUsersPage(query);}
public PageDTO<UserVO> queryUsersPage(UserQuery query) {//1.构建查询条件String name = query.getName();Integer status = query.getStatus();Page<User> page = Page.of(query.getPageNo(), query.getPageSize());if(StrUtil.isNotBlank(query.getSortBy())){page.addOrder(new OrderItem(query.getSortBy(), query.getIsAsc()));}else{//默认排序page.addOrder(new OrderItem("update_time" , false));}//2.分页查询Page<User> p = lambdaQuery().like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status).page(page);//3.转换PO为VOPageDTO<UserVO> dto = new PageDTO<>();dto.setTotal(p.getTotal());dto.setPages(p.getPages());List<User> records = p.getRecords();if(CollUtil.isEmpty(records)){dto.setList(new ArrayList<>());return dto;}//3.1 转换User的PO为VOdto.setList(BeanUtil.copyToList(records, UserVO.class));//3.2 封装地址信息//4.返回return dto;}
通用分页实体与MP转换
很多代码跟业务关系不大,比较通用
@Data
public class PageQuery {private Integer pageNo = 1;private Integer pageSize = 5;private String sortBy;private Boolean isAsc = true;public <T> Page<T> toMpPage(OrderItem ...items){Page<T> page = Page.of(pageNo, pageSize);if(StrUtil.isNotBlank(sortBy)){page.addOrder(new OrderItem(sortBy, isAsc));}else if(items!= null && items.length > 0){//默认排序page.addOrder(items);}return page;}public <T> Page<T> toMpPage(String sortBy, Boolean isAsc){return toMpPage(new OrderItem(sortBy, isAsc));}public <T> Page<T> toMpPageDefaultByCreatTime(){return toMpPage(new OrderItem("create_time",false));}public <T> Page<T> toMpPageDefaultByUpdateTime(){return toMpPage(new OrderItem("update_time",false));}
}
import java.util.ArrayList;
import java.util.List;@Data
public class PageDTO<T> {private Long total;private Long pages;private List<T> list;public static <PO,VO> PageDTO<VO> of(Page<PO> p,Class<VO> voClass){PageDTO<VO> dto = new PageDTO<>();dto.setTotal(p.getTotal());dto.setPages(p.getPages());List<PO> records = p.getRecords();if(CollUtil.isEmpty(records)){dto.setList(new ArrayList<>());return dto;}//3.1 转换User的PO为VOdto.setList(BeanUtil.copyToList(records, voClass));//3.2 封装地址信息//4.返回return dto;}
}
最终:
public PageDTO<UserVO> queryUsersPage(UserQuery query) {//1.构建查询条件String name = query.getName();Integer status = query.getStatus();Page<User> page = query.toMpPage();//2.分页查询Page<User> p = lambdaQuery().like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status).page(page);//3.转换PO为VOreturn PageDTO.of(p, UserVO.class);}
但是要记住Beanutil的使用要求User,UserVo的属性名要相同,如果不同需要自己完成转换,那能不能封装一个方法别的方法你帮我写好但是从PO到VO的转换我自己来写
public class PageDTO<T> {private Long total;private Long pages;private List<T> list;public static <PO,VO> PageDTO<VO> of(Page<PO> p, Function<PO,VO> converter){PageDTO<VO> dto = new PageDTO<>();dto.setTotal(p.getTotal());dto.setPages(p.getPages());List<PO> records = p.getRecords();if(CollUtil.isEmpty(records)){dto.setList(new ArrayList<>());return dto;}//3.1 转换User的PO为VOdto.setList(records.stream().map(converter).collect(Collectors.toList()));//3.2 封装地址信息//4.返回return dto;}
}
public PageDTO<UserVO> queryUsersPage(UserQuery query) {//1.构建查询条件String name = query.getName();Integer status = query.getStatus();Page<User> page = query.toMpPage();//2.分页查询Page<User> p = lambdaQuery().like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status).page(page);//3.转换PO为VOreturn PageDTO.of(p, user->{//1.拷贝基础属性UserVO vo = BeanUtil.copyProperties(user, UserVO.class);//2.处理特殊逻辑vo.setUsername(vo.getUsername().substring(0,vo.getUsername().length()-2)+"**");return vo;});}
完结啦~~