Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 313|回复: 0

[jsp学习]Jakarta-Common-BeanUtils研究心得

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-9-30 22:48:38 | 显示全部楼层 |阅读模式
    一、概述  
         第一次看到BeanUtils包,是在Struts项目中,作为Struts一个工具来使用的,估计功能越弄越强,就移到Common项目中了吧。  
      

      
      BeanUtils一共有四个package:  
    org.apache.commons.beanutils  
    org.apache.commons.beanutils.converters  
    org.apache.commons.beanutils.locale  
    org.apache.commons.beanutils.locale.converters  

           后三个包主要是用于数据的转换,围绕着一个Converter接口,该接口只有一个方法:

      java.lang.Object convert(java.lang.Class type,
          java.lang.Object value)  

           用于将一个value转换成另一个类型为type的Object。在一些自动化的应用中应该会有用。  

           这里不作评论,以后有兴趣了,或者觉得有用了,再行研究。这里只讲第一个包。  

    二、测试用的Bean  
    在开始所有的测试之前,我写了一个简单的Bean,以便于测试,代码如下:  
    package test.jakarta.commons.beanutils;   
      
       
       
         
       
                         
         
       
      
      public class Month {  
      private int value;  
      private String name;  
      private int[] days={11,22,33,44,55};  

      public Month(int v, String n){  
        value=v;  
        name=n;  
      }  
       
      public String getName() {  
        return name;  
      }  

      public int getValue() {  
        return value;  
      }  

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

      public void setValue(int value) {  
        this.value = value;  
      }  

      public String toString() {  
        return value+"("+name+")";  
      }  

      public int[] getDays() {  
        return days;  
      }  

      public void setDays(int[] is) {  
        days = is;  
      }  

    }  

    三、BeanUtils  
    这是一个主要应用于Bean的Util(呵呵,这个解释很绝吧),以下是其中几个方法的例子  

    //static java.util.Map describe(java.lang.Object bean)  
    //这个方法返回一个Object中所有的可读属性,并将属性名/属性值放入一个Map中,另外还有  
    //一个名为class的属性,属性值是Object的类名,事实上class是java.lang.Object的一个属性  
      Month month=new Month(1, "Jan");  
       
      try {  
        Map map=BeanUtils.describe(month);  
        Set keySet=map.keySet();  
        for (Iterator iter = keySet.iterator(); iter.hasNext();) {  
          Object element = (Object) iter.next();  
          System.out.println("KeyClass:"+element.getClass().getName());  
          System.out.println("ValueClass:"+map.get(element).getClass().getName());  
          System.out.print(element+"        ");  
          System.out.print(map.get(element));  
          System.out.println();  
        }  
      } catch (IllegalAccessException e) {  
        e.printStackTrace();  
      } catch (InvocationTargetException e) {  
        e.printStackTrace();  
      } catch (NoSuchMethodException e) {  
        e.printStackTrace();  
      }  
    输出为:  

    C:java>java    Month
    KeyClass:java.lang.String
    ValueClass:java.lang.String
    days    11
    KeyClass:java.lang.String
    ValueClass:java.lang.String
    value   1
    KeyClass:java.lang.String
    ValueClass:java.lang.String
    class   class Month
    KeyClass:java.lang.String
    ValueClass:java.lang.String
    name    Jan

    C:java>
        注意到所有Map中的key/value都是String,而不管object中实际的值是多少。  
    与此对应的还有static void populate(java.lang.Object bean, java.util.Map properties) 用于将刚才describe出的Map再装配成一个对象。  


    再看这样一段代码  
    曹晓钢也许还记得,为了取一个不确定对象的property,着实花了不少时间,  
    难度不大,但要做到100%的正确,仍然需要付出很大的精力。  
    //static java.lang.String getProperty(java.lang.Object bean, java.lang.String name)  
      Month month=new Month(1, "Jan");  
       
      try {  
        System.out.println(BeanUtils.getProperty(month,"value"));  
      } catch (Exception e) {  
        e.printStackTrace();  
      }  
    //输出是:1  

    与getProperty类似的还有getIndexedProperty, getMappedProperty,  
    以getIndexedProperty为例:  
      Month month=new Month(1, "Jan");  
       
      try {  
        System.out.println(BeanUtils.getIndexedProperty(month,"days",1));  
        System.out.println(BeanUtils.getIndexedProperty(month,"days[1]"));  
      } catch (Exception e) {  
        e.printStackTrace();  
      }  
    这两个调用是相同的。  


    BeanUtils中还有一个方法:  
         static void copyProperties(java.lang.Object dest, java.lang.Object orig)  
    它真是太有用,还记得struts中满天飞的都是copyProperties,我甚至怀疑整个BeanUtils最初是不是因为这个方法的需求才写出来的。  
    它将对象orig中的属性复制到dest中去。  


    四、PropertyUtils  
        这个类和BeanUtils类很多的方法在参数上都是相同的,但返回值不同。  
    BeanUtils着重于"Bean",返回值通常是String,而PropertyUtils着重于属性,它的返回值通常是Object。  


    五、ConstructorUtils  
    这个类中的方法主要分成两种,一种是得到构造方法,一种是创建对象。  
    事实上多数时候得到构造方法的目的就是创建对象,这里只介绍一下创建对象。  
    //static java.lang.Object ConstructorUtils.invokeConstructor  
    //(java.lang.Class klass, java.lang.Object[] args)  
    //根据一个java.lang.Class以及相应的构造方法的参数,创建一个对象。  
      Object obj=ConstructorUtils.invokeConstructor(Month.class, {new Integer(1), "Jan"});  
      Month month=(Month)obj;  
      try {  
        System.out.println(BeanUtils.getProperty(month,"value"));  
      } catch (Exception e) {  
        e.printStackTrace();  
      }  
    输出证明,构造方法的调用是成功的。  
    如果需要强制指定构造方法的参数类型,可以这样调用:  
        Object[] args={new Integer(1), "Jan"};  
        Class[] argsType={int.class, String.class};  
        Object obj;  
        obj = ConstructorUtils.invokeExactConstructor(Month.class, args, argsType);  
        Month month=(Month)obj;  
        System.out.println(BeanUtils.getProperty(month,"value"));  
    argsType指定了参数的类型。  


    六、ConstructorUtils补遗  
        创建对象还有一个方法:invokeExactConstructor,该方法对参数要求更加严格,传递进去的参数必须严格符合构造方法的参数列表。  
    例如:  
      Object[] args={new Integer(1), "Jan"};  
      Class[] argsType={int.class, String.class};  
      Object obj;  
      //下面这句调用将不会成功,因为args[0]的类型为Integer,而不是int  
      //obj = ConstructorUtils.invokeExactConstructor(Month.class, args);  
       
      //这一句就可以,因为argsType指定了类型。  
      obj = ConstructorUtils.invokeExactConstructor(Month.class, args, argsType);  
      Month month=(Month)obj;  
      System.out.println(BeanUtils.getProperty(month,"value"));  


    七、MethodUtils  
    与ConstructorUtils类似,不过调用的时候,通常需要再指定一个method name的参数。  

    八、DynaClass/DynaBean  
         这似乎是BeanUtils中最有趣的部分之一了,很简单,简单到光看这两个接口中的方法会不明白为什么要设计这两个接口。不过看到ResultSetDynaClass后,就明白了。下面是java doc中的代码:  
        ResultSet rs = ...;  
        ResultSetDynaClass rsdc = new ResultSetDynaClass(rs);  
        Iterator rows = rsdc.iterator();  
        while (rows.hasNext())  {  
          DynaBean row = (DynaBean) rows.next();  
          ... process this row ...  
        }  
        rs.close();  
    原来这是一个ResultSet的包装器,ResultSetDynaClass实现了DynaClass,它的iterator方法返回一个ResultSetIterator,则是实现了DynaBean接口。  
    在获得一个DynaBean之后,我们就可以用  
          DynaBean row = (DynaBean) rows.next();  
          System.out.println(row.get("field1")); //field1是其中一个字段的名字  

    再看另一个类RowSetDynaClass的用法,代码n下:  
      String driver="com.mysql.jdbc.Driver";  
      String url="jdbc:mysql://localhost/2hu?useUnicode=true&characterEncoding=GBK";  
      String username="root";  
      String password="";  

      java.sql.Connection con=null;  
      PreparedStatement ps=null;  
      ResultSet rs=null;  
      try {  
         Class.forName(driver).newInstance();  
         con = DriverManager.getConnection(url);  
         ps=con.prepareStatement("select * from forumlist");  
         rs=ps.executeQuery();  
         //先打印一下,用于检验后面的结果。  
         while(rs.next()){  
            System.out.println(rs.getString("name"));  
         }  
         rs.beforeFirst();//这里必须用beforeFirst,因为RowSetDynaClass只从当前位置向前滚动  
       
         RowSetDynaClass rsdc = new RowSetDynaClass(rs);  
         rs.close();  
         ps.close();  
         List rows = rsdc.getRows();//返回一个标准的List,存放的是DynaBean  
         for (int i = 0; i <rows.size(); i++) {  
              DynaBean b=(DynaBean)rows.get(i);  
              System.out.println(b.get("name"));  
         }  
      } catch (Exception e) {  
         e.printStackTrace();  
      }  
      finally{  
       try {  
        con.close();  
       } catch (Exception e) {  
      }  
    }  

    是不是很有趣?封装了ResultSet的数据,代价是占用内存。如果一个表有10万条记录,rsdc.getRows() 就会返回10万个记录。@_@  

    需要注意的是ResultSetDynaClass和RowSetDynaClass的不同之处:  
    1,ResultSetDynaClass是基于Iterator的,一次只返回一条记录,而RowSetDynaClass是基于List的,一次性返回全部记录。直接影响是在数据比较多时ResultSetDynaClass会比较的快速,而RowSetDynaClass需要将ResultSet中的全部数据都读出来(并存储在其内部),会占用过多的内存,并且速度也会比较慢。  
    2,ResultSetDynaClass一次只处理一条记录,在处理完成之前,ResultSet不可以关闭。  
    3,ResultSetIterator的next()方法返回的DynaBean其实是指向其内部的一个固定  
    对象,在每次next()之后,内部的值都会被改变。这样做的目的是节约内存,如果你需要保存每  
    次生成的DynaBean,就需要创建另一个DynaBean,并将数据复制过去,下面也是java doc中的代码:  
        ArrayList results = new ArrayList(); // To hold copied list  
        ResultSetDynaClass rsdc = ...;  
        DynaProperty properties[] = rsdc.getDynaProperties();  
        BasicDynaClass bdc =  
          new BasicDynaClass("foo", BasicDynaBean.class, rsdc.getDynaProperties());  
          Iterator rows = rsdc.iterator();  
        while (rows.hasNext()) {  
          DynaBean oldRow = (DynaBean) rows.next();  
          DynaBean newRow = bdc.newInstance();  
          PropertyUtils.copyProperties(newRow, oldRow);  
          results.add(newRow);  
        }  

    事实上DynaClass/DynaBean可以用于很多地方,存储各种类型的数据。自己想吧。嘿嘿。  


    九、自定义的CustomRowSetDynaClass  
    两年前写过一个与RowSetDynaClass目标相同的类,不过多一个功能,就是分页,只取需要的数据,  
    这样内存占用就会减少。  

    先看一段代码:  
      String driver="com.mysql.jdbc.Driver";  
      String url="jdbc:mysql://localhost/2hu?useUnicode=true&characterEncoding=GBK";  
      String username="root";  
      String password="";  

      java.sql.Connection con=null;  
      PreparedStatement ps=null;  
      ResultSet rs=null;  
      try {  
        Class.forName(driver).newInstance();  
        con = DriverManager.getConnection(url);  
        ps=con.prepareStatement("select * from forumlist order by name");  
        rs=ps.executeQuery();  
      /*  
      while(rs.next()){  
        System.out.println(rs.getString("name"));  
      }  
      rs.beforeFirst();  
      */  

      //第二个参数表示第几页,第三个参数表示页的大小  
      CustomRowSetDynaClass rsdc = new CustomRowSetDynaClass(rs, 2, 5);  
      //RowSetDynaClass rsdc = new RowSetDynaClass(rs);  
      rs.close();  
      ps.close();  
      List rows = rsdc.getRows();  
      for (int i = 0; i <rows.size(); i++) {  
        DynaBean b=(DynaBean)rows.get(i);  
        System.out.println(b.get("name"));  
      }  
    } catch (Exception e) {  
      e.printStackTrace();  
    }  
    finally{  
      try {  
        con.close();  
      } catch (Exception e) {  
      }  
    }  
        在这里用到了一个CustomRowSetDynaClass类,构造方法中增加了page和pageSize两个参数, 这样,不管数据库里有多少条记录,最多只取pageSize条记录,若pageSize==-1,则功能和 RowSetDynaClass一样。
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-14 02:13 , Processed in 0.403022 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表