接触反射和范型有一段时间了,刚好有空,就写了个结合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; }}