工作中用到了原生hibernate,得自己封装List<String,Map<Object,Objec>>,贴上代码。
/**
*
* @Author: Leon.Liu
* @Version: 2018-8-13
* @Explain:
* 重新改写了一下代码...原来需要用包名..现在不用了...
*/
public class LeonBatis<T> {
private T t;
public List<T> mapper(List<Map<Object,Object>> listMap,Map<String,Object> resultMap){
if(listMap==null||listMap.size()==0)return null;
return AssignBean(null,listMap,resultMap);
}
public LeonBatis() {
super();
}
public LeonBatis(T t) {
super();
this.t = t;
}
/**
*
* MyBatis的作用是自定义sql字段,查询数据库,以及自动封装对象,
*
* 那我的LeonBatis,先做的就是自动封装对象,其他的功能实现,等待以后需要自己添加
*
* @see 根据查询出来的自定义字段,进行对象封装,因为会有多个自定义对象,在一个查询结果里,然后这些查询结果都是有连接关系的,比如是当前查询结果的子之类的...
* @param Package 类的全路径,会有多个自定义路径 例:cn.softcore.com.bean.TopoBean
* @param listMap 数据库中查询出来的所有数据
* @param resultMap
* 第一种情况,key是对象的属性
* value是sql查询的别名
* 通过key 就是field 获得sql 别名,然后获取map中别名下的查询到的数据,赋值给field
*
* 例子 select t1.id kkid , t1.name kkname from t t1
* 查询出来的数据如下
* kkid kkname
* 1 小明
* 假如现在的现在的对象是student,对象的属性是id和name
* 那我们需要将kkid和kkname的值赋给id和name
* 这个时候直接通过属性是获取不到的值的,因为两个名称不一样
* 通过resultMap,id对应查询出来kkid,name对应查询出来kkname
* 将值赋给对应的属性,这样对象里就有查询出来的值了...
*
* 通过类的pid属性,获得PPID别名,然后通过PPID获得sql查询到的值,在赋值给PID
*
* 第二种情况,key是bean的field,不过是别的类,比如Area什么的,或者是List<Bean>之类的...
* value就是属性类的全路径包名,通过全路径包名获取到一个全新的resultMap,在通过第一种情况进行赋值.
* 然后将属性类赋值到类的属性中
*
* 第三种情况,如果resultMap为null,则执行反射属性执行
* Tips:
* 相对于MyBatis的resultMap
* 因为一个对象,对应多个自定义字段,所以每个自定义字段,都属于同一个类的全路径下
* @TODO:
* MyBatis中,会有多个对象自定义封装,比如一个对象,下面list<Son> ,这个时候需要查询出来对象,还要进行对象封装,以及赋值给子
*
* [əˈsaɪn] assign
*/
private List AssignBean(String packageName,List<Map<Object,Object>> listMap,Map<String,Object> resultMap){
List list = null;
if(packageName==null)list = new ArrayList<T>();
else list = new ArrayList<Object>();
//1.获取无参构造和方法
Map<String,Object> map = forNameClassGetNonParameterConstructor(packageName);
//1.1 获取无参构造
Constructor Constructor = (Constructor)map.get("Constructor");
//1.2 获取所有属性
Field[] fields = (Field[])map.get("fields");
//1.3 根据无参构造方法实例化对象
Object object = NonParameterConstructorToObject(Constructor);
//2.0 循环遍历查询出的完整数据listMap
for (Map<Object, Object> objectMap : listMap) {
//这个时候想要取数据,需要将 objectMap 对应的 key 找出来
if(resultMap!=null){
objectMapToObjectByResultMap(object,objectMap,fields,resultMap);
}
else{
objectMapToObjectByField(object,fields,objectMap);
}
// 8.循环遍历完所有属性,将数据完整Object添加到list中
//2.1 添加到list中
if(packageName==null)list.add((T)object);
else list.add(object);
//2.2 实例化新的obj,参加下一次循环
object = NonParameterConstructorToObject(Constructor);
}
return list;
}
/**
*
* @param objectMap 单条查询数据
* @param fields 类的属性
* @param resultMap 查询结果属性对应的字段
* @param obj 传递过来的对象,封装完数据,需要返回
* @For:
* 根据resultMap来封装对象
*/
private void objectMapToObjectByResultMap(Object obj,Map<Object, Object> objectMap,Field[] fields,Map<String,Object> resultMap){
String BEANPACKAGEFLAG = ".";//如果在一个属性里出现里. 那就是下一个类的象征了...
String ListType = "interface java.util.List";
String fieldName = null; // 类的属性名称
Object fieldValue = null; // 类的属性值
String fieldType = null; // 属性类型
String sqlFieldName = null; //属性对应的sql别名
//1.先遍历类的属性
for (Field field : fields) {
fieldName = field.getName(); //类的属性名
fieldType = field.getType().toString(); //类的属性类型Type
//resultMap从,放入属性名的key,取出对应sql语句中的别名字段,拿到别名字段,开始做下一步操作
//做一个验证,
//第一,不是所有属性都会赋值,so遇到不需要赋值的,直接跳过
if(resultMap.get(fieldName)==null)continue;
sqlFieldName = resultMap.get(fieldName).toString();
//2. 别名字段下数据不为空.则要进行验证是否为其他包... 例:cn.softcore.com.bean.TopoBean
//2.1 首先看下别名字段是不是下一个对象的包名,如果是,进行下一步操作
if(sqlFieldName.indexOf(BEANPACKAGEFLAG)!=-1){
//如果别名里包含. 说明是一个包..需要进行下一步的操作了...
List<Map<Object, Object>> arrayList = new ArrayList<>();
arrayList.add(objectMap);
//2.2 通过递归将当前数据,这个时候需要知道当前属性的类型,如果是单个类型,将类型list.get(0)赋值,若不是,则将list赋值进去
List<Object> list = AssignBean(sqlFieldName,arrayList,(Map<String,Object>)resultMap.get(sqlFieldName));
//将resultMap中数据删除
resultMap.remove(sqlFieldName);
//2.3 当前是一个类型是一个类名,如果是list
if(fieldType.equals(ListType)){
//赋值
invokeSet(obj, fieldName, list, fieldType);
}else{
//不是list,是一个实体类,直接传一个单独的类过去赋值
invokeSet(obj, fieldName, list.get(0), fieldType);
}
continue;
}
fieldValue = objectMap.get(sqlFieldName.toUpperCase());//从map中取出别名字段下的数据
if (fieldValue == null)continue; // 如果值为空,直接开始下一个循环
// 普通属性,直接赋值
invokeSet(obj, fieldName, fieldValue, fieldType);
}
}
/**
* 根据无参构造方法实例化对象
*/
private Object NonParameterConstructorToObject(Constructor constructor){
Object object = null;
try {
object = constructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return object;
}
/**
* @param Package 类的全路径包名
* @return
* 根据全路径包名
* 获取无参构造方法
* 以及所有属性
*/
private Map<String,Object> forNameClassGetNonParameterConstructor(String packageName){
Map<String,Object> map = new HashMap<>();
Class c = null;
try {
if(packageName==null)c = t.getClass();
else c = Class.forName(packageName);
Constructor Constructor = getNonParameterConstructor(c.getConstructors());
Field[] fields = c.getDeclaredFields();
map.put("Constructor",Constructor);
map.put("fields",fields);
}catch(Exception e){
e.printStackTrace();
}
return map;
}
/**
* 根据类的属性进行封装数据
*/
private void objectMapToObjectByField(Object obj,Field[] fields,Map<Object, Object> m){
String fieldName = null;// 类的属性名称
Object fieldValue = null;// 类的属性值
String fieldType = null;// 属性类型
for (Field field : fields) {
fieldName = field.getName(); // 类的属性名
fieldValue = m.get(fieldName.toUpperCase());// 从map中取出数据
fieldType = field.getType().toString(); // 类的属性类型Type
if (fieldValue == null)
continue; // 如果值为空,直接开始下一个循环
// 7.值不为空,反射执行方法
invokeSet(obj, fieldName, fieldValue, fieldType);
}
}
/**
* 获取无参构造方法
*/
private Constructor getNonParameterConstructor(Constructor[] c) {
for (Constructor constructor : c) {
if (constructor.getParameterTypes().length == 0) {
return constructor;
}
}
return null;
}
/**
*
* @param o 当前对象
* @param fieldName 属性名
* @param value 属性值
*
* 根据传递过来的对象和值,进行赋值,执行反射方法
*/
private void invokeSet(Object o, String fieldName, Object value,String fieldType) {
Method method = getSetMethod(o.getClass(), fieldName);
try {
method.invoke(o, new Object[] { caseFieldType(fieldType,value)});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param fieldType 属性类型
* @param value 属性值
* @return 返回一个已经实例化的对象
* @For:
* 根据属性类型,
* 将属性转换成相应的对象
* Tips:
* 对于byte和short,
* 因为使用频率实在太低,
* 而且暂时还不知道怎么转换,
* 所以不进行转换...
*/
private Object caseFieldType(String fieldType,Object value){
if(fieldType.indexOf("String")!=-1){
return value.toString();
}else if(fieldType.equals("byte") || fieldType.indexOf("Byte")!=-1){
return value;
}else if(fieldType.equals("short") || fieldType.indexOf("Short")!=-1){
return value;
}else if(fieldType.equals("long")|| fieldType.indexOf("Long")!=-1){
return Long.valueOf(value.toString());
}else if((fieldType.equals("int") || fieldType.indexOf("Integer")!=-1) && fieldType.indexOf("interface")==-1){
return Integer.parseInt(value.toString());
}else if(fieldType.equals("double") || fieldType.indexOf("Double")!=-1){
return Double.parseDouble(value.toString());
}else if(fieldType.equals("char") || fieldType.indexOf("Character")!=-1){
return Character.valueOf((Character) value);
}else if(fieldType.equals("boolean") || fieldType.indexOf("Boolean")!=-1){
return Boolean.parseBoolean(value.toString());
}else if(fieldType.equals("float") || fieldType.indexOf("Float")!=-1){
return Float.parseFloat(value.toString());
}else if(fieldType.indexOf("Date")!= -1 ){
String date = value.toString();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ParsePosition pos = new ParsePosition(0);
return formatter.parse(date, pos);
}else if(fieldType.equals("interface java.util.List")){
return value;
}
//会有list吗?不会有噢~,因为查询的语句里不会冒出来一个list的
return value;
}
/**
* 反射set方法
*/
private Method getSetMethod(Class objectClass, String fieldName) {
try {
Class[] parameterTypes = new Class[1];
Field field = objectClass.getDeclaredField(fieldName);
parameterTypes[0] = field.getType();
StringBuffer sb = new StringBuffer();
sb.append("set");
sb.append(fieldName.substring(0, 1).toUpperCase());
sb.append(fieldName.substring(1));
Method method = objectClass.getMethod(sb.toString(), parameterTypes);
return method;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}