java对象转换工具

工具类相关代码

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface JoinProperty {
    /**
     * 用VO哪个字段查
     */
    String source();

    /**
     * 目标表对应的实体
     */
    Class joinEntity();

    /**
     * 目标查询字段,默认会取id字段
     * @return
     */
    String on() default "";

    /**
     * 取目标表的哪个字段,默认取VO上当前注解的字段名
     */
    String select() default "";

    /**
     * 默认值
     * @return
     */
    String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";

}
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Mapping {
    /**
     * 实体源字段,用于转VO
     * @return
     */
    String source() default "";

    /**
     * 实体目标字段,用于DTO转到实体
     * @return
     */
    String target() default "";
}
@UtilityClass
public class BeanCopyUtils {
    public String[] getNullPropertyNames(Object source) {
       final BeanWrapper src = new BeanWrapperImpl(source);
       java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

       Set<String> emptyNames = new HashSet<String>();
       for (java.beans.PropertyDescriptor pd : pds) {
          Object srcValue = src.getPropertyValue(pd.getName());
          if (srcValue == null) {
             emptyNames.add(pd.getName());
          }
       }
       String[] result = new String[emptyNames.size()];
       return emptyNames.toArray(result);
    }

    /**
     * 拷贝对象属性并忽略null的属性
     * @param src
     * @param target
     */
    public void copyProperties(Object src, Object target) {
       if(src == null) {
          return;
       }
       BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
    }

    /**
     * 将list中的对象替换成vo对象
     * @param list
     * @param clazz
     * @return
     */
    @SneakyThrows
    public <T>List<T> replaceWithVO(List list, Class clazz) {
       if(list!=null&&list.size()>0){
          List newList=new ArrayList(list.size());
          for (Object o : list) {
             Object newObject=clazz.newInstance();
             copyProperties(o,newObject);
             newList.add(newObject);
          }
          process(list,newList, clazz);
          for(int i=0;i<list.size();i++){
             list.set(i,newList.get(i));
          }
       }
       return list;
    }

    /**
     * List的vo转换
     * @param list
     * @param clazz
     * @return
     */
    @SneakyThrows
    public <T>List<T> turnToVOList(List list,Class clazz) {
       List<T> newResult = new ArrayList();
       if(list!=null&&list.size()>0){
          newResult=new ArrayList(list.size());
          for (Object o : list) {
             Object newObject=clazz.newInstance();
             copyProperties(o,newObject);
             newResult.add((T)newObject);
          }
          process(list,newResult, clazz);
       }
       return newResult;
    }


    /**
     * vo转换
     * @param o
     * @param clazz
     * @param <T>
     * @return
     */
    @SneakyThrows
    public <T>T turnToVO(Object o,Class<T> clazz) {
       if(o!=null){
          T newObject=clazz.newInstance();
          copyProperties(o,newObject);
          process(ListUtil.toList(o),ListUtil.toList(newObject),clazz);
          return newObject;
       }
       return null;
    }

    /**
     * 装填JoinProperty数据
     * @param list
     * @param clazz
     */
    @SneakyThrows
    public void fillJoinProperty(List list,Class clazz){
       Field[] fields = clazz.getDeclaredFields();
       for (Field field : fields) {
          JoinProperty joinProperty = field.getAnnotation(JoinProperty.class);
          if (joinProperty != null) {
             Set idSet=new HashSet();
             for (Object o : list) {
                Object id=clazz.getMethod("get"+ StrUtil.upperFirst(joinProperty.source())).invoke(o);
                if(id!=null){
                   idSet.add(id);
                }
             }
             if(idSet.size()>0){
                String mapperName=joinProperty.joinEntity()+"Mapper";
                Object mapper= SpringContextHolder.getBean(StrUtil.lowerFirst(mapperName));
                String targetColumn="".equals(joinProperty.select())?field.getName():joinProperty.select();
                String targetQuery="".equals(joinProperty.on())?"id":joinProperty.on();
                Class queryClass=Class.forName("com.baomidou.mybatisplus.core.conditions.query.QueryWrapper");
                Object query=queryClass.newInstance();
                queryClass.getMethod("select",String[].class).invoke(query,(Object)new String[]{StrUtil.toUnderlineCase(targetQuery),StrUtil.toUnderlineCase(targetColumn)});
                queryClass.getMethod("in",Object.class, Collection.class).invoke(query,StrUtil.toUnderlineCase(targetQuery),idSet);
                List entityList=(List)mapper.getClass().getMethod("selectList",Class.forName("com.baomidou.mybatisplus.core.conditions.Wrapper")).invoke(mapper,query);
                Map entityMap=new HashMap(entityList.size());
                for (Object entity : entityList) {
                   entityMap.put(entity.getClass().getMethod("get"+StrUtil.upperFirst(targetQuery)).invoke(entity),entity.getClass().getMethod("get"+StrUtil.upperFirst(targetColumn)).invoke(entity));
                }
                for (Object o : list) {
                   Object id=clazz.getMethod("get"+StrUtil.upperFirst(joinProperty.source())).invoke(o);
                   Object value=entityMap.get(id);
                   field.setAccessible(true);
                   if(value==null&&!"\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n".equals(joinProperty.defaultValue())){
                      field.set(o, Convert.convert(field.getType(),joinProperty.defaultValue()));
                   }else{
                      field.set(o,value);
                   }
                }
             }
          }
       }
    }

    /**
     * 附加属性处理
     * @param source
     * @param list
     * @param clazz
     */
    @SneakyThrows
    private void process(List source,List list,Class clazz){
       Class sourceClass = source.get(0).getClass();
       Field[] sourceFields = sourceClass.getDeclaredFields();
       for (Field sourceField : sourceFields) {
          Mapping mapping=sourceField.getAnnotation(Mapping.class);
          if(mapping!=null&&mapping.target().length()>0){
             for (int i=0;i<list.size();i++) {
                Object o=list.get(i);
                Object sourceObject=source.get(i);
                Object value = sourceClass.getMethod("get" + StrUtil.upperFirst(sourceField.getName())).invoke(sourceObject);
                clazz.getMethod("set"+StrUtil.upperFirst(mapping.target()),value.getClass()).invoke(o,value);
             }
          }
       }
       Field[] fields = clazz.getDeclaredFields();
       for (Field field : fields) {
          Mapping mapping=field.getAnnotation(Mapping.class);
          if(mapping!=null&&mapping.source().length()>0){
             for (int i=0;i<list.size();i++) {
                Object o=list.get(i);
                Object sourceObject=source.get(i);
                Object value=sourceClass.getMethod("get"+StrUtil.upperFirst(mapping.source())).invoke(sourceObject);
                if(value!=null){
                   field.setAccessible(true);
                   field.set(o,value);
                }
             }
          }
       }
       fillJoinProperty(list,clazz);
    }

}

Entity转VO工具BeanCopyUtils使用技巧

BeanCopyUtils主要用于Entity转VO,同时可对VO中的附加字段从数据库中进行关联查询。主要的使用方式如下:

案例一,单个Entity转成VO
UserInfo userInfo=userInfoService.getById(12325465874314113L);
UserInfoVO vo=BeanCopyUtils.turnToVO(userInfo,UserInfoVO.class);
案例二,Entity列表转成VO列表
List<UserInfo> userInfoList=userInfoService.list();
List<UserInfoVO> voList=BeanCopyUtils.turnToVOList(userInfoList,UserInfoVO.class);
案例三,将分页对象Page中的Entity列表转成VO
Page<UserInfo> page=userInfoService.page();
BeanCopyUtils.replaceWithVO(page.getRecords(),UserInfoVO.class);

注意:案例三中其实都不用将转换后的对象赋值给一个变量,因为执行replaceWithVO方法后原List中的对象已经被替换了,直接将原List或Page返回给前端就行了,除非需要对VO的列表结果还需要进行下一步操作。

案例四,VO中的某些字段与源实体中的字段名不一致

有些时候VO中的某些字段与源实体中的字段名不一样,需要手动在逻辑代码中进行转换,这个时候只需要通过Mapping注解进行标记即可,注意:

public class UserInfoVO{
    
    /**
     * 用户id
     */
    @Mapping(source="id")
    private Long userId;
}
案例五,VO中的某些附加字段需要从数据库中级联查询

假设UserInfoVO长这样,里面有个部门id deptId

public class UserInfoVO{
    //其他的字段忽略
    
    /**
     * 部门id
     */
    private Long deptId;
}

这时,我们希望展示给前端的结果中能把部门的名字展示出来,一般我们会给UserInfoVO加一个字段

public class UserInfoVO{
    //其他的字段忽略
    
    /**
     * 部门id
     */
    private Long deptId;

    /**
     * 部门名称
     */
    private Long deptName;
}

然后在将查询结果转成VO后再从部门表中根据部门id查出部门信息塞到VO中

//单条记录
UserInfo userInfo=userInfoService.getById(12325465874314113L);
UserInfoVO vo=BeanCopyUtils.turnToVO(userInfo,UserInfoVO.class);
DeptInfo deptInfo=deptInfoService.getById(vo.getDeptId);
vo.setDeptName(deptInfo.getDeptName());

//多条记录
List<UserInfo> userInfoList=userInfoService.list();
List<UserInfoVO> voList=BeanCopyUtils.replaceWithVO(userInfoList,UserInfoVO.class);
for(UserInfoVO vo:voList){
        DeptInfo deptInfo=deptInfoService.getById(vo.getDeptId);
        vo.setDeptName(deptInfo.getDeptName());
}

//上面多条记录性能不好,查询次数会随着userInfoList的数量的增加而增加
//多条记录优化
List<UserInfo> userInfoList=userInfoService.list();
List<UserInfoVO> voList=BeanCopyUtils.replaceWithVO(userInfoList,UserInfoVO.class);
Set<Long> ids=voList.stream().map(UserInfoVO::getDeptId).collect(Collectors.toSet());
List<DeptInfo> deptInfoList=deptInfoService.listByIds(ids);
Map<Long,String> map=deptInfoList.stream().collect(Collectors.toMap(DeptInfo::getId,DeptInfo::getDeptName));
for(UserInfoVO vo:voList){
    vo.setDeptName(map.get(vo.getDeptId()));
}

上面的案例中我们可以看到步骤比较繁杂,而且还没有进行空指针判断代码就已经看起来比较多,所以针对上面这种情况我们可以通过添加一个@JoinProperty注解即可

public class UserInfoVO{
    //其他的字段忽略
    
    /**
     * 部门id
     */
    private Long deptId;

    /**
     * 部门名称
     */
    @JoinProperty(joinEntity = "DeptInfo", source ="deptId",on = "id",select = "deptName")
    private Long deptName;
}

这样上面那些繁杂的代码都不需要了,就执行turnToVO()方法即可。

说明:@JoinProperty注解中的joinEntity指需要关联的表对应的表名,source指用VO中的哪个字段去查,on指查的时候对应关联表的条件字段是什么,select指
取关联实体中的哪个字段。

上面案例中由于查的是id,所以on参数可以不写,因为默认查id。然后VO中的deptName和DeptInfo中的deptName名字一致,所以select也可以不写。

public class UserInfoVO{
    //其他的字段忽略
    
    /**
     * 部门id
     */
    private Long deptId;

    /**
     * 部门名称
     */
    @JoinProperty(joinEntity = DeptInfo.class, source ="deptId")
    private Long deptName;
}

如果字段没有映射到数据,想设置一个默认值,则可使用defaultValue参数

public class UserInfoVO{
    //其他的字段忽略
    
    /**
     * 部门id
     */
    private Long deptId;

    /**
     * 部门名称
     */
    @JoinProperty(joinEntity = DeptInfo.class, source ="deptId", defaultValue="默认部门")
    private Long deptName;
}
  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值