在日常Java数据库开发中我们很少会用到自动创建Java类及类中的变量和方法,目前最常见的第三方数据库操作框架基本都要手动创建一个和数据库表一模一样的javabean,并提供每个字段对于的set,get方法,鉴于这种方式能否用一种方法只要一个数据库表名称,就可以返回一个对应该表的javabean的List列表或者其他集合,而完全不用创建一系列的Javabean呢? 答案是有,Java本身自带的类库目前好像还没有类似的功能,但是开源组织开发出一个jar包,就是cglib,目前的版本已经到cglib-nodep-2.1_3.jar,其底层采用asm动态创建字节码,对外只提供了很少的几个方法,而且也没有相应的API文档。所以学习起来比较难以下手。
下面我简单的介绍下如何使用cglib动态创建类。(例子是参考网上的)
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
packagecom.javase.util;
importjava.util.Iterator;
importjava.util.Map;
importjava.util.Set;
importnet.sf.cglib.beans.BeanGenerator;
importnet.sf.cglib.beans.BeanMap;
publicclassCglibBeanUtil{
publicObjectobject=null;
/**
* 属性map
*/
publicBeanMapbeanMap=null;
publicCglibBeanUtil(){
super();
}
@SuppressWarnings("unchecked")
publicCglibBeanUtil(MappropertyMap){
this.object=generateBean(propertyMap);
this.beanMap=BeanMap.create(this.object);
}
/**
* 给bean属性赋值
*
* @param property
* 属性名
* @param value
* 值
*/
publicvoidsetValue(Stringproperty,Objectvalue){
beanMap.put(property,value);
}
/**
* 通过属性名得到属性值
*
* @param property
* 属性名
* @return 值
*/
publicObjectgetValue(Stringproperty){
returnbeanMap.get(property);
}
/**
* 得到该实体bean对象
*
* @return
*/
publicObjectgetObject(){
returnthis.object;
}
@SuppressWarnings("unchecked")
privateObjectgenerateBean(MappropertyMap){
BeanGeneratorgenerator=newBeanGenerator();
SetkeySet=propertyMap.keySet();
for(Iteratori=keySet.iterator();i.hasNext();){
Stringkey=(String)i.next();
generator.addProperty(key,(Class)propertyMap.get(key));
}
returngenerator.create();
}
}
//-----------------------------------------------------------------------------------------------------
//下面是测试类
packagecom.cglib.test;
importjava.lang.reflect.Method;
importjava.util.HashMap;
importcom.cglib.util.CglibBeanUtil;
publicclassCglibTest{
@SuppressWarnings("unchecked")
publicstaticvoidmain(String[]args)throwsClassNotFoundException{
// 设置类成员属性
HashMappropertyMap=newHashMap();
propertyMap.put("id",Class.forName("java.lang.Integer"));
propertyMap.put("name",Class.forName("java.lang.String"));
propertyMap.put("address",Class.forName("java.lang.String"));
// 生成动态 Bean
CglibBeanUtilbean=newCglibBeanUtil(propertyMap);
// 给 Bean 设置值
bean.setValue("id",newInteger(123));
bean.setValue("name","454");
bean.setValue("address","789");
// 从 Bean 中获取值,当然了获得值的类型是 Object
System.out.println(" >> id = "+bean.getValue("id"));
System.out.println(" >> name = "+bean.getValue("name"));
System.out.println(" >> address = "+bean.getValue("address"));
// 获得bean的实体
Objectobject=bean.getObject();
// 通过反射查看所有方法名
Classclazz=object.getClass();
System.out.println(clazz.getSimpleName());
Method[]methods=clazz.getDeclaredMethods();
for(inti=0;i
System.out.println(methods[i].getName());
}
}
}
通过以上例子我们可以发现,只要提供一个Map型的属性键值对(键是变量名,值是变量的类型),就可以创建出对应的类的所以字段(注意,cglib在给创建的字段前面都有前缀“$cglib_prop_”,使用时要注意,而类名是$cglib开头的如“net.sf.cglib.empty.Object$$BeanGeneratorByCGLIB$$b5c0bff6”,这个类是唯一的),并自动提供了每个字段的set,get方法。并且该类是生成在内存中,并没有生成在本地。
现在我们要做一种用底层jdbc操作数据只需根据表名返回的List型的集合,完全不用手动创建Javabean。
思路是:
1:创建一个数据库连接工具类DBUtil
2:定义一个接口:ObjectDao,该接口包含方法
List getObjectList(Connection conn, String tableName);//通过表名和前台传的连接返回对象
//如果是一个完整的项目,一般数据库连接是固定的不会每次都是一个新的数据库连接。所以上面方法中的连接可以根据实际情况省掉,而只需一个全局的连接。
现在有个问题是,通过jdbc获取到该表的数据后,如果动态的将不同的表的字段和值能组装成一个类实例并放入List中,那么只能有一种方法那就是反射。要用反射那么我们就要用Class,所以上面接口的方法看着不能满足,
所以我们在上面接口再定义个方法
List getObjectList(Connection conn, Object ob, String tableName); //和上面的方法一样,只是剥离开重新调用了下
我们最终目的是用jdbc查询后返回的ResultSet和Class来组装成一个List,所以单独定义一个工具类
GenerateUtil,其中有个方法public static List generateObjectListFromDB(Class cls, ResultSet rs),这样在接口的实现类中最终调用这个工具类的方法就可以返回我们所要的集合了。
3:下面就要实现这个接口:ObjectDaoImpl
下面直接贴上代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
packagecom.javase.dao.impl;
importjava.lang.reflect.Field;
importjava.lang.reflect.Method;
importjava.sql.Connection;
importjava.sql.ResultSet;
importjava.sql.ResultSetMetaData;
importjava.sql.SQLException;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
importcom.javase.dao.ObjectDao;
importcom.javase.db.DBUtil;
importcom.javase.util.CglibBeanUtil;
importcom.javase.util.GenerateUtil;
publicclassObjectDaoImplimplementsObjectDao
{
@Override
publicListgetObjectList(Connectionconn,StringtableName)
{
MapcolumnMap=newHashMap();
CglibBeanUtilbeanUtil=null;
Stringsql="select * from "+tableName;
Objectob=null;
try
{
ResultSetMetaDatars=conn.prepareStatement(sql).executeQuery().getMetaData();
for(inti=1;i<=rs.getColumnCount();i++)
{
columnMap.put(rs.getColumnName(i),Class.forName(rs.getColumnClassName(i)));
}
ob=newCglibBeanUtil(columnMap).getObject();
}catch(SQLExceptione)
{
e.printStackTrace();
}catch(ClassNotFoundExceptione)
{
e.printStackTrace();
}
returnthis.getObjectList(conn,ob,tableName);
}
publicListgetObjectList(Connectionconn,Objectob,StringtableName)
{
Stringsql="select * from "+tableName;
ResultSetrs=null;
Listlist=null;
try
{
rs=conn.prepareStatement(sql).executeQuery();
list=GenerateUtil.generateObjectListFromDB(ob.getClass(),rs);
}catch(SQLExceptione)
{
e.printStackTrace();
}finally
{
DBUtil.closeConnection(conn);
}
returnlist;
}
}
其中调用的工具生成类有2个,一个是CglibBeanUtil,和最上面的cglib例子一样,
另一个工具类是GenerateUtil
代码为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
packagecom.javase.util;
importjava.lang.reflect.Field;
importjava.lang.reflect.Method;
importjava.sql.ResultSet;
importjava.util.LinkedList;
importjava.util.List;
publicclassGenerateUtil
{
publicstaticListgenerateObjectListFromDB(Classcls,ResultSetrs)
{
System.out.println(cls.getName());
Listlist=newLinkedList();
Field[]fields=cls.getDeclaredFields();
try
{
while(rs.next())
{
Objectob=cls.newInstance();
for(inti=0;i
{
StringfieldName=fields[i].getName().replace("$cglib_prop_","");
StringsetMethodName="set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
MethodsetMethod=cls.getDeclaredMethod(setMethodName,newClass[]{fields[i].getType()});
setMethod.invoke(ob,rs.getObject(fieldName));
}
list.add(ob);
}
}catch(Exceptione)
{
e.printStackTrace();
}
returnlist;
}
}
所以我们对外提供的方法就是ObjectDaoImpl类的 getObjectList(Connection conn, String tableName),其中的数据库连接可以根据自己需要删掉换成全局的,再往外还可以包装对应的业务层Service及其ServiceImpl,完全根据自己实际需要。
最后我们用一个测试类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
packagecom.javase.dao;
importjava.sql.Connection;
importjava.util.List;
importcom.javase.dao.impl.ObjectDaoImpl;
importcom.javase.db.DBUtil;
publicclasstest
{
publicstaticvoidmain(String[]args)
{
Connectionconn=DBUtil.getConnection('O',"138.138.2.103",1522,"SJPT","TPS","SJPTTPS");
ObjectDaoImplodi=newObjectDaoImpl();
Listlist=odi.getObjectList(conn,"TP_CD00101");
System.out.println(list.size());
}
}
运行后完全正常
还有点是对事务的支持我没做,还有就是获得List后如何使用也没写,既然在daoImpl类中可以得到Class,那么再定义一个获取对于的Class的工具类,构造一个公共的方法获取List中对象的数据的方法即可,在这里我简单提下,方法参数就为(List list, Class class),在其中运用反射即可获取所有数据,这个由各位自己完成。
cglib的实例运用就说到这,谢谢