怎么建设在线视频网站,wordpress添加左侧菜单,重新建设网站,在eclipse中做网站开发快速入门
简介
在项目开发中#xff0c;Mybatis已经为我们简化了代码编写。
但是我们仍需要编写很多单表CURD语句#xff0c;MybatisPlus可以进一步简化Mybatis。
MybatisPlus官方文档#xff1a;https://www.baomidou.com/#xff0c;感谢苞米豆和黑马程序员。
Mybat…快速入门
简介
在项目开发中Mybatis已经为我们简化了代码编写。
但是我们仍需要编写很多单表CURD语句MybatisPlus可以进一步简化Mybatis。
MybatisPlus官方文档https://www.baomidou.com/感谢苞米豆和黑马程序员。
MybatisPlus无侵入的提供了代码生成、自动分页、逻辑删除、自动填充等功能。
需要注意MybatisPlus提高了单表查询开发效率复杂的多表查询还需要结合Mybatis配置文件使用。
引入依赖
MybatisPlus提供了starter包含Mybatis以及MybatisPlus的相关依赖
dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.5.3.1/version
/dependency定义Mapper
为了简化单表CURDMybatisPlus提供了BaseMapper接口。
BaseMapper实现了单表CURD我们定义的Mapper接口只需要继承它
package com.test.mp.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.mp.domain.po.User;public interface UserMapper extends BaseMapperUser {
}这样对于单表简单的CURD我们不再需要编写SQL语句。 原理
MybatisPlus是如何判断我们查询的表和字段名呢
MybatisPlus通过扫描实体类基于反射获取实体类信息作为数据库表信息。
在定义Mapper继承BaseMapperUser时我们指定了泛型User。
这个泛型就是数据库对应的POJOMybatisPlus就是根据这个泛型进行推断生成SQL
把POJO的类名驼峰转下划线作为表名把POJO所有变量名驼峰转下划线作为字段名并根据变量类型推断字段类型把名为id的字段作为主键
常用注解
TableName
如果POJO类名不符合约定与表明不一致。
可以使用TableName注解指定表名。
例如POJO类名为UserMapper实际的数据库表名为tb_user
package com.test.mp.domain.po;import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.time.LocalDateTime;Data
TableName(tb_user)
public class User {private Long id;private String username;private String password;private String phone;private String info;private Integer status;private Integer balance;private LocalDateTime createTime;private LocalDateTime updateTime;
}TableId
如果POJO类里没有名为id的成员变量或者主键不是id。
可以使用TableId注解指定主键成员变量它有2个属性
value数据库主键字段名成员变量名和数据库字段名不一致时使用type主键的策略默认为雪花算法常用IdType.NONE
其中常用的type有如下三种
AUTO数据库自增长即AUTO_INCREMENT。INPUT通过set方法自行输入。ASSIGN_ID分配ID接口identifierGenerator的方法nextId来生成id默认实现类为DefaultIdentifierGenerator雪花算法。
通常情况下我们按照MybatisPlus规范定义POJO和数据库字段因此只需要指定TableId(typeIdType.AUTO)
例如
package com.test.mp.domain.po;import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;import java.time.LocalDateTime;Data
TableName(tb_user)
public class User {TableId(valueuid, typeIdType.AUTO)private Long uid;private String username;private String password;private String phone;private String info;private Integer status;private Integer balance;private LocalDateTime createTime;private LocalDateTime updateTime;
}TableField
和TableId的用途一样只不过不指定主键。只指定成员变量和数据库字段名对应关系。
除此之外有3种特殊情况也需要用到TableField注解
成员变量是Boolean类型且以is开头如isMarried。MybatisPlus通过反射获取成员变量名时会去掉is得到Married。成员变量名和sql关键字冲突如order。成员变量不是数据库字段。
因此一般不建议成员变量使用is开头或与sql关键字冲突。如果非要这么使用需要用TableField注解指定和数据库字段的映射关系。
例如
package com.itheima.mp.domain.po;import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;import java.time.LocalDateTime;Data
public class User {private Long id;private String username;private String password;TableField(is_married)private boolean isMarried;TableField(order)private Integer orderr;TableField(existfalse)private Integer notInTable;
}常见配置
MybatisPlus的配置项继承了Mybatis原生配置并在此基础上新增自己的配置。如
mybatis-plus:type-aliases-package: com.test.mp.domain.pojo # 别名扫描包mapper-locations: classpath*:/mapper/**/*.xml # Mapper.xml文件地址默认值configuration:map-underscore-to-camel-case: true # 是否开启下划线和驼峰的映射cache-enabled: false # 是否开启二级缓存global-config:db-config:id-type: assign_id # id为雪花算法生成update-strategy: not_null # 更新策略只更新非空字段核心功能
MybatisPlus为我们提供的CURD是根据id为条件的如果我们需要复杂条件的CURD需要用到一些核心功能。
条件构造器
在MybatisPlus提供的BaseMapper接口按ctrlf12发现很多方法的参数有Wrapper类型 选中代码中的Wrapper类名按ctrlh显示所有子类右击Wrapper选择Diagrams - Show Diagrams Popup。
然后右击Wrapper选择Show Implementations查看继承关系图这些Wrapper就是条件构造器 QueryWrapper
QueryWrapper常用于构建select、delete、update的where条件部分。
我们以QueryWrapper为例查询名字中带o的且存款大于等于1000元的用户的id、username、info和balance字段
SELECT id, username, info, balance From user WHERE username LIKE ? AND balance ?;Test
void testQueryWrapper() {// 1.构建查询条件QueryWrapperUser wrapper new QueryWrapperUser().select(id, username, info, balance).like(username, o).ge(balance, 1000);// 2.查询ListUser users userMapper.selectList(wrapper);users.forEach(System.out::println);
}再展示另外一个例子更新用户名为jack的用户的余额为2000
UPDATE user SET balance 2000 WHERE (username jack);Test
void testUpdateByQueryWrapper() {// 1.要更新的数据User user new User();user.setBalance(2000);// 2.更新的条件QueryWrapperUser wrapper new QueryWrapperUser().eq(username, jack);// 3.执行更新userMapper.update(user, wrapper);
}UpdateWrapper
UpdateWrapper通常只有在set语句比较特殊才使用。
我们以UpdateWrapper为例更新id为1, 2, 4的用户的余额扣200。
UPDATE user SET balance balance - 200 WHERE id in (1, 2, 4);Test
void testUpdateByWrapper() {// 1. 要更新的id集合ListLong ids List.of(1L, 2L, 4L);// 2. 设置set语句并构建更新条件UpdateWrapperUser wrapper new UpdateWrapperUser().setSql(balance balance -200).in(id, ids);// 3. 更新userMapper.update(null, wrapper);
}LambdaWrapper
LambdaWrapper包括LambdaQueryWrapper和LambdaUpdateWrapper。
我们以LambdaQueryWrapper为例前面使用QueryWrapper时我们使用了字符串硬编码。
为了避免硬编码MybatisPlus推荐使用LambdaQueryWrapper通过lambda方法引用来调用
Test
void testLambdaQueryWrapper() {// 1.构建查询条件LambdaQueryWrapperUser wrapper new LambdaQueryWrapperUser().select(User::getId, User::getUsername, User::getInfo, User::getBalance).like(User::getUsername, o).ge(User::getBalance, 1000);// 2.查询ListUser users userMapper.selectList(wrapper);users.forEach(System.out::println);
}自定义SQL
在前面的UpdateWrapper中我们将set更新的sql语句写在了业务层代码中不符合实际开发低耦合的规范。
比较常见的用法是用MybatisPlus的Wrapper来构建复杂的Where条件然后自己定义SQL语句中剩下的部分。
对于多表操作也可以用这种方法构建Where条件然后编写剩余部分的SQL语句
例如我们将id在指定范围内的用户的余额扣减指定值 基于Wrapper构建where条件 Test
void testCustomSqlUpdate() {// 1.更新条件ListLong ids List.of(1L, 2L, 4L);int amount 200;// 2.定义条件LambdaQueryWrapperUser wrapper new LambdaQueryWrapperUser().in(User::getId, ids);// 3.调用自定义SQL方法userMapper.updateBanlanceByIds(wrapper, amount);
}在mapper方法参数中用Param注解声明wrapper变量名称必须是ew // 注解声明的Wrapper的变量名称必须是ew也可以使用常量值Constants.WRAPPER
public interface UserMapper extends BaseMapperUser {void updateBanlanceByIds(Param(Constants.WRAPPER) LambdaQueryWrapperUser wrapper, Param(amount) int amount);
}自定义SQL并使用传递下来的Wrapper条件 update idupdateBanlanceByIdsUPDATE user SET balance balance - #{amount} ${ew.customSqlSegment}
/updateService接口
原理
MybatisPlus已经帮我们简化了单表CURD操作但我们还需要写Service层代码。
为了进一步简化MybatisPlus为我们提供了IService接口这个接口提供了简单CURD的Service抽象方法。
我们定义的UserService接口可以继承IServiceIService包含简单CURD的抽象方法。但是会出现一个问题。
IService接口非常多UserServiceImpl在实现接口时需要实现全部方法如下图所示 为了解决这个问题MybatisPlus又为我们提供了ServiceImpl实现Iservice所有的抽象方法我们的UserServiceImpl只需要继承它即可 基本用法
下面通过一个例子来演示IService 定义IUserService接口继承IService接口并指定泛型为POJO类 package com.test.mp.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.test.mp.domain.po.User;public interface IUserService extends IServiceUser {
}定义IUserServiceImpl类实现IUserService接口然后继承ServiceImpl类并指定Mapper和POJO的泛型 package com.test.mp.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.test.mp.domain.po.User;
import com.test.mp.mapper.UserMapper;
import com.test.mp.service.IUserService;
import org.springframework.stereotype.Service;Service
public class UserServiceImpl extends ServiceImplUserMapper, User implements IUserService {
}测试简单CURD无需编写Service和Mapper代码 SpringBootTest
class IUserServiceTest {Autowiredprivate IUserService userService;Testvoid testSaveUser() {User user new User();user.setUsername(Test);user.setPassword(123456);user.setPhone(18888888888);user.setBalance(200);user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userService.save(user);}Testvoid testQuery() {ListUser users userService.listByIds(List.of(1L, 2L, 4L));users.forEach(System.out::println);}
}基础用法
下面以一个案例来演示MybatisPlus的强大的功能实现对用户表的新增、删除、查询。 为了方便接口调试我们引入Swagger相关依赖 !--swagger--
dependencygroupIdcom.github.xiaoymin/groupIdartifactIdknife4j-openapi2-spring-boot-starter/artifactIdversion4.1.0/version
/dependency
!--web--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependency然后在Controller编写对于简单的增、删、查IService已经为我们封装好了相关方法。 我们不需要再编写Service和Mapper代码就可以实现这些功能 Api(tags 用户管理接口)
RequestMapping(/users)
RestController
RequiredArgsConstructor
public class UserController {// RequiredArgsConstructor注解通过构造函数给userService赋值private final IUserService userService;ApiOperation(新增用户接口)PostMappingpublic void saveUser(RequestBody UserFormDTO userDTO) {User user BeanUtil.copyProperties(userDTO, User.class);userService.save(user);}ApiOperation(删除用户接口)DeleteMapping(/{id})public void deleteUser(ApiParam(用户id) PathVariable(id) Long id) {userService.removeById(id);}ApiOperation(根据id查询用户接口)GetMapping(/{id})public UserVO queryUserById(ApiParam(用户id) PathVariable(id) Long id) {User user userService.getById(id);return BeanUtil.copyProperties(user, UserVO.class);}ApiOperation(根据id批量查询用户接口)GetMappingpublic ListUserVO queryUserByIds(ApiParam(用户id) RequestParam(ids) ListLong ids) {ListUser users userService.listByIds(ids);return BeanUtil.copyToList(users, UserVO.class);}
}自定义用法
对于一些比较复杂的查询还需要我们自定义Service和Mapper代码。
以这样一个案例为例扣减用户余额。 由于不是常规查询因此我们在Controller编写代码调用自定义的Service方法。 Api(tags 用户管理接口)
RequestMapping(/users)
RestController
RequiredArgsConstructor
public class UserController {// RequiredArgsConstructor注解通过构造函数给userService赋值private final IUserService userService;ApiOperation(扣减用户余额接口)GetMapping(/{id}/deduction/{money})public void deductMoneyById(ApiParam(用户id) PathVariable(id) Long id,ApiParam(扣减的金额) PathVariable(money) Integer money) {userService.deductBalance(id, money);}
}然后在ServiceImpl实现自定义的方法。首先判断是否合法然后调用Mapper中自定义的方法 Service
public class UserServiceImpl extends ServiceImplUserMapper, User implements IUserService {Overridepublic void deductBalance(Long id, Integer money) {User user getById(id);if (user null || user.getStatus() 2) {throw new RuntimeException(用户状态异常);}if (user.getBalance() money) {throw new RuntimeException(用户余额不足);}baseMapper.deductBalance(id, money);}
}然后在Mapper中定义SQL语句复杂的可以使用Wrapper简单的可以使用注解或xml public interface UserMapper extends BaseMapperUser {Update(UPDATE user SET balance balance - #{money} WHERE id #{id})void deductBalance(Param(id) Long id, Param(money) Integer money);
}Lambda查询
对于条件查询以往我们需要写xml判断某个参数是否为空。MybatisPlus也为我们提供了简便用法Lambda以省略mapper编写。
现在我们以这样一个案例为例根据name、status、minBalance、maxBalance模糊查询用户。 在Controller编写代码调用Service层自定义方法 Api(tags 用户管理接口)
RequestMapping(/users)
RestController
RequiredArgsConstructor
public class UserController {private final IUserService userService;ApiOperation(根据复杂条件查询用户接口)GetMapping(/list)public ListUserVO queryUsers(UserQuery query) {ListUser users userService.queryUsers(query.getName(), query.getStatus(), query.getMinBalance(), query.getMaxBalance());return BeanUtil.copyToList(users, UserVO.class);}
}在ServiceImpl定义方法可以通过查询方法的链式调用进行查询。 对于like、eq、gt、lt等方法如果传入三个参数第一个参数为condition。 最后通过one、list、page、count等方法获取查询结果。 Service
public class UserServiceImpl extends ServiceImplUserMapper, User implements IUserService {Overridepublic ListUser queryUsers(String name, Integer status, Integer minBalance, Integer maxBalance) {return lambdaQuery().like(name ! null, User::getUsername, name).eq(status ! null, User::getStatus, status).gt(minBalance ! null, User::getBalance, minBalance).lt(maxBalance ! null, User::getBalance, maxBalance).list();}
}Lambda更新
我们以这样一个需求为例根据id扣减用户余额完成对用户状态、余额校验。如果扣减后余额为0修改status为2。
前面我们已经完成了deductBalance业务流程现在我们只需要修改service层对mapper调用为lambda即可。无需再写mapper代码。
Service
public class UserServiceImpl extends ServiceImplUserMapper, User implements IUserService {Overridepublic void deductBalance(Long id, Integer money) {User user getById(id);if (user null || user.getStatus() 2) {throw new RuntimeException(用户状态异常);}if (user.getBalance() money) {throw new RuntimeException(用户余额不足);}int remainBalance user.getBalance() - money;lambdaUpdate().set(User::getBalance, remainBalance).set(remainBalance 0, User::getStatus, 2).eq(User::getId, id).update();}
}但是这里还存在一个问题如果有多个线程执行这个方法。如ThreadA(扣100)、ThreadB扣100。
若同时执行到remainBalance最终得到的remainBlance相同。最终两个线程只有一个生效。
因此这里需要加线程锁。可以是乐观锁也可以是悲观锁。
我们这里采用乐观锁先比较再更新在执行update前先使用.eq(User::getBalance, user.getBalance())判断。
如果条件不成立说明已经有其它线程对Balance进行修改。当前update就失败了。
Service
Transactional
public class UserServiceImpl extends ServiceImplUserMapper, User implements IUserService {Overridepublic void deductBalance(Long id, Integer money) {User user getById(id);if (user null || user.getStatus() 2) {throw new RuntimeException(用户状态异常);}if (user.getBalance() money) {throw new RuntimeException(用户余额不足);}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()).update();}
}拓展功能
代码生成
前面我们根据数据库表定义POJO、Mapper接口、Service接口、ServiceImpl和Controller。
对于不同的数据库表定义的模板文件是相同的区别就在于POJO字段名和文件的接口名及类名。
MybatisPlus为我们提供了代码生成器可以根据数据库表一键生成这些文件 安装MyabtisPlus插件 然后打开菜单栏-Other-Config Database配置数据库信息 jdbc:mysql://127.0.0.1:3306/mp?useUnicodetruecharacterEncodingUTF-8autoReconnecttrueserverTimezoneAsia/Shanghai然后再次打开菜单栏-Other-Code Generator 点击右下角code generatro即可生成相应的文件
静态工具
IService接口提供的方法都是非静态方法不同Service之间相互调用可能会导致循环依赖。
MybatisPlus为我们提供了DB静态工具其中的方法为静态方法避免了循环依赖问题DB调用时需要传入Class参数。
第一个案例根据id查询用户并查询用户的所有地址。
Override
public UserVO queryUserAndAddressById(Long id) {User user getById(id);if (user null || user.getStatus() 2) {throw new RuntimeException(用户状态异常);}ListAddress addresses Db.lambdaQuery(Address.class).eq(Address::getUserId, id).list();UserVO userVO BeanUtil.copyProperties(user, UserVO.class);if (CollUtil.isNotEmpty(addresses)) {userVO.setAddresses(BeanUtil.copyToList(addresses, AddressVO.class));}return userVO;
}第二个案例批量查询用户并查询用户的所有地址。
Override
public ListUserVO queryUserAndAddressByIds(ListLong ids) {// 根据id查询userListUser users listByIds(ids);if (CollUtil.isEmpty(users)) {return Collections.emptyList();}// 获取用户id集合ListLong userIds users.stream().map(User::getId).collect(Collectors.toList());// 根据id查询地址ListAddress addresses Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();// 转换地址为VOListAddressVO addressVOList BeanUtil.copyToList(addresses, AddressVO.class);// 分类整理地址集合相同用户的放入一个集合MapLong, ListAddressVO addressMap new HashMap(0);if (CollUtil.isNotEmpty(addressVOList)) {addressMap addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));}// 转换VO返回ListUserVO list new ArrayList(users.size());for (User user : users) {UserVO userVO BeanUtil.copyProperties(user, UserVO.class);list.add(userVO);userVO.setAddresses(addressMap.get(user.getId()));}return list;
}逻辑删除
日常生活中我们在网站上执行删除操作实际上是软删除。只是在数据库中将数据标记为删除并不是真正的从数据库中删除。
具体实现方法是在表中添加一个字段标记数据是否被删除当删除数据时把标记置为1查询时只查询标记为0的数据。
例如逻辑删除字段为deleted
查询操作
SELECT * FROM user WHERE deleted 0;删除操作
UPDATE user SET deleted 1 WHERE id 1 AND deleted 0;MybatisPlus提供了逻辑删除功能无需改变方法调用方式而是在底层帮我们自动修改CURD语句。
我们需要做的就是在application.yaml文件中配置逻辑删除的字段名称和值即可。
mybatis-plus:global-config:db-config:logic-delete-field: deleted # 全局逻辑删除的实体字段名字段类型可以是boolean、integerlogic-delete-value: 1 # 逻辑删除值默认为1logic-not-delete-value: 0 # 逻辑未删除值默认为0枚举处理器
如果POJO类中有一个枚举类型的成员变量如
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;}
}Data
public class User {TableId(type IdType.AUTO)private Long id;private String username;private String password;private String phone;private String info;private Integer status;private Integer balance;private UserStatus status;private LocalDateTime createTime;private LocalDateTime updateTime;
}对于status成员变量数据库字段的类型是INTPOJO的类型的enum。
Mybatis有一个TypeHandler接口它可以实现数据库和Java类型的转换。但它不能将Enum类型和数据库的类型进行转换。
MybatisPlus提供了MybatisEnumTypeHandler处理器以实现Enum类型和数据库类的转换用法如下 在application.yml配置 mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler在enum类上加EnumValue注解 Getter
public enum UserStatus {NORMAL(1, 正常),FREEZE(2, 冻结);EnumValueprivate final int value;private final String desc;UserStatus(int value, String desc) {this.value value;this.desc desc;}
}此时再次查询会默认返回枚举项如NORMAL、FREEZE。
如果想返回value或desc可以在对应的成员变量上加JsonValue注解。
JSON处理器
数据库字段有一个冷门的类型json。在Java对应的POJO中我们一般用String成员变量映射这个字段。
Mybatis也为我们提供了自动从数据库的json转换为Java的字符串的功能。如 但是在Java中String类型不能直接访问json成员为了解决这个问题我们可以根据Json定义一个实体类 为了实现实体类和数据库json类型的转换MybatisPlus提供了一个Json类型处理器。用法如下
在对应的字段的TableFirld注解上加入typeHandler JacksonTypeHandler.class属性。 但是这样需要在所有json字段都加注解非常繁琐。我们可以采用另一种方法
在TableName注解上加入autoResultMap true属性。 插件功能
MybatisPlus提供的内置拦截器有多租户插件、动态表名插件、分页插件、乐观锁插件、SQL性能规范插件等。
比较常用的插件就是分页插件之前我们通过pageHelper实现分页下面将介绍MybatisPlus分页插件的用法。
分页插件
首先要在配置类中注册MybatisPlus的核心插件同时添加分页插件
Configuration
public class MybatisConfig {Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {// 初始化核心插件MybatisPlusInterceptor interceptor new MybatisPlusInterceptor();// 添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}然后编写分页查询代码
Test
void testPageQuery() {// 1.分页查询new Page()的两个参数分别是页码、每页大小PageUser p userService.page(new Page(2, 2));// 2.总条数System.out.println(total p.getTotal());// 3.总页数System.out.println(pages p.getPages());// 4.数据ListUser records p.getRecords();records.forEach(System.out::println);
}也支持排序
int pageNo 1, pageSize 5;
// 分页参数
PageUser page Page.of(pageNo, pageSize);
// 排序参数, 通过OrderItem来指定
page.addOrder(new OrderItem(balance, false));userService.page(page);通用分页实体
很多业务都有分页查询需求因此我们可以为分页查询定义一个通用的实体PageQuery
Data
public class PageQuery {private Integer pageNo;private Integer pageSize;private String sortBy;private Boolean isAsc;public T PageT toMpPage(OrderItem ... orders){// 1.分页条件PageT p Page.of(pageNo, pageSize);// 2.排序条件// 2.1.先看前端有没有传排序字段if (sortBy ! null) {p.addOrder(new OrderItem(sortBy, isAsc));return p;}// 2.2.再看有没有手动指定排序字段if(orders ! null){p.addOrder(orders);}return p;}public T PageT toMpPage(String defaultSortBy, boolean isAsc){return this.toMpPage(new OrderItem(defaultSortBy, isAsc));}public T PageT toMpPageDefaultSortByCreateTimeDesc() {return toMpPage(create_time, false);}public T PageT toMpPageDefaultSortByUpdateTimeDesc() {return toMpPage(update_time, false);}
}然后定义一个返回结果的通用实体PageDTO
Data
NoArgsConstructor
AllArgsConstructor
public class PageDTOV {private Long total;private Long pages;private ListV list;/*** 返回空分页结果* param p MybatisPlus的分页结果* param V 目标VO类型* param P 原始PO类型* return VO的分页对象*/public static V, P PageDTOV empty(PageP p){return new PageDTO(p.getTotal(), p.getPages(), Collections.emptyList());}/*** 将MybatisPlus分页结果转为 VO分页结果* param p MybatisPlus的分页结果* param voClass 目标VO类型的字节码* param V 目标VO类型* param P 原始PO类型* return VO的分页对象*/public static V, P PageDTOV of(PageP p, ClassV voClass) {// 1.非空校验ListP records p.getRecords();if (records null || records.size() 0) {// 无数据返回空结果return empty(p);}// 2.数据转换ListV vos BeanUtil.copyToList(records, voClass);// 3.封装返回return new PageDTO(p.getTotal(), p.getPages(), vos);}/*** 将MybatisPlus分页结果转为 VO分页结果允许用户自定义PO到VO的转换方式* param p MybatisPlus的分页结果* param convertor PO到VO的转换函数* param V 目标VO类型* param P 原始PO类型* return VO的分页对象*/public static V, P PageDTOV of(PageP p, FunctionP, V convertor) {// 1.非空校验ListP records p.getRecords();if (records null || records.size() 0) {// 无数据返回空结果return empty(p);}// 2.数据转换ListV vos records.stream().map(convertor).collect(Collectors.toList());// 3.封装返回return new PageDTO(p.getTotal(), p.getPages(), vos);}
}以后业务需要的分页查询和分页结果可以继承这两个通用实体。