使用@Query注解的时候,常常需要写sql来映射非域类的实例,通常的做法就是 实现 RowMapper接口,然后new实例一个一个的设置值进去。。。为此。出世了自动映射工具类

注意事项:此抽象类只是结果集 一条记录到行  的映射,添加了额外的方法;比如就是把一个字段的值拆分成Map或List,然后会自动组装成类实例

这是抽象类,也是主要的,你的域类继承这个抽象类即可,无需任何实现,@Query(....,rowMapperClass=域类.class) 即可

package cn.dmahz.dao.repo.model;

import cn.dmahz.dao.repo.model.article.ArticleInfoRepoModel;
import cn.dmahz.utils.MyReflectUtils;
import com.sun.rowset.JdbcRowSetImpl;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.ConvertUtils;
import org.springframework.jdbc.core.RowMapper; import java.lang.reflect.*;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLSyntaxErrorException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern; /**
* 自动映射 RowMapping
* @author Dream
*/
@Slf4j
public abstract class RowMapperAutoMapping<T> implements RowMapper<T> { private static final Set<Class<?>> BASE_TYPE_SET = new HashSet<>();
private static final Set<Class<?>> ARRAY_BASE_TYPE_SET = new HashSet<>(); static {
BASE_TYPE_SET.add(String.class);
BASE_TYPE_SET.add(Byte.class);
BASE_TYPE_SET.add(Byte.TYPE);
BASE_TYPE_SET.add(Double.class);
BASE_TYPE_SET.add(Double.TYPE);
BASE_TYPE_SET.add(Float.class);
BASE_TYPE_SET.add(Float.TYPE);
BASE_TYPE_SET.add(Integer.class);
BASE_TYPE_SET.add(Integer.TYPE);
BASE_TYPE_SET.add(Long.class);
BASE_TYPE_SET.add(Long.TYPE);
BASE_TYPE_SET.add(Short.class);
BASE_TYPE_SET.add(Short.TYPE);
BASE_TYPE_SET.add(Boolean.class);
BASE_TYPE_SET.add(Boolean.TYPE); ARRAY_BASE_TYPE_SET.add(String[].class);
ARRAY_BASE_TYPE_SET.add(Byte[].class);
ARRAY_BASE_TYPE_SET.add(byte[].class);
ARRAY_BASE_TYPE_SET.add(Double[].class);
ARRAY_BASE_TYPE_SET.add(double[].class);
ARRAY_BASE_TYPE_SET.add(Float[].class);
ARRAY_BASE_TYPE_SET.add(float[].class);
ARRAY_BASE_TYPE_SET.add(Integer[].class);
ARRAY_BASE_TYPE_SET.add(int[].class);
ARRAY_BASE_TYPE_SET.add(Long[].class);
ARRAY_BASE_TYPE_SET.add(long[].class);
ARRAY_BASE_TYPE_SET.add(Short[].class);
ARRAY_BASE_TYPE_SET.add(short[].class);
ARRAY_BASE_TYPE_SET.add(Boolean[].class);
ARRAY_BASE_TYPE_SET.add(boolean[].class);
} private static final Pattern COMPILE = Pattern.compile("([A-Z])+"); /**
* 解析处理值,将值解析为数组形式并返回
* @param fieldName
* @param value
*/
protected List<Object> parsedValueIsArray(String fieldName,Object value){
return new ArrayList<>();
} /**
* 将字段值转换成 List Map对象,其中List中的每个Map元素对应一个类实例
* @param fieldName
* @param value
* @return
*/
protected List<Map<String,Object>> parsedValueIsArrayMap(String fieldName,Object value){
return new ArrayList<>();
} public T autoMapping(ResultSet rs,Class<T> tClass) throws SQLException, IllegalAccessException, InstantiationException {
T t = tClass.newInstance();
Field[] allFields = MyReflectUtils.getAllFields(tClass);
for (Field field : allFields) { int modifiers = field.getModifiers();
if(Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)){
continue;
} switchIf(t,field,rs,null);
}
return t;
} /**
* 获取集合的实例
* @return
*/
protected Collection<?> getCollectionInstance(){
return new ArrayList<>();
} @SuppressWarnings("DuplicatedCode")
private void switchIf(Object o, Field field, ResultSet rs, Map<String,Object> valueMap) throws IllegalAccessException, SQLException, InstantiationException {
Object extractValue = extractValue(rs, valueMap, field.getName());
Type genericType = field.getGenericType();
if(genericType instanceof ParameterizedType){
// 泛型类型
ParameterizedType parameterizedType = (ParameterizedType)genericType;
Type rawType = parameterizedType.getRawType();
if(Collection.class.isAssignableFrom((Class<?>) rawType)){
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
if(actualTypeArguments.length > 1){
throw new RuntimeException("仅支持单泛型Copy");
}
Class<?> argumentCls = (Class<?>) actualTypeArguments[0]; boolean b = copyMappingField(o, field, argumentCls, extractValue);
if(!b){
List<Map<String, Object>> maps = parsedValueIsArrayMap(field.getName(), extractValue);
Object instance;
if(!((Class<?>) rawType).isInterface()){
instance = ((Class<?>) rawType).newInstance();
}else{
instance = getCollectionInstance();
} @SuppressWarnings("unchecked") Collection<Object> coll = (Collection<Object>) instance;
Object argInstance;
for (Map<String, Object> map : maps) {
argInstance = argumentCls.newInstance();
Field[] allFields = MyReflectUtils.getAllFields(argumentCls);
for (Field f : allFields) {
switchIf(argInstance,f,null,map);
}
coll.add(argInstance);
}
field.set(o,coll);
}
}
}else{
// 基本数组类型
Class<?> componentType = ((Class<?>) genericType).getComponentType();
if (componentType != null){
// 数组类型,例如:int[] string[] entity[]
copyMappingArray(o,field,componentType,extractValue);
}else {
// 基本类型,不包含泛型的类型 ;基本类型或单类型
boolean b = copyMappingField(o, field, (Class<?>) genericType, extractValue);
if(!b){
log.error("不是基本类型,准备再次进行解刨 {}",genericType);
// 不是基本类型,则进行再次解抛
Class<?> genericCls = ((Class<?>) genericType);
Object instance = genericCls.newInstance();
Field[] allFields = MyReflectUtils.getAllFields(genericCls);
for (Field f : allFields) {
switchIf(instance,f,null,valueMap);
}
}
}
}
} /**
* 处理基本数组形式的copy映射,例如:int[],String[],Long[],实体类[],POJO[];
* 粗略的说明就是:将 expectValue经过解析,返回数组形式的值对象,设置到o对象里的field字段中
* @param o 需要设置对象的实例
* @param field 当前处理的字段
* @param typeCls 字段的类型
* @param expectValue 期望的值
* @throws IllegalAccessException
* @throws SQLException
* @throws InstantiationException
*/
@SuppressWarnings("DuplicatedCode")
private void copyMappingArray(Object o, Field field, Class<?> typeCls, Object expectValue) throws IllegalAccessException, SQLException, InstantiationException {
Object[] oS = (Object[]) Array.newInstance(typeCls,0);
if(BASE_TYPE_SET.contains(typeCls)){
List<Object> objects = parsedValueIsArray(field.getName(), expectValue);
field.set(o,objects.toArray(oS));
}else{
List<Map<String, Object>> maps = parsedValueIsArrayMap(field.getName(), expectValue);
ArrayList<Object> objects = new ArrayList<>();
Object instance;
for (Map<String, Object> map : maps) {
instance = typeCls.newInstance();
Field[] allFields = MyReflectUtils.getAllFields(typeCls);
for (Field f : allFields) {
switchIf(instance,f,null,map);
}
objects.add(instance);
}
field.set(o,objects.toArray(oS));
}
} /**
* 赋值映射普通字段
*/
private boolean copyMappingField(Object o,Field field,Class<?> fieldTypeCls,Object value) throws IllegalAccessException {
if(BASE_TYPE_SET.contains(fieldTypeCls)){
if(value != null){
value = ConvertUtils.convert(value, fieldTypeCls);
}
field.set(o,value);
return true;
}
return false;
} /**
* 提取ResultSet 或 valueMap中的值(二选一),根据字段名称进行获取
* @param rs 结果集 (二选一)
* @param valueMap 值Map,保存字段的名称和值 (二选一)
* @param fieldName 字段名称
* @return
* @throws SQLException
*/
@SuppressWarnings({"DuplicatedCode"})
private Object extractValue(ResultSet rs,Map<String,Object> valueMap,String fieldName) throws SQLException {
String underscoreName = fieldName;
Matcher matcher = COMPILE.matcher(underscoreName);
while (matcher.find()){
underscoreName = underscoreName.replace(matcher.group(1),"_" + matcher.group(1).toLowerCase());
}
String[] keys = new String[]{fieldName,underscoreName};
for (String key : keys) {
try{
return rs != null ? rs.getObject(key) : valueMap !=null && valueMap.containsKey(key) ? valueMap.get(key) : null;
}catch (SQLSyntaxErrorException e) {
// 什么也不做,继续遍历key获取字典
if (e.getErrorCode() != 1054){
throw e;
}
}
}
log.debug("字段 {}从ResultSet中无法获取到值,请注意是否是设计如此", fieldName);
return null;
} public void test(){
System.out.println(this.getClass());
} @SuppressWarnings("unchecked")
@Override
public T mapRow(ResultSet rs, int rowNum) throws SQLException {
try {
Type genericSuperclass = this.getClass().getGenericSuperclass();
if(genericSuperclass instanceof ParameterizedType){
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
return autoMapping(rs, (Class<T>) parameterizedType.getActualTypeArguments()[0]);
}else {
log.warn("泛型未声明,使用 this.getClass() 获取注入的Class对象");
return autoMapping(rs, (Class<T>) this.getClass());
}
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
return null;
} public static void main(String[] args) throws IllegalAccessException, SQLException, InstantiationException {
// Matcher virtualUserName = compile.matcher("virtualUserName");
// System.out.println(virtualUserName.find());
// System.out.println(virtualUserName.find());
// System.out.println(virtualUserName.find());
// System.out.println(virtualUserName.find());
//
// String name = "virtualUserName";
// String underscoreName = name;
// Matcher matcher = compile.matcher(name);
// while (matcher.find()){
// underscoreName = underscoreName.replace(matcher.group(1),"_" + matcher.group(1).toLowerCase());
// }
// System.out.println("underscoreName:" + underscoreName); // TestResultSet testResultSet = new TestResultSet();
// TestEntity testEntity = new TestEntity();
// TestEntity testEntity1 = testEntity.autoMapping(testResultSet, TestEntity.class);
// System.out.println("testEntity1: " + testEntity1); System.err.println(boolean.class);
System.err.println(Boolean.class);
System.err.println(Boolean.TYPE);
System.err.println(Integer.TYPE);
System.err.println(Integer.class);
System.err.println(Integer[].class);
System.err.println(int[].class);
System.err.println(float[].class);
System.err.println(Float[].class); ArticleInfoRepoModel articleInfoRepoModel = new ArticleInfoRepoModel();
articleInfoRepoModel.mapRow(null,1); } @Getter
@Setter
@ToString
static class TestEntity extends RowMapperAutoMapping<TestEntity> { private String id; private String name; private Integer age; private Long createTime; private String[] authors; private TestCategoryEntity[] testCategoryEntities; private List<TestCategoryEntity> testCategoryEntityList; @Override
protected List<Object> parsedValueIsArray(String fieldName, Object value) {
ArrayList<Object> objects = new ArrayList<>();
if("authors".equals(fieldName)){
String[] split = value.toString().split(",");
for (String s : split) {
objects.add(s);
}
}
return objects;
} @Override
protected List<Map<String, Object>> parsedValueIsArrayMap(String fieldName, Object value) {
ArrayList<Map<String, Object>> maps = new ArrayList<>();
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("id","小飞机_id");
hashMap.put("name","小飞机撞大象");
maps.add(hashMap); hashMap = new HashMap<>();
hashMap.put("id","小火车_id");
hashMap.put("name","小火车开飞机");
maps.add(hashMap);
return maps;
}
} @Data
static class TestCategoryEntity{ private String id; private String name; } static class TestResultSet extends JdbcRowSetImpl { private Map<String,Object> map = new HashMap<>(); public TestResultSet() {
map.put("id","001_id");
map.put("name","我是iemo");
map.put("age",25);
map.put("createTime",System.currentTimeMillis());
map.put("authors","小王作者,小恶魔作者");
map.put("testCategoryEntities","001:喜哦,002:小王");
} @Override
public Object getObject(String columnLabel) throws SQLException {
return map.get(columnLabel);
}
}
}

这是反射工具类,可以获取范围内的方法的字段列表,没有加锁,当并发高的情况下,可能会有问题吧,后期优化即可,每个类的反射出的字段都会进行缓存下来,方便下次直接返回

package cn.dmahz.utils;

import cn.dmahz.anno.IgnoreField;
import cn.dmahz.anno.ManyChild;
import cn.dmahz.anno.OneParent;
import cn.dmahz.anno.PrimaryId;
import cn.dmahz.excep.*;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.annotation.*;
import org.springframework.util.ReflectionUtils; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; @Slf4j
public class MyReflectUtils { private static final Field[] ARRAY_FIELDS = new Field[0]; private static final Map<String, Map<String, Field>> CACHE_FIELD = new ConcurrentHashMap<>();
private static final Map<String, Map<String, Field>> CACHE_AUDIT_FIELD = new ConcurrentHashMap<>(); /*锁对象实例*/
private static final Object CACHE_LOCK = new Object();
private static final Object CACHE_AUDIT_LOCK = new Object(); private static final Map<String, Map<String, Method>> CACHE_METHOD = new ConcurrentHashMap<>(); public static void main(String[] args) {
Method createBy = getMethodInMapper("cn.dmahz.dao.mapper.RelatedBookCategoryMapper.test_save");
System.out.println(createBy); System.out.println(Boolean.class.getSimpleName()); } /**
* 获取映射器的中的方法,仅适用于Mapper接口中的方法
* @param mapperId 例如:cn.dmahz.dao.mapper.RelatedBookCategoryMapper.test_save
* @return
*/
public static Method getMethodInMapper(String mapperId){
int lastIndexOf = mapperId.lastIndexOf(".");
// 包名.类名
String classFullName = mapperId.substring(0,lastIndexOf);
// 方法名
String methodName = mapperId.substring(lastIndexOf + 1);
return getMethodInInterface(classFullName,methodName);
} /**
* 获取指定接口的方法对象
* @param className 类全路径字符串;例如:class.getName()
* @param methodName 方法名称
* @return
*/
@SneakyThrows
public static Method getMethodInInterface(String className, String methodName){
Class<?> cls = Class.forName(className); String clsName = cls.getName();
if(!CACHE_METHOD.containsKey(clsName)){
CACHE_METHOD.put(clsName,new ConcurrentHashMap<>());
}
Map<String, Method> methodMap = CACHE_METHOD.get(clsName);
if(!methodMap.isEmpty()){
return methodMap.get(methodName);
}else {
Class<?> targetCls = cls;
Method targetMethod = null;
do {
Method[] declaredMethods = targetCls.getDeclaredMethods();
for (Method method:declaredMethods){
String name = method.getName();
if(!methodMap.containsKey(name)){
if(name.equals(methodName))
targetMethod = method;
methodMap.put(name,method);
}
}
} while (targetCls.getInterfaces().length> 0 && (targetCls = targetCls.getInterfaces()[0]) != null);
return targetMethod;
}
} /**
* 获取cls中的全部的审计字段
*
* @param cls
* @return
*/
public static Field[] getAllAuditFields(Class<?> cls){
String auditClsKey = cls.getName();
if(!CACHE_AUDIT_FIELD.containsKey(auditClsKey)) {
synchronized (CACHE_AUDIT_LOCK) {
if(CACHE_AUDIT_FIELD.containsKey(auditClsKey)){
return CACHE_AUDIT_FIELD.get(auditClsKey).values().toArray(ARRAY_FIELDS);
} else {
ConcurrentHashMap<String, Field> fieldMap = new ConcurrentHashMap<>(7);
Field[] allFields = getAllFields(cls);
for (Field field : allFields) {
if (field.isAnnotationPresent(CreatedBy.class) || field.isAnnotationPresent(CreatedDate.class)
|| field.isAnnotationPresent(LastModifiedBy.class) || field.isAnnotationPresent(LastModifiedDate.class)
|| field.isAnnotationPresent(Id.class)) {
fieldMap.put(field.getName(), field);
}
}
CACHE_AUDIT_FIELD.put(auditClsKey, fieldMap);
}
}
}
return CACHE_AUDIT_FIELD.get(auditClsKey).values().toArray(ARRAY_FIELDS);
} /**
* 获取除Object以外的所有字段数组
* @param cls
* @return
*/
public static Field[] getAllFields(Class<?> cls){
return getAllFields(cls, null);
} /**
* 获取截至endClass的所有字段列表,忽略Object的所有字段
* @param cls 实体类对象
* @param endClass 停止类,包含当前类所属字段
* @return
*/
public static Field[] getAllFields(Class<?> cls,Class<?> endClass){
Class<?> targetClass = cls;
Map<String, Field> cacheField = getCacheField(targetClass.getName());
if(cacheField.isEmpty()){
do {
Field[] declaredFields = targetClass.getDeclaredFields();
for(Field field:declaredFields){
field.setAccessible(true);
cacheField.put(field.getName(),field);
}
}while ((targetClass = targetClass.getSuperclass()) != null &&
(!(endClass != null && targetClass.isAssignableFrom(endClass)) && !targetClass.isAssignableFrom(Object.class))
);
}
return cacheField.values().toArray(ARRAY_FIELDS);
} /**
* 获取当前类中指定字段名称的对象
* @param cls
* @param fieldName
* @return
*/
public static Field getDeclaredFields(Class<?> cls,String fieldName){
Class<?> targetClass = cls;
Map<String, Field> cacheField = getCacheField(targetClass.getName());
if(cacheField.containsKey(fieldName)){
return cacheField.get(fieldName);
}
do {
Field declaredField = null;
try {
declaredField = targetClass.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
// 这里不处理异常
}
if(declaredField != null){
ReflectionUtils.makeAccessible(declaredField);
putCacheField(cls.getName(),fieldName,declaredField);
return declaredField;
}
}while ((targetClass = targetClass.getSuperclass()) != null && !targetClass.isAssignableFrom(Object.class));
return null;
} private static void putCache(String clsName,Map<String,Field> fieldMap){
Map<String, Field> cacheField = getCacheField(clsName);
cacheField.putAll(fieldMap);
} private static void putCacheField(String clsName,String fieldName,Field field){
Map<String, Field> cacheField = getCacheField(clsName);
cacheField.put(fieldName,field);
} private static Map<String,Field> getCacheField(String clsName){
Map<String, Field> stringFieldMap = CACHE_FIELD.get(clsName);
if(ObjectUtils.isEmpty(stringFieldMap)){
stringFieldMap = new ConcurrentHashMap<>(7);
CACHE_FIELD.put(clsName,stringFieldMap);
}
return stringFieldMap;
} public static String convertGetMethodName(Field field){
char[] chars = field.getName().toCharArray();
chars[0] = String.valueOf(chars[0]).toUpperCase().toCharArray()[0];
if(boolean.class.isAssignableFrom(field.getType())){
return "is".concat(String.valueOf(chars));
}
return "get".concat(String.valueOf(chars));
} public static String convertSetMethodName(Field field){
char[] chars = field.getName().toCharArray();
chars[0] = String.valueOf(chars[0]).toUpperCase().toCharArray()[0];
return "set".concat(String.valueOf(chars));
} public static <T,VO> VO convertToVO(T source,Class<VO> target){
if(source == null){
return null;
}
return doConvertToVO(source,target,null);
} /**
* 转换为VO对象
* @param sourceList
* @param target
* @return
*/
public static <T,VO> List<VO> convertToVO(List<T> sourceList,Class<VO> target){
final Field[] allFields = getAllFields(target);
List<VO> voList = sourceList.parallelStream().map(source -> doConvertToVO(source,target,allFields)).filter(Objects::nonNull).sequential().collect(Collectors.toList());
return voList;
} /**
* 将源源对象转换成VO实体对象,相同字段则进行赋值
* @param source
* @param target
* @param targetFields
* @param <T>
* @param <VO>
* @return
*/
private static <T,VO> VO doConvertToVO(T source,Class<VO> target,Field[] targetFields){
Field[] allFields = targetFields;
if(allFields == null){
allFields = getAllFields(target);
}
VO vo = null;
try {
vo = target.newInstance();
for (Field field : allFields) {
ReflectionUtils.makeAccessible(field);
if (!writePrimaryIdField(source, vo, field) && !writeOneParentField(source, vo, field) && !writeManyChildField(source, vo, field)) {
writeOrdinaryField(source,source.getClass(), vo, field);
}
}
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return vo;
} /**
* 将目标实体以父子关系链接起来
* @param <T>
* @param sourceList 源对象列表
* @param targetCls 目标Class
* @throws IllegalAccessException
* @throws InstantiationException
* @return
*/
public static <T> List<T> linkRelationshipTree(List<?> sourceList, Class<T> targetCls) { List<CombinationData> combinationDataList = new ArrayList<>(); HashMap<String, T> resultMap = new HashMap<>(sourceList.size()); HashMap<String, CombinationData.Child> childHashMap = new HashMap<>(sourceList.size()); boolean parentMode = false;
boolean childMode = false; Set<String> cacheFieldSignature = new HashSet<>(); for (Object source : sourceList) {
cacheFieldSignature.clear();
Class<?> sourceClass = source.getClass();
T newInstance;
try {
newInstance = targetCls.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
CannotInstantiationException cannotInstantiationException = new CannotInstantiationException("不能实例化此对象:" + targetCls.getName());
cannotInstantiationException.addSuppressed(e);
throw cannotInstantiationException;
} CombinationData combinationData = new CombinationData();
combinationData.setSource(source);
combinationData.setTarget(newInstance); ReflectionUtils.doWithFields(targetCls,field -> {
ReflectionUtils.makeAccessible(field); String fieldSignature = field.getType().getTypeName().concat("->").concat(field.getName());
if(cacheFieldSignature.contains(fieldSignature)){
return;
} /**
* 当字段不是被 @PrimaryId、@OneParent、@MaryChild 标注的话,会抛出异常
*/
if (!writePrimaryIdField(sourceClass, combinationData, field) && !writeOneParentField(source, sourceClass, combinationData, field) && !writeManyChildField(combinationData, source, sourceClass, field)) {
writeOrdinaryField(source, sourceClass, newInstance, field);
} cacheFieldSignature.add(fieldSignature); }, ReflectionUtils.COPYABLE_FIELDS);
String primaryIdValue = combinationData.getIdValue(); resultMap.put(primaryIdValue,newInstance); CombinationData.Child child = combinationData.getChild();
if(ObjectUtils.isNotEmpty(child)){
childHashMap.put(primaryIdValue,child);
} //判断模式
if(ObjectUtils.isNotEmpty(combinationData.getParent())){
parentMode = true;
}
if(ObjectUtils.isNotEmpty(combinationData.getChild())){
childMode = true;
} combinationDataList.add(combinationData);
} if(parentMode && childMode){
throw new CircularReferenceException(targetCls.getSimpleName().concat("循环引用异常,请使用 {@OneParent|@ManyChild} 其中一个注解进行标识"));
} Collection<T> collection = processParseConstituteTree(parentMode, childMode, combinationDataList, resultMap, childHashMap); return Collections.unmodifiableList(new ArrayList<>(collection));
} @ToString
private static class CombinationData {
/**
* 提取数据的源对象
*/
@Getter
@Setter
private Object source; /**
* 设置数据的目标对象
*/
@Getter
@Setter
private Object target; /**
* 源对象的主键ID
*/
@Getter
private Field sourcePrimaryIdField; @Getter
private Field targetPrimaryIdField; /**
* 当前target和source对应的主键id值
*/
private Object idValue; public <T> T getIdValue(){
return (T) idValue;
} /**
* 设置主键ID字段
* @param sourceField 源主键ID字段
* @param targetField 目标主键ID字段
*/
public void setPrimaryIdField(Field sourceField,Field targetField){
this.sourcePrimaryIdField = sourceField;
this.targetPrimaryIdField = targetField;
try {
Object o = CombinationData.this.sourcePrimaryIdField.get(source);
CombinationData.this.targetPrimaryIdField.set(target,o);
this.idValue = o;
} catch (IllegalAccessException e) {
throw new IllegalAccessObjectException("非法访问对象字段");
}catch (NullPointerException e){
throw new NullPointerException("未提供 @PrimaryId 标注主键ID字段");
}
} @Getter
private Parent parent; public Parent newInstanceParent(){
if(ObjectUtils.isEmpty(this.parent)){
this.parent = new Parent();
}
return parent;
} private class Parent { /**
* 目标对象的父字段对象
*/
@Getter
@Setter
private Field targetParentField; @Getter
private Type targetTypes; /**
* 源对象的父ID值
*/
@Getter
@Setter
private Object parentId; public void setTargetParentField(Field targetParentField) {
this.targetParentField = targetParentField;
this.targetTypes = targetParentField.getGenericType();
} public void setTargetParentField(Object value) throws IllegalAccessException {
targetParentField.set(CombinationData.this.target,value);
} } @Getter
private Child child;
public Child newInstanceChild(){
if(ObjectUtils.isEmpty(this.child)){
this.child = new Child();
}
return child;
} private class Child { /**
* 当前子属性集合对象的字段,最终要往这里添加值
*/
@Getter
private Field targetField; /**
* 父ID值,后期进行计算
*/
@Getter
@Setter
private Object parentId; /**
* 当前对象对应的子ID集合,
* 需要反向思考父子关系
*/
@Getter
private List<String> childIdList = new ArrayList<>(); public void addChildId(String childId){
childIdList.add(childId);
} public void setTargetField(Field targetField) throws IllegalAccessException {
this.targetField = targetField;
//设置泛型的参数化类型
Type genericType = targetField.getGenericType();
ParameterizedType parameterizedType = (ParameterizedType) genericType;
Type typeArgument = parameterizedType.getActualTypeArguments()[0];
this.genericType = typeArgument;
//获取目标对象的子集合对象
Object o = null;
try {
o = targetField.get(CombinationData.this.target);
} catch (IllegalAccessException e) {
e.printStackTrace();
} if(ObjectUtils.isEmpty(o)){
o = new ArrayList<>();
this.targetField.set(CombinationData.this.target,o);
} this.list = (List<Object>) o;
} /**
* 目标对象的子集合属性引用
*/
private List<Object> list; /**
* 泛型的类型
*/
private Type genericType; public void addChild(Object value){
Class<?> genericType = (Class<?>) this.genericType;
if(genericType.isAssignableFrom(value.getClass())){
list.add(value);
} else {
throw new TypeNotMatchException(String.format("提供的数据类型为:%s;需要的类型:%s",value.getClass(),this.genericType.getClass()));
}
}
} } /**
* 写入普通字段
*/
private static boolean writeOrdinaryField(Object source,Class<?> sourceClass,Object target ,Field field) throws IllegalAccessException {
//是否需要忽略当前字段,只有目标字段作为普通字段时才具备此效果
if(field.isAnnotationPresent(IgnoreField.class)){
return true;
}
String fieldName = field.getName();
Field f = getDeclaredFields(sourceClass,fieldName);
if(ObjectUtils.isEmpty(f)){
log.debug("源对象[{}] -> 字段[{}] 不存在",sourceClass.getName(),fieldName);
// throw new UnableProcessThis("无法处理当前字段(如果需要忽略,请使用@IgnoreField注解在 ["+target.getClass().getName()+"] 中进行标注):"+field.toGenericString());
return false;
}else {
Object srcValue = f.get(source);
field.set(target, srcValue);
return true;
}
} private static boolean writePrimaryIdField(Class<?> sourceClass,CombinationData combinationData,Field field){
if (field.isAnnotationPresent(PrimaryId.class)){
Field f = getDeclaredFields(sourceClass, field.getName());
combinationData.setPrimaryIdField(f,field);
return true;
}
return false;
} private static boolean writePrimaryIdField(Object source,Object target ,Field targetField) throws IllegalAccessException {
if (targetField.isAnnotationPresent(PrimaryId.class)){
Field f = getDeclaredFields(source.getClass(), targetField.getName());
targetField.set(target,f.get(source));
return true;
}
return false;
} private static boolean writeOneParentField(Object source,Class<?> sourceClass,CombinationData combinationData,Field field){
OneParent oneParent = AnnotationUtils.getAnnotation(field, OneParent.class);
if(ObjectUtils.isNotEmpty(oneParent)){
Field f = MyReflectUtils.getDeclaredFields(sourceClass,oneParent.parentIdValueFieldName());
Object value = ReflectionUtils.getField(f, source);
CombinationData.Parent parent = combinationData.newInstanceParent();
parent.setParentId(value);
parent.setTargetParentField(field);
return true;
}
return false;
} private static boolean writeOneParentField(Object source,Object target ,Field targetField) throws IllegalAccessException {
OneParent oneParent = AnnotationUtils.getAnnotation(targetField, OneParent.class);
if(ObjectUtils.isNotEmpty(oneParent)){
Field f = MyReflectUtils.getDeclaredFields(source.getClass(),oneParent.parentIdValueFieldName());
Object value = ReflectionUtils.getField(f, source);
targetField.set(target,value);
return true;
}
return false;
} private static boolean writeManyChildField(CombinationData combinationData,Object source,Class<?> sourceClass,Field field) throws IllegalAccessException {
ManyChild manyChild = AnnotationUtils.getAnnotation(field, ManyChild.class);
if(ObjectUtils.isNotEmpty(manyChild)){
//从源对象获取父ID
Field f = MyReflectUtils.getDeclaredFields(sourceClass,manyChild.parentIdValueFieldName());
Object value = ReflectionUtils.getField(f, source);
CombinationData.Child child = combinationData.newInstanceChild();
child.setTargetField(field);
child.setParentId(value);
return true;
}
return false;
} private static boolean writeManyChildField(Object source,Object target ,Field targetField) throws IllegalAccessException {
ManyChild manyChild = AnnotationUtils.getAnnotation(targetField, ManyChild.class);
if(ObjectUtils.isNotEmpty(manyChild)){
//从源对象获取父ID
Field f = MyReflectUtils.getDeclaredFields(source.getClass(),manyChild.parentIdValueFieldName());
Object value = ReflectionUtils.getField(f, source);
targetField.set(target,value);
return true;
}
return false;
} /**
* 将列表数据构成树
* @param finalParentMode
* @param finalChildMode
* @param combinationDataList
* @param rootMap
* @param childHashMap
* @param <T>
* @return
*/
private static <T> Collection<T> processParseConstituteTree(final boolean finalParentMode,final boolean finalChildMode,
List<CombinationData> combinationDataList,
HashMap<String, T> rootMap,
HashMap<String, CombinationData.Child> childHashMap
){
//排除的ID集合,从resultMap中根据key进行删除
final List<Object> excludeIdList = new ArrayList<>(); combinationDataList.forEach(combinationData -> {
//处理父级关系
CombinationData.Parent parent = combinationData.getParent();
if(ObjectUtils.isNotEmpty(parent)){
Object parentId = parent.getParentId();
T t = rootMap.get(parentId);
if(ObjectUtils.isNotEmpty(t)){
try {
combinationData.getParent().setTargetParentField(t);
if(finalParentMode && !finalChildMode){
excludeIdList.add(parentId);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}); if(finalChildMode){
excludeIdList.clear();
} //解析子级列表关系
childHashMap.forEach((id, child) -> {
Object parentId = child.getParentId();
if(ObjectUtils.isNotEmpty(parentId)){
CombinationData.Child c = childHashMap.get(parentId);
if(ObjectUtils.isNotEmpty(c)){
T currentT = rootMap.get(id);
if(ObjectUtils.isEmpty(currentT)){
throw new InvalidPrimaryIdValueException("无效主键ID值异常;不能找到指定主键值对应的实体;主键ID值为:".concat(id));
}
c.addChild(currentT);
//这里需要记录排除的ID列表
if(finalChildMode){
excludeIdList.add(id);
}
}
}
}); //移除 resultMap 里的指定ID键对象
// 如果有子级列表关系存在,则只返回首层,否则,返回最后一个子集
excludeIdList.forEach(rootMap::remove); return rootMap.values();
} }

特殊的就是

org.apache.commons.beanutils.ConvertUtils;  这个是commons包中的,来源去maven repo查询即可

如果有问题留言讨论

使用SpringDataJdbc的@Query注解实现自动映射结果集 ----- RowMapper接口的更多相关文章

  1. SpringBoot注解把配置文件自动映射到属性和实体类实战

    SpringBoot注解把配置文件自动映射到属性和实体类实战 简介:讲解使用@value注解配置文件自动映射到属性和实体类 1.配置文件加载 方式一 1.Controller上面配置 @Propert ...

  2. Mybaits 源码解析 (八)----- 全网最详细,没有之一:结果集 ResultSet 自动映射成实体类对象(上篇)

    上一篇文章我们已经将SQL发送到了数据库,并返回了ResultSet,接下来就是将结果集 ResultSet 自动映射成实体类对象.这样使用者就无需再手动操作结果集,并将数据填充到实体类对象中.这可大 ...

  3. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_2-7.接口配置文件自动映射到属性和实体类配置

    笔记 7.接口配置文件自动映射到属性和实体类配置     简介:使用@value注解配置文件自动映射到属性和实体类 1.添加 @Component或者Configuration 注解:        ...

  4. 反射+自定义注解---实现Excel数据列属性和JavaBean属性的自动映射

    简单粗暴,直奔主题.   需求:通过自定义注解和反射技术,将Excel文件中的数据自动映射到pojo类中,最终返回一个List<pojo>集合? 今天我只是通过一位使用者的身份来给各位分享 ...

  5. 通过JPA注解映射视图的实体类 jpa 视图 无主键 @Query注解的用法(Spring Data JPA) jpa 使用sql语句

    参考: https://blog.csdn.net/qq465235530/article/details/68064074 https://www.cnblogs.com/zj0208/p/6008 ...

  6. 使用Java注解开发自动生成SQL

    使用注解开发的好处就是减少配置文件的使用.在实际过程中,随着项目越来越复杂,功能越来越多,会产生非常多的配置文件.但是,当配置文件过多,实际维护过程中产生的问题就不容易定位,这样就会徒劳的增加工作量. ...

  7. 【spring boot】14.spring boot集成mybatis,注解方式OR映射文件方式AND pagehelper分页插件【Mybatis】pagehelper分页插件分页查询无效解决方法

    spring boot集成mybatis,集成使用mybatis拖沓了好久,今天终于可以补起来了. 本篇源码中,同时使用了Spring data JPA 和 Mybatis两种方式. 在使用的过程中一 ...

  8. 【Spring Data 系列学习】Spring Data JPA @Query 注解查询

    [Spring Data 系列学习]Spring Data JPA @Query 注解查询 前面的章节讲述了 Spring Data Jpa 通过声明式对数据库进行操作,上手速度快简单易操作.但同时 ...

  9. Hibernate使用注解进行ORM映射实例

    在上一篇博客中,我们通过xml配置文件进行实体类和表的映射,但是近两年来有更多的项目对一些比较稳定的实体类使用了注解进行ORM映射,这样使得编程更加简洁.简单.其实使用注解进行ORM映射和使用xml进 ...

随机推荐

  1. [自动化]ssh自动化免密访问配置

    ssh简介 SSH(Secure Shell)是一种通信加密协议,加密算法包括:RSA.DSA等 RSA:非对称加密算法,其安全性基于极其困难的大整数的分解(两个素数的乘积): DSA:也是非对称加密 ...

  2. kafka在linux下安装

    简介 Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据. 相关术语(参考百度百科) Broker Kafka集群包含一个或多个服务器,这种服务器被称为brok ...

  3. m0n0wall安装教程

    m0n0wall的镜像链接:https://pan.baidu.com/s/1soIw7cS1Tv180fbo2655UA 提取码:dpon 一.新建虚拟机 新建虚拟机我想大家都会,详细步骤我就不陈述 ...

  4. 3款自助型BI分析平台功能盘点,帮助你预测商业发展方向

    在快速发展的今天,商业智能BI已经不同于传统的商业智能BI,商业智能BI已经逐渐转变为自助和业务主导的模式,自助BI分析平台应运而生,自助BI分析平台逐渐成为许多企业的选择. 自助式BI分析平台与传统 ...

  5. bi报表是什么意思,有什么优势?

    ​BI也叫商业智能系统,BI报表也就是将企业中现有数据进行整合并提供出的报表,商业智能描述了一系列的概念和方法,通过应用基于事实的支持系统来辅助商业决策的制定. 商业智能技术提供使企业迅速分析数据的技 ...

  6. 【C# 基础概念】抽象类、密封类及类成员

    使用 abstract 关键字可以创建不完整且必须在派生类中实现的类和 class 成员. 使用 sealed 关键字可以防止继承以前标记为 virtual 的类或某些类成员. abstract修饰符 ...

  7. weblogic集群自动批量化补丁升级

    转至:http://blog.itpub.net/28833846/viewspace-2726722/ 一.前言介绍 Weblogic是一种基于J2EE架构的中间件,用于开发.集成.部署和管理大型分 ...

  8. AcWing 215. 破译密码

    传送门 思路:gcd(a,b)=k<=>gcd(a/k,b/k)=1,令x=a/k,y=b/k,则问题变为问x<=a/d,y<=b/d有多少(x,y)满足gcd(x,y)=1. ...

  9. Leaflet:控件Control相关

    Leaflet官方文档中只给出了4种控件:Zoom.Attribution.Layers.Scale:它们都是继承自Control类,具体可以参考Control. Control Zoom.Scale ...

  10. mysql-8.0.12 安装使用教程

    Microsoft Windows [版本 10.0.15063] (c) 2017 Microsoft Corporation.保留所有权利. C:\WINDOWS\system32>D: D ...