接触反射和范型有一段时间了,刚好有空,就写了个结合Sring的DI,加上反射和范型,写了个测试例子,朋友们多多指教!
以下是代码
-----------------------------------------------------------------------------------------------------------------------------
package com.zhaoda.test.spring.po;
/**
* PO,数据库也是根据这个类来设计的.
*
* @author 罗文强
*
*/
public class People {
private Integer id;
private String name;
private Integer age;
/**
* @return 年龄
*/
public Integer getAge() {
return age;
}
/**
* @param age
* 设置年龄
*/
public void setAge(Integer age) {
this.age = age;
}
/**
* @return ID
*/
public Integer getId() {
return id;
}
/**
* @param id
* 设置ID
*/
public void setId(Integer id) {
this.id = id;
}
/**
* @return 名字
*/
public String getName() {
return name;
}
/**
* @param name
* 设置名字
*/
public void setName(String name) {
this.name = name;
}
}
-----------------------------------------------------------------------------------------------------------------------------
package com.zhaoda.test.spring.dao;
import java.util.List;
import com.zhaoda.test.spring.po.People;
/**
* 对{@link People}进行操作的接口
*
* @author 罗文强
*
*/
public interface PeopleDao {
/**
* 添加一个人
*
* @param p
* 数据库中未存在而需要添加的人
*/
public void add(People p);
/**
* 修改一个人的信息
*
* @param p
* 需要更新的人
*/
public void update(People p);
/**
* 删除一个人的资料
*
* @param p
* 需要删除的人
*/
public void delete(People p);
/**
* 查询所有的人
*
* @return 所有符合{@link People}类的对象
*/
public List<People> findAll();
/**
* 根据ID查询人
*
* @param p
* @return ID对应的人
*/
public People findById(People p);
// 如果有需要根据条件来查询的,可以使用自定义的条件对象来实现动态生成SQL
}
-----------------------------------------------------------------------------------------------------------------------------
package com.zhaoda.test.spring.dao.impl;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import com.zhaoda.test.spring.dao.PeopleDao;
import com.zhaoda.test.spring.exception.UnknowDataType;
import com.zhaoda.test.spring.po.People;
/**
* DAO,{@link JdbcDaoSupport}依赖了{@link java.sql.DataSource}.
* 所以,在用的时候,必须提供依赖实现
*
* @author 罗文强
*
*/
public class PeopleDaoImpl extends JdbcDaoSupport implements PeopleDao {
/*
* @see com.zhaoda.test.spring.dao.PeopleDao#add(com.zhaoda.test.spring.People)
*/
public void add(People p) {
String sql = "insert into tb_test_people(id, name, age) "
+ "select isnull(max(id), 0) + 1, ?, ? from tb_test_people";
Object[] os = new Object[2];
os[0] = p.getName();
os[1] = p.getAge();
// 使用Spring的JdbcTemplate()更新数据库
int result = getJdbcTemplate().update(sql, os);
System.out.println("受影响行数: " + result);
}
/*
* (non-Javadoc)
*
* @see com.zhaoda.test.spring.dao.PeopleDao#delete(com.zhaoda.test.spring.People)
*/
public void delete(People p) {
String sql = "delete tb_test_people where id = ?";
Object[] os = new Object[1];
os[0] = p.getId();
// 使用Spring的JdbcTemplate()更新数据库
int result = getJdbcTemplate().update(sql, os);
System.out.println("受影响行数: " + result);
}
/*
* (non-Javadoc)
*
* @see com.zhaoda.test.spring.dao.PeopleDao#findAll()
*/
public List<People> findAll() {
Connection connection = null;
List<People> result = new LinkedList<People>();
try {
String sql = "select id, name, age from tb_test_people";
// 这里不用Spring的JdbcTemplate的查询,因为我们要使用结果集
connection = getJdbcTemplate().getDataSource().getConnection();
ResultSet rs = connection.createStatement().executeQuery(sql);
while (rs.next()) {
// 调用setValue方法,这个方法是用反射和范型进行设置值的.
People temp = setValue(People.class, rs);
result.add(temp);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (connection != null && !connection.isClosed()) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return result;
}
/*
* (non-Javadoc)
*
* @see com.zhaoda.test.spring.dao.PeopleDao#findById(com.zhaoda.test.spring.People)
*/
public People findById(People p) {
String sql = "select id, name, age from tb_test_people where id = ?";
Connection connection = null;
try {
// 这里不用Spring的JdbcTemplate的查询,因为我们要使用结果集
connection = getJdbcTemplate().getDataSource().getConnection();
PreparedStatement ps = connection.prepareStatement(sql);
ps.setInt(1, p.getId());
ResultSet rs = ps.executeQuery();
if (rs.next()) {
// 调用setValue方法,这个方法是用反射和范型进行设置值的.
p = setValue(People.class, rs);
return p;
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (connection != null && !connection.isClosed()) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
/*
* (non-Javadoc)
*
* @see com.zhaoda.test.spring.dao.PeopleDao#update(com.zhaoda.test.spring.People)
*/
public void update(People p) {
String sql = "update tb_test_people set name = ?, age = ? where id = ?";
Object[] os = new Object[3];
os[0] = p.getName();
os[1] = p.getAge();
os[2] = p.getId();
int result = getJdbcTemplate().update(sql, os);
System.out.println("受影响行数: " + result);
}
/**
* 通过反射设置对象的值的公用方法.
*
* @param <T>
* 通过类的无参数构造器产生一个实例
* @param c
* 类
* @param rs
* 调用了rs.next()后的rs
* @return 类的实例,并且已经封装了值.
*/
private <T> T setValue(Class<T> c, ResultSet rs) {
T o = null;
try {
// 初始化类的实例
o = c.newInstance();
// 取得结果集的元数据
ResultSetMetaData metaData = rs.getMetaData();
// 遍历元数据,取得每个列的名称和数据类型
for (int i = 1; i <= metaData.getColumnCount(); i++) {
// 列名
String columnName = metaData.getColumnName(i);
// 数据类型
int columnType = metaData.getColumnType(i);
// 列的值
Object columnValue = rs.getObject(columnName);
// 字符串的列数据类型,这个是SQL的数据类型
String columnTypeName = metaData.getColumnTypeName(i);
// 构造需要操作的方法名称
String methodName = "set"
+ columnName.substring(0, 1).toUpperCase()
+ columnName.substring(1, columnName.length());
Method method = null;
// 根据数据类型,得到相应的方法.
switch (columnType) {
case Types.TIMESTAMP: {
method = c.getMethod(methodName, Date.class);
break;
}
case Types.BIGINT: {
method = c.getMethod(methodName, Integer.class);
break;
}
case Types.INTEGER: {
method = c.getMethod(methodName, Integer.class);
break;
}
case Types.VARCHAR: {
method = c.getMethod(methodName, String.class);
break;
}
case Types.CHAR: {
method = c.getMethod(methodName, String.class);
break;
}
default: {
throw new UnknowDataType("不支持数据类型: " + columnTypeName);
}
}
// 调用方法,关于这个方法更详细的信息可以参考API
method.invoke(o, columnValue);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return o;
}
}
-----------------------------------------------------------------------------------------------------------------------------
package com.zhaoda.test.spring.exception;
/**
* 未知数据类型异常
*
* @author 罗文强
*
*/
public class UnknowDataType extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 2354064628190018064L;
private Integer errorCode;
public UnknowDataType(Integer errorCode) {
super();
this.errorCode = errorCode;
}
public UnknowDataType() {
super();
}
public UnknowDataType(String message, Throwable cause) {
super(message, cause);
}
public UnknowDataType(String message, Integer errorCode, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
public UnknowDataType(String message, Integer errorCode) {
super(message);
this.errorCode = errorCode;
}
public UnknowDataType(String message) {
super(message);
}
public UnknowDataType(Throwable cause) {
super(cause);
}
/**
* @return 错误代码
*/
public Integer getErrorCode() {
return errorCode;
}
/**
* @param errorCode
* 设置错误代码
*/
public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
}
}
-----------------------------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- 初始化一个数据源,因为这里设计的数据库操作需要用到 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- 给数据源的属性注入值 -->
<property name="driverClassName"
value='net.sourceforge.jtds.jdbc.Driver' />
<property name="url"
value="jdbc:jtds:sqlserver://127.0.0.1/test" />
<property name="username" value="sa" />
<property name="password" value="123456" />
</bean>
<!-- DAO依赖于数据源 -->
<bean id="peopleDao"
class="com.zhaoda.test.spring.dao.impl.PeopleDaoImpl">
<!-- 这里给DAO注入数据源 -->
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
</beans>
-----------------------------------------------------------------------------------------------------------------------------
package com.zhaoda.test.spring;
import java.util.Iterator;
import junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.zhaoda.test.spring.dao.PeopleDao;
import com.zhaoda.test.spring.po.People;
/**
* 测试Spring,这里还用到了Java的范型和反射
*
* @author 罗文强
*
*/
public class DaoTest extends TestCase {
private static ApplicationContext ctx = null;
/**
* @param arg0
*/
public DaoTest(String arg0) {
super(arg0);
}
/*
* (non-Javadoc)
*
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() throws Exception {
String file = "applicationContext.xml";
ctx = new ClassPathXmlApplicationContext(file);
super.setUp();
}
/*
* (non-Javadoc)
*
* @see junit.framework.TestCase#tearDown()
*/
protected void tearDown() throws Exception {
super.tearDown();
}
public void testAdd() {
PeopleDao dao = getBean(PeopleDao.class, "peopleDao");
People p = new People();
p.setAge(10);
p.setName("老张");
dao.add(p);
}
public void testFindById() {
PeopleDao dao = getBean(PeopleDao.class, "peopleDao");
People p = new People();
p.setId(1);
p = dao.findById(p);
System.out.println(p.getId());
System.out.println(p.getName());
System.out.println(p.getAge());
}
public void testFindAll() {
PeopleDao dao = getBean(PeopleDao.class, "peopleDao");
Iterator<People> ps = dao.findAll().iterator();
while (ps.hasNext()) {
People p = ps.next();
System.out.println(p.getId());
System.out.println(p.getName());
System.out.println(p.getAge());
}
}
public void testUpdate() {
PeopleDao dao = getBean(PeopleDao.class, "peopleDao");
People p = new People();
p.setId(1);
p.setAge(10);
p.setName("老张第一");
dao.update(p);
}
public void testDelete() {
PeopleDao dao = getBean(PeopleDao.class, "peopleDao");
People p = new People();
p.setId(5);
dao.delete(p);
}
/**
* 这个就是根据范型来自动强制转型的方法了.
*
* @param <T>
* @param c
* @param name
* @return
*/
@SuppressWarnings("unchecked")
private <T> T getBean(Class<T> c, String name) {
Object o = ctx.getBean(name);
return (T) o;
}
}