package com.yanzuoguang.db.impl; import com.yanzuoguang.dao.DaoConst; import com.yanzuoguang.dao.TableAnnotation; import com.yanzuoguang.db.ConfigDb; import com.yanzuoguang.util.base.MethodField; import com.yanzuoguang.util.base.ObjectHelper; import com.yanzuoguang.util.helper.StringHelper; import com.yanzuoguang.util.log.Log; import com.yanzuoguang.util.vo.MapRow; import org.springframework.beans.*; import org.springframework.dao.DataRetrievalFailureException; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.support.JdbcUtils; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * 将数据映射为结果 * * @author 颜佐光 */ public class AllBeanRowMapper<T> implements RowMapper<T> { /** * 需要映射的Class */ private Class<T> mappedClass; /** * 是否属于映射方式 */ private boolean isMapping = false; /** * 获取字段映射关系 */ private Map<String, MethodField> typeField; /** * 配置信息 */ private ConfigDb configDb; /** * 构造函数 * * @param mappedClass */ public AllBeanRowMapper(Class<T> mappedClass, ConfigDb configDb) { initialize(mappedClass); this.configDb = configDb; } /** * 初始化元素之间的映射关系 * * @param mappedClass the mapped class. */ protected void initialize(Class<T> mappedClass) { this.mappedClass = mappedClass; if (ObjectHelper.isSub(MapRow.class, mappedClass) || ObjectHelper.isSub(Map.class, mappedClass)) { isMapping = true; } else { Map<String, MethodField> temp = ObjectHelper.getTypeField(mappedClass); typeField = new HashMap<>(temp.size()); for (Map.Entry<String, MethodField> item : temp.entrySet()) { String name = item.getKey(); // 获取字段值 MethodField field = item.getValue(); // 获取名称 TableAnnotation annotation = null; if (field.getField() != null) { annotation = field.getField().getAnnotation(TableAnnotation.class); } else if (field.getGetMethod() != null) { annotation = field.getGetMethod().getAnnotation(TableAnnotation.class); } if (annotation != null && !StringHelper.isEmpty(annotation.value())) { name = annotation.value(); } String underscoredName = underscoreName(name); this.typeField.put(underscoredName, item.getValue()); } } } /** * convert a name in camelCase to an underscored name in lower case. * Any upper case letters are converted to lower case with a preceding underscore. * * @param name the string containing original name * @return the converted name */ public String underscoreName(String name) { return underscoreNameBase(name); } /** * 获取列明 * * @param name * @return */ private static String underscoreNameBase(String name) { if (!StringUtils.hasLength(name)) { return ""; } return name.toLowerCase().replace("_", ""); } /** * 将行进行转换 * * @param from * @return */ public static MapRow toLoweRow(MapRow from) { MapRow to = new MapRow(); for (Map.Entry<String, Object> key : from.entrySet()) { to.put(underscoreNameBase(key.getKey()), key.getValue()); } return to; } /** * 获取空值字段 * * @param from * @return */ public static Object getLoweRowField(MapRow from, String field) { field = underscoreNameBase(field); for (Map.Entry<String, Object> key : from.entrySet()) { if (underscoreNameBase(key.getKey()).equals(field)) { return key.getValue(); } } return null; } /** * Extract the values for all columns in the current row. * <p>Utilizes public setters and result setByType metadata. * * @see ResultSetMetaData */ @Override public T mapRow(ResultSet rs, int rowNumber) throws SQLException, TypeMismatchException { Assert.state(this.mappedClass != null, "Mapped class was not specified"); T mappedObject = BeanUtils.instantiate(this.mappedClass); ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); for (int index = 1; index <= columnCount; index++) { String column = JdbcUtils.lookupColumnName(rsmd, index); String underscoredName = underscoreName(column); if (this.isMapping) { Object value = JdbcUtils.getResultSetValue(rs, index); if (value instanceof Date) { value = JdbcUtils.getResultSetValue(rs, index, String.class); } ((Map) mappedObject).put(getCamelCase(column), value); } else if (!this.typeField.containsKey(underscoredName)) { continue; } else { MethodField pd = this.typeField.get(underscoredName); Class<?> type; if (pd.getField() != null) { type = pd.getField().getType(); } else { type = pd.getGetMethod().getReturnType(); } Object value = null; try { value = JdbcUtils.getResultSetValue(rs, index, type); if (configDb.isPrintMapper() && rowNumber == 0) { Log.info(AllBeanRowMapper.class, "Mapping column '%s' to property '%s' of type %s", column, pd.getName(), type); } ObjectHelper.setByType(mappedObject, pd, value); } catch (TypeMismatchException e) { if (value == null) { Log.info(AllBeanRowMapper.class, "Intercepted TypeMismatchException for row %d and column '%s' with " + "value %s when setting property '%s' of type %s on object: %s", rowNumber, column, StringHelper.EMPTY, pd.getName(), type, mappedObject); } else { throw e; } } catch (Exception ex) { throw new DataRetrievalFailureException("Unable to map column " + column + " to property " + pd.getName(), ex); } } } return mappedObject; } /** * 设置SameCase命名方式 * * @param column * @return */ private String getCamelCase(String column) { switch (configDb.getRowNameType()) { case DaoConst.ROW_NAME_TYPE_NO_CHANGE: break; case DaoConst.ROW_NAME_TYPE_CAMEL_CASE: default: column = StringHelper.getCamelCase(column); break; } return column; } /** * 缓存的处理类 */ private static Map<Class, Object> Cache = new HashMap<Class, Object>(); /** * 获取可以转化实体 * * @param cls 类型 * @param <T> 泛型类型 * @return 可转换的实体 */ public static <T extends Object> AllBeanRowMapper<T> getInstance(Class<T> cls, ConfigDb configDb) { if (!Cache.containsKey(cls)) { Cache.put(cls, new AllBeanRowMapper<T>(cls, configDb)); } AllBeanRowMapper<T> ret = (AllBeanRowMapper<T>) Cache.get(cls); return ret; } }