BeanUtils——JavaBean相互转换及字典翻译
JavaBean相互转换
在升级公司架构过程中,发现有大量Entity与DTO相互转换的问题,并且其中还伴随DTO中的数据字典翻译,所以特意写个工具类,主要利用spring提供的BeanUtils工具类,用redis翻译字典
其中功能包括:
翻译JavaBean中带有@CacheFormat的属性
/**
* 翻译当前类中需要翻译的字典值
*
* @param source 待翻译的对象
*/
public static <T> void dataFormatter(T source) { //判断原对象是否为null
Assert.notNull(source, "待翻译的原对象不能为null"); //获取所有属性并翻译字典
Field[] declaredFields = source.getClass().getDeclaredFields();
//翻译字典:找出所有含有@CacheFormatter的属性
Stream<Field> fieldStream = Arrays.stream(declaredFields)
//排除没有注解@CacheFormatter的字段
.filter(field -> field.isAnnotationPresent(CacheFormat.class));
//翻译
doFormatter(fieldStream, source, source.getClass());
}
翻译List中带有@CacheFormat的属性
/**
* 翻译当前集合类中需要翻译的字典值
*
* @param sources 待翻译的集合对象
*/
public static <T> void dataFormatter(List<T> sources) { //当翻译的集合为空时,返回空的集合
if (sources == null || sources.isEmpty()) {
return;
} Class targetClass = sources.get(0).getClass();
//获取所有属性并翻译字典
Field[] declaredFields = targetClass.getDeclaredFields();
//翻译字典:找出所有含有@CacheFormat的属性集合
List<Field> formatterFields = Arrays.stream(declaredFields)
//排除没有注解@CacheFormat的字段
.filter(field -> field.isAnnotationPresent(CacheFormat.class))
.collect(Collectors.toList());
//循环列表(并行操作)
sources.parallelStream().forEach(target -> {
//翻译
doFormatter(formatterFields.stream(), target, targetClass);
});
}
Entity 与DTO互转
/**
* 把原对象转换成目标类的对象,并翻译目标类的属性字典
* 只针对目标类没有范型或者范型与原对象一样
* @param source 原对象
* @param targetClass 目标类
* @return 目标对象
*/
public static <T> T dataConvert(Object source, Class<T> targetClass) { Assert.isTrue(source != null && targetClass != null, "原对象或目标class不能为null"); T target = BeanUtils.instantiateClass(targetClass);
//把目标对象的属性设置成原对象中对应的属性
BeanUtils.copyProperties(source, target); dataFormatter(target);
return target;
} /**
* 实体属性互转
*
* @param source 原对象
* @param target 目标对象
* @return 目标对象
*/
public static <T> T dataObjConvert(Object source, T target) { Assert.isTrue(source != null && target != null, "待转换的原对象或目标对象不能为null");
//转换
BeanUtils.copyProperties(source, target);
//翻译
dataFormatter(target);
return target;
}
List与List互转
/**
* 批量把原对象转换成目标对象,并翻译目标对象的属性字典
* 如果想返回指定类型的集合即List的子类,参考{@link HyBeanUtils#dataConverts2}
*
* @param sources 原对象集合
* @param targetClass 目标对象的类
* @return 返回转换后的目标集合
*/
public static <T, E> List<T> dataConverts(List<E> sources, Class<T> targetClass) { Assert.notNull(targetClass, "转换的目标Class不能为null"); //当翻译的集合为空时,返回空的集合
if (sources == null || sources.isEmpty()) {
List<T> targetList = new ArrayList<>();
return targetList;
}
//获取原集合的类型
Class<? extends List> aClass = sources.getClass();
//目标集合
List<T> targetList = BeanUtils.instantiateClass(aClass); //把目标对象的属性设置成原对象中对应的属性(并行操作)
sources.parallelStream().forEach(item -> {
T target = BeanUtils.instantiateClass(targetClass);
BeanUtils.copyProperties(item, target);
targetList.add(target);
}); //翻译字典
dataFormatter(targetList); return targetList;
}
这个是List转换的升级版 T与T互转,这里的T是List的子类
之所以写这个,就是为了解决mybatis的Page转换问题/**
* 返回指定类型的方法,这里的类型必须是List的子类
* 批量把原对象转换成目标对象,并翻译目标对象的属性字典,
*
* @param sources 原对象集合
* @param targetClass 目标对象的类
* @param returnType 返回值类型
* @return 返回转换后的目标集合
*/
public static <T, E, R extends List<T>> R dataConverts2(List<E> sources, Class<T> targetClass, Class<R> returnType) { Assert.notNull(targetClass, "转换的目标Class不能为null");
Assert.notNull(returnType, "返回值类型Class不能为null"); //当翻译的集合为空时,返回空的集合
if (sources == null || sources.isEmpty()) {
return null;
}
//目标集合
R targetList = BeanUtils.instantiateClass(returnType); //把目标对象的属性设置成原对象中对应的属性(并行操作)
sources.parallelStream().forEach(item -> {
T target = BeanUtils.instantiateClass(targetClass);
BeanUtils.copyProperties(item, target);
targetList.add(target);
}); //翻译字典
dataFormatter(targetList); return targetList;
}
上述所用到的公共方法
/**
* 对目标类需要翻译的字段进行翻译
*
* @param stream
* @param target 目标对象
* @param targetClass 目标对象类
*/
private static <T> void doFormatter(Stream<Field> stream, Object target, Class<T> targetClass) { //排除目标对象中字段值为null的字段
stream.filter(field -> {
PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(targetClass, field.getName());
Object invoke = null;
try {
invoke = propertyDescriptor.getReadMethod().invoke(target, new Object[]{});
} catch (IllegalAccessException e) {
logger.warn("待翻译的字段的get是无法访问的", e);
} catch (InvocationTargetException e) {
logger.warn("调用待翻译的字段的get方法时报错", e);
} catch (Exception e) {
logger.warn("确保属性有get,set方法", e);
}
return invoke != null;
//遍历需要翻译的字段
}).forEach(field -> {
CacheFormat annotation = field.getAnnotation(CacheFormat.class); //缓存系统编号,如果不指定则默认为当前系统编号
String systemCode = "system_code";
if (StringUtils.isNotBlank(annotation.systemCode())) {
systemCode = annotation.systemCode();
}
//缓存key,如果不指定,则默认为字段名称
String key = annotation.key();
if (StringUtils.isBlank(key)) {
key = field.getName();
} //判断注解@CacheFormatter是否指定把字典翻译到另一个字段上
String formatterField = annotation.destination();
if (StringUtils.isBlank(formatterField)) {
//当注解中不指定其他字段时,默认翻译到加注解的属性上
formatterField = field.getName();
} try {
PropertyDescriptor orginPropertyDescriptor = BeanUtils.getPropertyDescriptor(targetClass, field.getName());
Object value = orginPropertyDescriptor.getReadMethod().invoke(target, new Object[]{});
//设置目标字段值
PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(targetClass, formatterField);
//取缓存
String cacheValue = RedisUtils.hget(systemCode +":valueset:" + key, value + "");
//如果数据字典中查询不到,则取业务缓存中取
if (StringUtils.isBlank(cacheValue)) {
cacheValue = RedisUtils.hget(systemCode + ":valueset:" + key, value + "");
} Assert.hasLength(cacheValue, "在缓存" + key + "中没有找到" + value + "对应的缓存");
//设置缓存值到属性字段中
propertyDescriptor.getWriteMethod().invoke(target, cacheValue); } catch (IllegalAccessException e) {
logger.warn("待翻译的字段的set是无法访问的", e);
} catch (InvocationTargetException e) {
logger.warn("调用待翻译的字段的set方法时报错", e);
} catch (Exception e) {
e.printStackTrace();
logger.warn("调用待翻译的字段的set方法时报错,推测类型不匹配", e);
}
}); }
注解 CacheFormat
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheFormat { /**
* 缓存key
* @return
*/
String key(); /**
* 指定翻译值存放字段, 例如:userType的翻译结果放到userTypeName上
* @return
*/
String destination() default ""; /**
* 系统编号
* @return
*/
String systemCode() default "";
注意:该翻译只关注第一层即当前对象的属性,并不会递归翻译
比如:当前类有一个属性为对象实例,该对象也有被@CacheFormat注解的属性
这时该工具类不会去翻译这个属性中的属性,需要开发者先用当前工具类转换该属性
然后再设置到目标类中
BeanUtils——JavaBean相互转换及字典翻译的更多相关文章
- Git-it字典翻译
Git-it字典翻译 下面的内容翻译自git-it/dictionary 水平有限,翻译欠佳. Git准备工作 创建一个新的文件夹(目录) $ mkdir <目录名称> 切换到这个目录 ( ...
- poj 2503:Babelfish(字典树,经典题,字典翻译)
Babelfish Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 30816 Accepted: 13283 Descr ...
- hdu 1075:What Are You Talking About(字典树,经典题,字典翻译)
What Are You Talking About Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 102400/204800 K ...
- 字典翻译@Dict
1.编写翻译字典@Dict /** * 数据字典翻译注解 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) publ ...
- BeanUtils JavaBean 工具包使用
感谢原文作者:小老弟 原文链接:https://www.cnblogs.com/syncmr/p/10523576.html 目录 简介 BeanUtils类 使用示例 ConvertUtils 功能 ...
- HDOJ1075字典翻译(map应用)
#include<iostream> #include<cstdio> #include<map> #include<string> #include& ...
- kettle系列-6.kettle实现多字段字典快速翻译
在数据清洗转换中,常见的字典翻译,如性别在原表中是1(男).2(女)等,类似还有很多较大的字典需要翻译,若同一个表中有很多个字典需要翻译,采用[数据库查询]方式翻译的话效率就会相当低下. 这里采用ja ...
- java将一个javabean转化为另一个javabean
公司的项目是用webservice来进行前后台对接,启动后台后需要刷服务才能在前台生成对应的代码,但是有一个很恶心的地方,它给每个service都生成了一个model,于是出现后台只有一个javabe ...
- JavaBean转换为XML的源码
package com.cmge.utils; import java.util.Iterator; import com.cmge.org.oa.bean.OADepartment; import ...
随机推荐
- JavaWeb笔记(十一)Maven
什么是Maven Maven是Apache旗下一款开源自动化的项目管理工具,它使用java语言编写,因此Maven是一款跨平台的项目管理工具. 主要功能 项目构建 在实际开发中,不仅仅是写完代码项目就 ...
- Android记事本07
昨天: activity横竖屏切换的生命周期 今天: Anr异常的原因和解决方案 遇到的问题: 无.
- oracle定时job粗解
其中一篇随笔我写了oracle的存储过程大概的介绍,存储过程除了自身有in的param,来进行程序调用处理之外,还可以通过定时任务的方式调用来执行. 应用场景: 数据同步:有两个显示菜单,“信息编辑” ...
- Linux下磁盘管理
设置密码mkpasswdmkpasswd -s 0mkpasswd -s 0 -1 15 规定密码的长度 1. 查看磁盘或者目录的容量df 查看磁盘各分区使用情况 不加参数以k为单位 df -i in ...
- 多线程 线程组 ThreadGroup
package org.zln.thread; import java.util.Date; /** * Created by sherry on 000024/6/24 22:30. */ publ ...
- 【bzoj4154】[Ipsc2015]Generating Synergy KD-tree
题目描述 给定一棵以1为根的有根树,初始所有节点颜色为1,每次将距离节点a不超过l的a的子节点染成c,或询问点a的颜色 输入 第一行一个数T,表示数据组数 接下来每组数据的第一行三个数n,c,q表示结 ...
- 【bzoj1270】[BeijingWc2008]雷涛的小猫 dp
题目描述 输入 输出 样例输入 样例输出 8 题解 dp 设f[i][j]表示在第i棵树的j高度时最多吃到的柿子数. 那么只有两种可能能够到达这个位置:滑下来.跳下来. 滑下来直接用f[i][j+ ...
- [spoj] FTOUR2 FREE TOUR II || 树分治
原题 给出一颗有n个点的树,其中有M个点是拥挤的,请选出一条最多包含k个拥挤的点的路径使得经过的权值和最大. 正常树分治,每次处理路径,更新答案. 计算每棵子树的deep(本题以经过拥挤节点个数作为d ...
- .ini配置读取
ini文件的格式 格式 INI文件由节.键.值组成. 节 [section] 参数(键=值) name=value 注解 注解使用分号表示(;).在分号后面的文字,直到该行结尾都全部为注解. ...
- Hibernate中的延迟加载及fetch
Hibernate中的延迟加载 1.类级别的查询策略: lazy : true(默认值) false(立即加载) 2.多对一关联的查询策略: lazy: proxy(默认值) no-proxy ...