• Beautils工具类实现的原理


    关于内省机制和反射机制请看这一篇博客【还没写完,在草稿中】。

    先说一下什么叫做 bean 属性,bean 属性指的是 get / set 方法后的名称,而不是类的属性:

    比如:

    private String username;   //bean属性指的不是这里的属性
    
    public String getUsername() {//而是指的这里get后面的名称
        return username;
    }
    
    public void setUsername(String username) {//这里的set后面的Username就是bean属性
       this.username = username;
    }

    Beanutils 工具它的底层是使用 java 内省(introspector)机制,而内省它的实现是依赖于 java 反射。

    1、直接使用反射实现 Beanutils 的功能:

    package online.msym.test;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    import org.junit.Test;
    
    import online.msym.bean.User;
    
    public class Demo {
    
        //使用反射来完成封装
        @Test
        public void fun1() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{
            //1.创建一个Map集合,模仿 request.getParameterMap() 获取的结果
            Map<String,String[]> map=new HashMap<String, String[]>();
            map.put("username", new String[]{"tom"});//注意,我这里put的是小写的username,虽然后面使用的是equalsIgnoreCase(),但是还是不妥,
            map.put("password", new String[]{"123"}); //这个错误由博友【圳(zhèn)】[这个字不会读… 1B5D8B8E ]找出。
           
    //2.创建一个User对象(User类中提供了get/set方法,toString方法)
            User user=new User();
           
    //3.将map集合中key的名称与user中bean属性一致的使用key对应的value封装到bean属性上。
           
    //3.1得到map中所有的key的set集合
            Set<String> keys=map.keySet();
           
    //3.2得到User类中所有的方法
            Method[] ms=user.getClass().getDeclaredMethods();   
           
    //3.3.判断所有方法名称是否与"set"+key的值相等(不区分大小写)
            for(String key:keys){
                String setMethodName
    ="set"+key; //此时,遍历的第一个setMethodName = setusername,所以后面的equals()需要忽略大小写。
               
    //3.4遍历所有的ms,并得到方法名称
                for(Method m:ms){
                    String methodName
    =m.getName();
                   
    if(setMethodName.equalsIgnoreCase(methodName)){ //我在这里,equalsIgnoreCase()
                       
    //3.5.使用method对象调用invoke方法将key对应的value值进行赋值
                        m.invoke(user, map.get(key)[0]); // user.setXxx(map.get(xxx))
                    }
                }
            }
           
    //4.输出
            System.out.println(user);
        }
    }

    3


    2、使用内省(introspector)的方式完成:

    package online.msym.test;
    
    import java.beans.BeanInfo;
    import java.beans.IntrospectionException;
    import java.beans.Introspector;
    import java.beans.PropertyDescriptor;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    import org.junit.Test;
    
    import online.msym.bean.User;
    
    public class Demo {
        // 使用内省来完成请求参数封装
        @Test
        public void fun2() throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
            // 1.创建一个Map集合,模仿request.getParameterMap()获取的结果
            Map<String, String[]> map = new HashMap<String, String[]>();
            map.put("username", new String[] { "tom" });
            map.put("password", new String[] { "123" });
            // 2.创建一个User对象
            User user = new User();
            // 3.得到一个BeanInfo对象
            BeanInfo bif = Introspector.getBeanInfo(User.class);
            // 4.得到所有属性描述器
            PropertyDescriptor[] pds = bif.getPropertyDescriptors();
            // 5.通过属性描述器得到读写方法
            for (PropertyDescriptor pd : pds) {
                Method writeMethod = pd.getWriteMethod();
                // 6.得到方法名称
                if (writeMethod != null) {
                  //System.out.println(pd.getName()); //得到bean属性名称
                    //System.out.println(writeMethod.getName()); //得到所有的set方法名称
                    String name=pd.getName();                
                  writeMethod.invoke(user, map.get(name)[0]);
                }
            }
            System.out.println(user);
        }
    }

    这个 Beanutils 工具类能实现大多数的 bean 数据的封装,但是也有不能被封装的,比如 Date 对象,当有 Date 类型的 bean 时,就需要自定义类型转换器了。

    表单:

    2

    下面是一个自定义的类型转换器:(将表单中的生日文本转换为 Date 类型,封装到 javabean 中)

    package online.msym.utils;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import org.apache.commons.beanutils.Converter;
    
    public class MyDateConverter implements Converter {
    
        // 这个方法就是真正进行类型转换的方法
        public Object convert(Class type, Object value) {
            // System.out.println(type); // class java.util.Date
            // System.out.println(value); // 2018/11/11
            String s = (String) value;
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
            Date date = null;
            try {
                date = sdf.parse(s);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return date;
        }
    }

    在封装 javabean 的 Servlet 中的 dopost() 方法中这样写:

    public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            User user = new User();
            try {
                // 对自定义的类型转换器进行注册
                ConvertUtils.register(new MyDateConverter(), java.util.Date.class);
                BeanUtils.populate(user, request.getParameterMap());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            System.out.println(user);//这里会打印出表单输入的数据,并将输入的Date字符串,转换为Date类型
        }

    打印输出:( User 类中重写了 toString()方法)

    1

  • 相关阅读:
    monkeyrunner之夜神模拟器的安装与使用(二)
    monkeyrunner之安卓开发环境搭建(一)
    MySQL 返回未包含在group by中的列
    MySQL数据库初体验
    MongoDB安装
    关于数据库你必须知道的事~
    PostgreSQL中的MVCC 事务隔离
    深入浅出MySQL之索引为什么要下推?
    Java集合篇:Map集合的几种遍历方式及性能测试
    Oracle11g:数据库恢复总结
  • 原文地址:https://www.cnblogs.com/daimajun/p/6592085.html
Copyright © 2020-2023  润新知