通过映射将Map值赋值给实体类属性

通过映射将MAP数据映射到对应的实体类

  1. 通过映射来给实体赋值,new一个对应实体类的class实例,然后取到实体类的所有属性数组,遍历属性数组,从map中获取对应的value值。注意:获取的属性数组中只能获取到它当前的所有属性,不能获取到它继承的属性,想要获取到其父类的属性可以通过获取到其父类字节码,然后在获取父类中的所有属性;
    有一个问题是:获取value值时,是根据当前类属性的字段名称来获取它的value值,所以必须要求类属性的名称与map中的key值完全一致,否则不能获取到值。具体代码如下:
//这里clazz参数代表的是需要转换的对应实体类class,map就是要取值的map,我们调用的时候可以直接传map和实体class。如:
mapTObject(map, A.class);

public static Object mapTObject(Map<String, Object> map,Class<?> clazz){
		if(map == null){
			return null;
		}
		Object obj = null;
		try {
			obj = clazz.newInstance();
			Field[] fields = obj.getClass().getDeclaredFields();//获取到所有属性,不包括继承的属性
			Field[] supFields = obj.getClass().getSuperclass().getDeclaredFields();//获取传入类的父类的所有属性
			for(Field field : fields){
				int mod = field.getModifiers();//获取字段的修饰符
				if(Modifier.isStatic(mod) || Modifier.isFinal(mod)){
					continue;
				}
				field.setAccessible(true);
				field.set(obj, map.get(field.getName()));//根据属性名称去map获取value
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return obj;
	}

通过实体挨个赋值

直接从map中根据key获取value值来赋值给对应实体类的属性。缺点是会比较麻烦一些,需要挨个给获取map中额key值赋值给实体。如下:

User user = User.builder()
			.name(StringUtils.isNotBlank(map.get("name")) ? map.get("name") : null)
			.age(map.get("age"))
			.build();

自定义转译工具类,转译实体类

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.vladmihalcea.hibernate.type.json.internal.JacksonUtil;
import lombok.*;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.ResultTransformer;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.WKTReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ConcurrentReferenceHashMap;

import javax.persistence.Column;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {

    @Autowired
    private static EntityManager entityManager;

    public static void main(String[] args) {
        //自定义SQL查询语句
        String sql = "select * from user ";
        int nowPage = 1;
        int pageSize = 10;
        Query pageQuery = entityManager.createNativeQuery(sql);
        pageQuery.setFirstResult((nowPage-1) * pageSize);
        pageQuery.setMaxResults(pageSize);
        NativeQueryImplementor<User> implementor = pageQuery.unwrap(NativeQueryImpl.class).setResultTransformer(new BaseTransformer(User.class));
        List<User> resultList = implementor.list();
    }

}

class BaseTransformer implements ResultTransformer {

    /**
     * 缓存
     */
    private static Map<Class, Map<String, DOProperties>> cacheMap = new ConcurrentReferenceHashMap<>();
    /**
     * 列名-属性名,属性类型
     */
    private Map<String, DOProperties> map;
    private Class resultClass;



    private static Pattern CAMEL_PATTERN = Pattern.compile("([a-z])([A-Z])");
    private static final String UNDER_LINE = "_";

    private static final int DATE = 1;
    private static final int DATE_TIME = 2;
    private static final String DATE_FORMAT = "yyyy-MM-dd";
    private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT);
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT);


    private static Set<Class> DATE_CLASS = Sets.newHashSet(java.sql.Date.class,
            LocalDateTime.class, LocalDate.class, Timestamp.class);
    private static Set<Class> GEOMETRY_CLASS = Sets.newHashSet(Geometry.class);
    private static Set<Class> JSON_CLASS = Sets.newHashSet(JsonNode.class, JSONObject.class, JSONArray.class);
    private static List<Set<Class>> CLASS_LIST = Lists.newArrayList(DATE_CLASS, GEOMETRY_CLASS, JSON_CLASS);


    @SneakyThrows
    @Override
    public Object transformTuple(Object[] tuple, String[] aliases) {
        Object result = resultClass.newInstance();
        for (int i = 0; i < tuple.length; i++) {
            if (tuple[i] == null) {
                continue;
            }
            if (map.containsKey(aliases[i])) {
                //属性名-属性类型
                DOProperties property = map.get(aliases[i]);
                if (property != null) {
                    Object value;
                    Class type = property.getClassType();
                    if (support(tuple[i].getClass(), type)) {
                        value = transferType(tuple[i], type);
                    } else {
                        value = tuple[i];
                    }
                    //TODO 性能有问题,修改实现
                    BeanUtils.copyProperty(result, property.getClassName(), value);
//                    property.getSetter().invoke(result, value);
                }
            }
        }
        return result;
    }

    @Override
    public List transformList(List list) {
        return list;
    }

    /**
     * TODO 通过工厂类获取单例对象
     */
    public BaseTransformer (Class clazz) {
        this.resultClass = clazz;
        map = cacheMap.get(resultClass);
        if (map == null) {
            map = new HashMap<>(16);
            //缓存实体类属性与数据库列名的对应关系?
            Class curr = resultClass;
            while (curr != null && curr != Object.class) {
                for (Field field : curr.getDeclaredFields()) {
                    Column annotation = field.getAnnotation(Column.class);
                    String columnName;
                    //如过属性有column注解,则使用对应的列名,否则默认使用驼峰转下划线
                    if (annotation != null && StringUtils.isNotBlank(annotation.name())) {
                        columnName = annotation.name();
                    } else {
                        columnName = camelToUnderline(field.getName());
                    }
                    DOProperties dtoProperties = DOProperties.builder()
                            .column(columnName)
                            .className(field.getName())
                            .classType(field.getType())
                            .setter(getSetter(resultClass, field))
                            .build();
                    map.put(columnName, dtoProperties);
                    //代码中已经存在一些注解使用了大写的字段名,但是表的字段名是小写的情况,处理一下
                    String lowerColumnName = columnName.toLowerCase();
                    if (!map.containsKey(lowerColumnName)) {
                        map.put(lowerColumnName, dtoProperties);
                    }
                }
                curr = curr.getSuperclass();
            }
            cacheMap.put(resultClass, map);
        }
    }

    private Method getSetter(Class resultClass, Field field) {
        String fieldName = field.getName();
        Class fieldType = field.getType();
        String setter = "set" + Character.toUpperCase(fieldName.charAt(0)) +
                (fieldName.length() > 1 ? fieldName.substring(1) : "");
        try {
            return resultClass.getMethod(setter, fieldType);
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

    public static String camelToUnderline(String name) {
        Matcher matcher = CAMEL_PATTERN.matcher(name);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1) + UNDER_LINE + matcher.group(2).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * 判断是否支持类型转换
     * @param source
     * @param target
     * @return
     */
    public static boolean support(Class source, Class target) {
        if (source == target) {
            return true;
        }
        if (source == String.class) {
            for (Set<Class> classSet : CLASS_LIST) {
                if (classSet.contains(target)) {
                    return true;
                }
            }
            return false;
        } else {
            for (Set<Class> classSet : CLASS_LIST) {
                //实现了同种分类格式之间的转换(如不同的时间格式之间转换)
                if (classSet.contains(source)) {
                    return target == String.class || classSet.contains(target);
                }
            }
            return false;
        }
    }

    /**
     * 类型转换
     *
     * @param parameter  原始值
     * @param targetType 目标类型
     * @param <T>
     * @return
     * @see #support(Class, Class) 实现了该方法返回true的类型转换
     */
    @SneakyThrows
    public static <T> T transferType(Object parameter, Class<T> targetType) {
        if (parameter == null) {
            return null;
        }
        if (parameter.getClass() == targetType) {
            return (T) parameter;
        }
        //将原始参数类型统一转换成String,便于向目标类型转换。减少需要实现的代码,不过会降低些转换效率
        String str = formatToStr(parameter);
        if (targetType == String.class) {
            return (T) str;
        } else if (targetType == Geometry.class) {
            WKTReader reader = new WKTReader();
            return (T) reader.read(parameter.toString());
        } else if (targetType == LocalDate.class) {
            return (T) LocalDate.parse(formatDateStr(str, DATE), DATE_FORMATTER);
        } else if (targetType == LocalDateTime.class) {
            return (T) LocalDateTime.parse(formatDateStr(str, DATE_TIME), DATE_TIME_FORMATTER);
        } else if (targetType == Timestamp.class) {
            LocalDateTime localDateTime = LocalDateTime.parse(formatDateStr(str, DATE), DATE_TIME_FORMATTER);
            return (T) Timestamp.valueOf(localDateTime);
        } else if (targetType == java.sql.Date.class) {
            LocalDate localDate = LocalDate.parse(formatDateStr(str, DATE), DATE_FORMATTER);
            return (T) java.sql.Date.valueOf(localDate);
        } else if (targetType == Integer.class) {
            return (T) Integer.valueOf(str);
        } else if (targetType == Long.class) {
            return (T) Long.valueOf(str);
        } else if (targetType == Short.class) {
            return (T) Short.valueOf(str);
        } else if (targetType == Boolean.class) {
            return (T) Boolean.valueOf(str);
        } else if (targetType == Float.class) {
            return (T) Float.valueOf(str);
        } else if (targetType == Double.class) {
            return (T) Double.valueOf(str);
        } else if (targetType == Byte.class) {
            return (T) Byte.valueOf(str);
        } else if (targetType == JsonNode.class){
            return (T) JacksonUtil.toJsonNode(str);
        } else if (targetType == JSONObject.class) {
            return (T) JSONObject.parseObject(str);
        } else if (targetType == JSONArray.class) {
            return (T) JSONObject.parseArray(str);
        } else {
            throw new IllegalArgumentException("不支持的目标类型:" + targetType.getName());
        }
    }

    /**
     * 转换两个日期字符串的格式
     *
     * @param str
     * @param date
     * @return
     */
    private static CharSequence formatDateStr(String str, int date) {
        if (str.length() == DATE_FORMAT.length()) {
            //将只有日期的格式转换为日期和时间的格式
            if (date == DATE_TIME) {
                str = str + " 00:00:00";
            }
        } else if (str.length() == DATE_TIME_FORMAT.length()) {
            //将日期和时间的格式转换为只有日期的格式
            if (date == DATE) {
                str = str.substring(0, DATE_FORMAT.length());
            }
        }
        return str;
    }

    private static String formatToStr(Object v) {
        //先将日期类型转换成统一格式的字符串
        if (v instanceof Timestamp) {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_TIME_FORMAT);
            return simpleDateFormat.format((Timestamp) v);
        } else if (v instanceof LocalDateTime) {
            return DATE_TIME_FORMATTER.format((LocalDateTime) v);
        } else if (v instanceof LocalDate) {
            return DATE_FORMATTER.format((LocalDate) v);
        } else if (v instanceof java.sql.Date) {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_TIME_FORMAT);
            return simpleDateFormat.format((java.sql.Date) v);
        } else {
            return v.toString();
        }
    }
}
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.lang.reflect.Method;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DOProperties {
    private String column;
    private Class classType;
    private String className;
    private Method setter;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值