编写一个工具类, 用于将实体、集合、page的entity与vo之间的类型转换工具类。
在有使用Mybatis Plus的项目框架中,我们从库中查询出来的数据只能映射到实体类, 不能够很好的适应我们的VO对象,而且有时候分页查询时往往会涉及连表查询等等, 通常得通过写sql来得到VO类型的输出。
如果你不想写sql怎么办?只想通过调用简单快捷的Mybatis Plus的方法进行对表操作, 那么就可以使用这个工具类了。
我工作中追求的是减少复杂的开发过程, 提高开发效率,代码可复用化。
进入正题.
通常copy一个对象简单的方法是使用工具类BeanUtils.copyProperties(), 但是对于我们的集合和Page对象束手无策, 但还是先了解一下copyProperties()的使用
BeanUtils.copyProperties(source, target);
source是被复制的对象,target是被赋值的对象。即将source中的数据拷贝到target对象中, 使用前先得new一个target对象。需要注意的是,两个对象之间只有相同字段和类型的值才能被成功拷贝,否则拷贝后需对不成功的字段进行赋值
完整代码
了解了copyProperties()的使用过程, 我们就可以用它作为copy的基础来编写我们的工具类了。
先上一波完整代码,粘贴到你的util中即可, 可通过实例化工具或者直接使用静态方法两种方式调用。
ModelUtil.java
/**
* 类型转换
* entity <----> entityVO,
* List<entity> <----> List<entityVO>,
* Page<entity> <----> Page<entityVO>
* @author Huzz
* @created 2021-12-07 9:55
*/
@Component
public class ModelUtil<Source, Target> {
private static final Logger log = LoggerFactory.getLogger(ModelUtil.class);
/**
* 通过静态方法调用(单例模式)
*/
private static ModelUtil modelUtil = new ModelUtil();
public ModelUtil(){
}
/** -----------------------静态方法方式调用-------------------------------------- */
/**
* 转换为目标对象
* @param source 源对象
* @param type 目标对象类
* @return 目标对象
*/
public static Object toEntityStatic(Object source, Class<?> type){
return modelUtil.toEntity(source, type);
}
/**
* 转换为目标Page对象
* @param source 源对象
* @param type 目标类型
* @return 目标Page对象
*/
public static Page<?> toPageEntityStatic(Page<?> source, Class<?> type){
return modelUtil.toPageEntity(source, type);
}
/**
* 转换为目标List对象
* @param source 源对象
* @param type 目标类型
* @return 目标List对象
*/
public static List<?> toArrayListEntityStatic(List<?> source, Class<?> type){
return modelUtil.toArrayListEntity(source, type);
}
/** -------------------------------------------------------------------------- */
/**
* 转换为实体对象
*
* @return Target
*/
public Target toEntity(Source source, Class<Target> type) {
Target target = createInstance(type);
BeanUtils.copyProperties(source, target);
return target;
}
/**
* 实例化对象
*
* @param clazz
* @return
*/
private Target createInstance(Class<Target> clazz) {
Target target = null;
try {
target = clazz.newInstance();
} catch (InstantiationException e) {
log.info("转换为实体对象错误: 实例化{}失败", clazz);
e.getMessage();
} catch (IllegalAccessException e) {
log.info("转换为实体对象错误: 无权访问指定类{}", clazz);
e.getMessage();
}
return target;
}
/**
* Page类型entity转换
* @param source
* @param type
* @return
*/
public Page<Target> toPageEntity(Page<Source> source, Class<Target> type) {
Page<Target> target = new Page<>();
BeanUtils.copyProperties(source, target);
target.setRecords(toArrayListEntity(source.getRecords(), type));
return target;
}
/**
* List类型的数据entity转换
* @param source
* @param type
* @return
*/
private List<Target> toArrayListEntity(List<Source> source, Class<Target> type) {
List<Target> target = new ArrayList<>();
source.forEach(e -> {
Target instance = createInstance(type);
BeanUtils.copyProperties(e, instance);
target.add(instance);
});
return target;
}
}
拷贝对象
/**
* 转换为实体对象
*
* @return Target
*/
public Target toEntity(Source source, Class<Target> type) {
Target target = createInstance(type);
BeanUtils.copyProperties(source, target);
return target;
}
/**
* 实例化对象
*
* @param clazz
* @return
*/
private Target createInstance(Class<Target> clazz) {
Target target = null;
try {
target = clazz.newInstance();
} catch (InstantiationException e) {
log.info("转换为实体对象错误: 实例化{}失败", clazz);
e.getMessage();
} catch (IllegalAccessException e) {
log.info("转换为实体对象错误: 无权访问指定类{}", clazz);
e.getMessage();
}
return target;
}
将实体类转换为VO, 反过来也可以
实例化方式:
ModelUtil<User, UserVO> modelUtil = new ModelUtil<>();
UserVO vo = modelUtil.toEntity(user, userVO.class);
使用静态方法方式:
UserVO vo = ModelUtil.toEntityStatic(user, UserVO.class);
拷贝集合
/**
* List类型的数据entity转换
* @param source
* @param type
* @return
*/
private List<Target> toArrayListEntity(List<Source> source, Class<Target> type) {
List<Target> target = new ArrayList<>();
source.forEach(e -> {
Target instance = createInstance(type);
BeanUtils.copyProperties(e, instance);
target.add(instance);
});
return target;
}
在方法内,每次循环都会实例化一个目标类的对象, 并将原来集合中的一个对象拷贝给该对象,最后返回新集合,使用方式如下:
// 实例化方式
ModelUtil<User, UserVO> modelUtil = new ModelUtil<>();
List<UserVO> vo = modelUtil.toArrayListEntity(userList, UserVO.class);
// 使用静态方式
List<UserVO> vo = ModelUtil.toArrayListEntityStatic(userList, UserVO.class);
拷贝Page
/**
* Page类型entity转换
* @param source
* @param type
* @return
*/
public Page<Target> toPageEntity(Page<Source> source, Class<Target> type) {
Page<Target> target = new Page<>();
BeanUtils.copyProperties(source, target);
target.setRecords(toArrayListEntity(source.getRecords(), type));
return target;
}
Page对象的拷贝中, 由于存在某些字段的数据类型不一致, 所以拷贝完共同字段后, 需要对类型不同的字段做单独处理, 以上代码中, 只是处理了分页的数据records。records是一个集合, 我们再调用上面的拷贝集合方法即可完成处理。使用
// 实例化方式
ModelUtil<User, UserVO> modelUtil = new ModelUtil<>();
List<UserVO> vo = modelUtil.toPageEntity(userPage, UserVO.class);
// 使用静态方式
List<UserVO> vo = ModelUtil.toPageEntityStatic(userPage, UserVO.class);
END
有了这些方法后, 如果我们在用Mybatis Plus写集合查询, 但最终的返回类型还要求有其他非实体类字段,比如连表查询后再查询。 对于这种情况,如果我们不想写sql, 可以先分页查询实体类, 然后转换成voList对象; 然后查询另一张表, 将取出来的数据set到voList就好了。