mybatis与反射实现对象封装

        在项目中经常要我们查询某张表的的部分字段,比如select emp_id,emp_name,...... from emp where xxx;诸如此类,在dao层的xml我们就可以这样定义:

 
    
    
    .........

dao接口层:

List> queryName() throws Exception;

此时mybatis便会自动将查出来的每一行结果字段通过key value的形式返回出来,key就是我自己定义的属性name,value就是具体查到的属性,还有就是mybatis支持两种返回结果:

  1.   这样会返回你需要的字段和该实体类没有被映射的字段,比如age你没去查,但由于你返回的是整个实体类,会去映射,映射不上就引用类型就是null,基本类型就是0或者false。

那我们不禁好奇,到底是怎样封装的呢?其实也很简单,就是拿到Map中每个key值的字段和类型,然后与实体类的字段与类型进行比较,然后通过反射实现set方法,实现一个对象的封装,具体看下面的demo。

package 反射;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * @author Heian
 * @time 19/09/26 10:29
 * @description: 反射实现Map转换Dto实体类
 */
public class MapToDto {


    public static Object MapConvertDto(Map map, Class cl) throws Exception{
        Object obj = cl.newInstance ();
        Field[] fields = cl.getDeclaredFields ();
        for (Field field : fields) {
            //筛选实体类属性为private的
            int num = field.getModifiers ();//返回修饰符
            String s = Modifier.toString (num);//对类成员变量进行解码,有点类似于序列化和反序列化
            if ("private".equals (s)){
                String fieldName = field.getName (); 
                if (map.containsKey (fieldName)){
                    Class fieldClass = map.get (fieldName).getClass ();//取得map中value的类型(基本数据类型存在自动装箱,此处需要转化,这是个坑切记)
                    Field f = null;
                    //因为每个基本数据类型的包装类比如Integer都会存在全局变量TYPE,所以可针对这点来判断是否是包装类
                    try {
                        f = fieldClass.getDeclaredField ("TYPE");
                    } catch (NoSuchFieldException e) {
                        //如果不存在此变量,则说明不是基本类型,do nothing
                    } catch (SecurityException e) {
                        e.printStackTrace ();
                    }
                    //取得map中Value的接口,防止传过来的是子类,而在实体类中成员中是父类,这里常用的就是ArrayList和List,所以下面就用这个举例
                    //比如 实体类是List map是ArrlyList  此时invoke就会报错,因为您传入的参数类型是子类,而实体是父类,参数类型不匹配
                    Class[] interfaces = fieldClass.getInterfaces ();
                    Class father = null;
                    for (Class interf : interfaces) {
                        if (interf.equals (List.class)){
                            father = interf;
                            break;
                        }
                    }
                    if (null != father){
                        Method method = cl.getDeclaredMethod (getFidldFuncName (fieldName), father);//拿到方法
                        method.invoke (obj,map.get(fieldName));
                    }else {
                        if (f == null) {
                            Method method = cl.getDeclaredMethod (getFidldFuncName (fieldName), fieldClass);
                            method.invoke (obj,map.get(fieldName));//interfClass是fieldClass的父类
                        }else {
                            List first = new ArrayList<> (Arrays.asList ("java.lang.Byte","java.lang.Short",
                                    "java.lang.Integer","java.lang.Long","java.lang.Float","java.lang.Double","java.lang.Character"));
                            List second = new ArrayList<> (Arrays.asList (byte.class,short.class,int.class,long.class,
                                    float.class,double.class,char.class));
                            for (int i = 0; i < first.size (); i++) {
                                if (first.get (i).equals (fieldClass.getName ())){
                                    Method method = cl.getDeclaredMethod (getFidldFuncName (fieldName), second.get (i));
                                    method.invoke (obj,map.get(fieldName));
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        return obj;
    }

    public static String getFidldFuncName(String filedStr){
        return "set" + filedStr.substring (0,1).toUpperCase () + filedStr.substring (1);
    }

    public static void main(String[] args) throws Exception {
        Map map = new HashMap<> ();
        map.put ("id",11);
        map.put ("name","jack");
        map.put ("list",new ArrayList(Arrays.asList ("1","2","3")));
        Stu s = (Stu) MapConvertDto (map, Stu.class);
        System.out.println (s);
    }


}

class Stu{
    private int id;
    private String name;
    private List list;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    @Override
    public String toString() {
        return "Stu{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", list=" + list +
                '}';
    }
}

备注:

  1. 此处需要注意,由于jdk1.5实现可基本数据类型的自动装箱与拆箱,如果你在实体类某个字段如id定义的是int类型,而Map中的key字段id是Integer则,调用获取方 cl.getDeclaredMethod (set方法名, 参数类型)则会抛出无法找到该方法而报错,因为你实体类方法存的是int,而你传来的确实integer,所以需要在手动拆箱。
  2. Field[] fields1 = cl.getFields ()  与  Field[] fields = cl.getDeclaredFields (); 前者是获取某个类的公有的public字段,包含父类;后者是获取当前类的所有成员变量(public、private、protected)
  3. cl.getMethod(String name, Class... parameterTypes)与getDeclaredMethod(String name, Class... parameterTypes),前者是获取公共的public,后者是获取所有的修饰符的方法

 

       

你可能感兴趣的:(Java高级)