业务开发过程中,经常会遇到各种实体之类的转换,JSON转换,Map转换,属性赋值填充,这里整理几个常用的工具,提升效率。
(1)Bean转换工具类
在一些通用传参、签名验证等场景,需要将接口Param参数或实体,转成Map类型;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Map;
/**
* @author A
* @description javaBean转Map工具类
* @date 2021/1/16
*/
@Slf4j
public class BeanUtils {
/**
* obj转Map
*/
public static Map convertToMap(Object obj) {
Map map = Maps.newHashMap();
try {
// 获取javaBean的BeanInfo对象
BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass(), Object.class);
// 获取属性描述器
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
// 获取属性名
String key = propertyDescriptor.getName();
// 获取该属性的值
Method readMethod = propertyDescriptor.getReadMethod();
Object value = readMethod.invoke(obj);
map.put(key, value);
}
} catch (Exception e) {
log.error("BeanUtils.convertToMap_error! e:{}", e);
}
return map;
}
/**
* obj转Map
*/
public static Map convertToStrMap(Object obj) {
Map map = Maps.newHashMap();
try {
final Map stringObjectMap = convertToMap(obj);
if (MapUtils.isNotEmpty(stringObjectMap)) {
stringObjectMap.forEach((k, v) -> map.put(k, (String) (v)));
}
} catch (Exception e) {
log.error("BeanUtils.convertToStrMap_error! e:{}", e);
}
return map;
}
}
(2)实体转换
DO、DTO、BO、VO之间的转换,大部分都是同名属性赋值;这里推荐一个导师建议的第三方工具包MapStruct,导师说之前在天猫时使用较多的就是这个插件;原理是扫描并解析注解参数,在编译期生成setter方法;相对BeanUtil的copyProperties,这个插件更为强大和省心,如能自定义setter方法加入业务逻辑,能指定哪些字段需要赋值那些不需要,赋值前后的映射关系,这些都可以通过注解属性实现;而SpringFramework自带的bean转换工具反而不是很推荐,不灵活切可能遇到类转换错误、装箱/拆箱时的空指针等;
依赖:
1.2.0.Final
org.mapstruct
mapstruct
${mapstruct.version}
compile
org.mapstruct
mapstruct-processor
${mapstruct.version}
compile
新建Mapper接口:
/**
* bean转换服务
*
* @Author AA
* @CreateDate 2019/12/09
*/
@Mapper(componentModel = "spring")
public interface BeanConvertMapper {
AccountInfoDTO convertToAccountInfoDTO(AccountInfo accountInfo);
@Mappings({
@Mapping(source = "userId", target = "openid")
})
UserInfoDTO convertToUserInfo(UserInfo userInfo);
@Mappings({
@Mapping(target = "periods", expression = "java(com.xx.internet.supermembercore.service.help.BeanMapperUtil.cfgToPeriods(memberDO))")
})
MemberDTO convertToMemberDTO(MemberDO memberDO);
/*一对一*/
@Mappings({
@Mapping(target = "userBenefitId", source = "benefitInstanceId"),
@Mapping(target = "amount", ignore = true),
@Mapping(target = "balance", source = "benefitValue"),
@Mapping(target = "endTime", source = "benefitExpireTime"),
@Mapping(target = "useStatus", source = "benefitStatus"),
@Mapping(target = "rcvTime", source = "sendDay")
})
UserBenefitDTO convertToUserBenefitDTO(MemberBenefitDO memberBenefitDO);
/*多对一*/
@Mappings({
@Mapping(source = "sku.id", target = "skuId"),
@Mapping(source = "sku.code", target = "skuCode"),
@Mapping(source = "sku.price", target = "skuPrice"),
@Mapping(source = "item.id", target = "itemId"),
@Mapping(source = "item.title", target = "itemName")
})
SkuDTO domain2dto(Item item, Sku sku);
}
参考:
mapstruct使用详解
MapStruct – Java bean mappings, the easy way!
(3)JSON相关的注解
名称到属性的映射、复用类但需要忽略非必要参数给前端;
1. 返回参数时忽略属性,会用到Jackson相关的注解,其中用得较多的是@JSONIgnore:
(1) @JsonIgnoreProperties
// 此注解是类注解,作用是json序列化时将java bean中的一些属性忽略掉;
// 写法将此标签加在model类的类名上,可以多个属性也可以单个属性;
// 生成json时将name和age属性过滤
@JsonIgnoreProperties({"name"}, {"age"})
public class user {
private Long id;
private String name;
private int age;
}
(2) @JsonIgnore
// 此注解用于属性或者方法上(最好是属性上),作用和上面的@JsonIgnoreProperties一样
// 生成json时不生成age属性
public class user {
private String name;
@JsonIgnore
private int age;
}
(3) @JsonFormat
// 此注解用于属性或者方法上(最好是属性上),可以方便的把Date类型直接转化为我们想要的模式,
// 比如@JsonFormat(pattern = “yyyy-MM-dd HH-mm-ss”)
(4) @JsonSerialize
// 此注解用于属性或者getter方法上,用于在序列化时嵌入我们自定义的代码,比如序列化一个double时在其后面限制两位小数点。
(5) @JsonDeserialize
// 此注解用于属性或者setter方法上,用于在反序列化时可以嵌入我们自定义的代码,类似于上面的@JsonSerialize
2. 传输时传参paramName与实体字段名映射;尤其是设计参数与java关键字重合时,非常方便;
如这里的前段传参的参数名"enum",服务端无法使用enum接收参数(java关键字冲突);
/**
* QuestionSchemaDTO
*/
@Data
public static class QuestionSchemaDTO {
/**
* 问题key 需手动赋值 用来匹配答案表单
*/
private String key;
/**
* 问题标题
*/
@JSONField(name = "title")
private String questionName;
/**
* 问题输入类型 string-单选/单填空 array-多选
*/
private String type;
/**
* 填空题的沉底提示语
*/
private String placeholder;
/**
* 选项 tip:前端协议enum为空则认为是填空题
*/
@JSONField(name = "enum")
private List options;
}