上一篇介绍了PropertyUtils的用法,PropertyUtils主要是在不修改bean结构的前提下,动态访问bean的属性;

但是有时候,我们会经常希望能够在不定义一个Java类的前提下,动态决定这个类中包含哪些属性,并动态访问它们的属性值,比较典型的使用场景是作为SQL查询的结果集的bean;

为了支持以上特性,Apache Commons Beanutils包为我们提供了DynaBean接口、DynaClass接口;

举个简单例子如下:

       DynaProperty[] props = new DynaProperty[]{
            new DynaProperty("address", java.util.Map.class),
            new DynaProperty("subordinate", mypackage.Employee[].class),
            new DynaProperty("firstName", String.class),
            new DynaProperty("lastName",  String.class)
          };
        BasicDynaClass dynaClass = new BasicDynaClass("employee", null, props);
        
        DynaBean employee = dynaClass.newInstance();
        employee.set("address", new HashMap());
        employee.set("subordinate", new Employee[]{...});
        employee.set("firstName", "Fred");
        employee.set("lastName", "Flintstone");

        DynaBean employee = ...; // 具体的DynaBean实现类
      
        String firstName = (String) employee.get("firstName");
        Address homeAddress = (Address) employee.get("address", "home");
        Object subordinate = employee.get("subordinate", 2);

由于DynaBean和DynaClass都是接口,它们可以有多种实现形式,应用于多种场景。

接下来,会介绍在Apache Commons Beanutils包下,DynaBean和DynaClass接口不同的实现类;

当然,我们也可以自定义实现类来满足我们特定的需求;

基础实现类:BasicDynaBean和BasicDynaClass

先了解下这两个重要的实现,这两个类为DynaBean和DynaClass接口的基础实现类;

首先,我们可以这样创建一个DynaClass实例,其中类的成员属性是用DynaProperty类来描述的:

        DynaProperty[] props = new DynaProperty[]
        { 
            new DynaProperty("address", java.util.Map.class),
            new DynaProperty("subordinate", Employee[].class),
            new DynaProperty("firstName", String.class),
            new DynaProperty("lastName", String.class) 
        };
        BasicDynaClass dynaClass = new BasicDynaClass("employee", null, props);

注意这里的Class<?> dynaBeanClass参数为空,看下源码就发现,如果为null的话,默认会使用BasicDynaBean.class;

有了BasicDynaClass实例后,我们就可以开始创建DynaBean实例了,并且可以调用DynaBean接口中定义的方法,如get和set来读写属性值,如下所示:

        DynaBean employee = dynaClass.newInstance();
        employee.set("address", new HashMap<String, Object>());
        employee.set("subordinate", new Employee[0]);
        employee.set("firstName", "Fred");
        employee.set("lastName", "Flintstone");

      System.out.println(employee.get("firstName"));

实现类:ResultSetDynaClass,处理数据库查询结果集

ResultSetDynaClass主要用于包装java.sql.ResultSet,即SQL查询时候返回的结果集;

不使用DynaBean的话,通常我们是这样处理的:

            String sql = "SELECT id, name, address, state FROM user";
            stmt = conn.prepareStatement(sql);
            ResultSet rs = stmt.executeQuery(sql);

            while (rs.next())
            {
                Long id = rs.getLong("id");
                String name = rs.getString("name");
                String address = rs.getString("address");
                boolean state = rs.getBoolean("state");

                System.out.print("id: " + id);
                System.out.print(", name: " + name);
                System.out.print(", address: " + address);
                System.out.println(", state: " + state);
            }

使用ResultSetDynaClass的话,我们可以这样做:

            String sql = "SELECT id, name, address, state FROM user";
            stmt = conn.prepareStatement(sql);
            ResultSet rs = stmt.executeQuery(sql);
            Iterator<DynaBean> rows = (new ResultSetDynaClass(rs)).iterator();
            while (rows.hasNext())
            {
                DynaBean row = rows.next();
                System.out.print("id: " + row.get("id"));
                System.out.print(", name: " + row.get("name"));
                System.out.print(", address: " + row.get("address"));
                System.out.println(", state: " + row.get("state"));
            }

完整示例:

/*
 * File Name: ResultSetDyna.java
 * Description: 
 * Author: PiChen
 * Create Date: 2017年5月30日
 */
package apache.commons.beanutils.example.dynabeans;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;

import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.ResultSetDynaClass;

/**
 * 
 * @author PiChen
 * @version 2017年5月30日
 */

public class ResultSetDyna
{
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://localhost/demo";

    static final String USER = "root";
    static final String PASS = "root";

    public static void main(String[] args)
    {
        Connection conn = null;
        PreparedStatement stmt = null;
        try
        {
            Class.forName("com.mysql.jdbc.Driver");

            conn = DriverManager.getConnection(DB_URL, USER, PASS);

            String sql = "SELECT id, name, address, state FROM user";
            stmt = conn.prepareStatement(sql);

            ResultSet rs = stmt.executeQuery(sql);

            // while (rs.next())
            // {
            // Long id = rs.getLong("id");
            // String name = rs.getString("name");
            // String address = rs.getString("address");
            // boolean state = rs.getBoolean("state");
            //
            // System.out.print("id: " + id);
            // System.out.print(", name: " + name);
            // System.out.print(", address: " + address);
            // System.out.println(", state: " + state);
            // }

            Iterator<DynaBean> rows = (new ResultSetDynaClass(rs)).iterator();
            while (rows.hasNext())
            {
                DynaBean row = rows.next();
                System.out.print("id: " + row.get("id"));
                System.out.print(", name: " + row.get("name"));
                System.out.print(", address: " + row.get("address"));
                System.out.println(", state: " + row.get("state"));
            }

            rs.close();
            stmt.close();
            conn.close();
        }
        catch (SQLException se)
        {
            se.printStackTrace();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (stmt != null)
                    stmt.close();
            }
            catch (SQLException se2)
            {
            }
            try
            {
                if (conn != null)
                    conn.close();
            }
            catch (SQLException se)
            {
                se.printStackTrace();
            }
        }
    }

}
View Code

相关文章: