用实例聊聊Spring/reflect/范型

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值