一篇模板模式~以jdbc为基础

反射封装mapRow:参考:

 https://blog.csdn.net/ldz0414/article/details/84468749

模板设计部分:

//1、获取连接
Connection conn = this.getConnection();
//2、创建语句集
PreparedStatement pstmt = this.createPreparedStatement(conn,sql);
//3、执行语句集,并且获得结果集
ResultSet rs = this.executeQuery(pstmt,paramValues);
//4、解析语句集
List<?> result = this.parseResultSet(rs,rowMapper);
//5、关闭结果集
this.closeResultSet(rs);
//6、关闭语句集
this.closeStatement(pstmt);
//7、关闭连接
this.closeConnection(conn);

从上面我们可以得出: 我们只要传入参数: conn 、 sql 、 paramValues 、 rowMapper 就可以了!

conn : 我们可以初始化的时候获取;

sql: 从外部动态传入;

paramValues: 外部动态传入;

rowMapper: 反射封装了mapRow: (主要就是将结果集和对应的实体类做了一个映射)

模板模式定义: 

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

  我的翻译就是:完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。

具体类内容如下: 

public class UserDao {

    //为什么不继承,主要是为了解耦
    private JdbcTemplate jdbcTemplate = new JdbcTemplate(null);

    public List<?> query() {
        String sql = "select * from t_user";
        return jdbcTemplate.executeQuery(sql, new RowMapperUtils(User.class), null);
//        return jdbcTemplate.executeQuery(sql, (ResultSet rs, int rowNum) -> {
//            User member = new User();
//            member.setUsername(rs.getString("username"));
//            member.setPassword(rs.getString("password"));
//            member.setNickName(rs.getString("nickName"));
//            member.setAge(rs.getInt("age"));
//            member.setAddr(rs.getString("addr"));
//            return member;
//        }, null);
    }
}
public class User {

    private String username;
    private String password;
    private String nickName;

    private int age;
    private String addr;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", nickName='" + nickName + '\'' +
                ", age=" + age +
                ", addr='" + addr + '\'' +
                '}';
    }
}
public class UserDaoTest {

    public static void main(String[] args) {
        UserDao userDao = new UserDao();
        System.out.println(userDao.query());

    }
}
public class RowMapperUtils<T> implements RowMapper<T> {

    /**
     * 任意类: 作为反射 的基础调用参数
     */
    private Class<?> targetClass;

    /**
     * 字段map : 缓存 字段名
     */
    private HashMap<String, Field> fieldHashMap;

    public RowMapperUtils(Class<?> targetClass) {
        this.targetClass = targetClass;
        fieldHashMap = new HashMap<>();
        //获取该类声明的所有字段
        Field[] fields = targetClass.getDeclaredFields();
        for (Field field : fields) {
            // 同时存入大小写,如果表中列名区分大小写且有列ID和列iD,则会出现异常。
            // 阿里开发公约,建议表名、字段名必须使用小写字母或数字;禁止出现数字开头,禁止两个下划线中间只出现数字。
            fieldHashMap.put(field.getName(), field);
            // fieldMap.put(getFieldNameUpper(field.getName()), field);
        }
    }

    @Override
    public T mapRow(ResultSet rs, int rowNum) throws Exception {
        T obj = null;
        try {
            obj = (T) targetClass.newInstance();
            final ResultSetMetaData metaData = rs.getMetaData();
            int columnLength = metaData.getColumnCount();
            String columnName = null;
            for (int i = 1; i <= columnLength; i++) {
                // 获取列名
                columnName = metaData.getColumnName(i);
                //获取字段类型
                Class fieldType = fieldHashMap.get(columnName).getType();
                //获取字段对象
                Field field = fieldHashMap.get(columnName);
                //设置字段可以访问
                field.setAccessible(true);
                // fieldClazz == Character.class || fieldClazz == char.class
                if (fieldType == int.class || fieldType == Integer.class) { // int
                    //往对象中设置 字段对象的 值 field: 字段对象
                    // ojb  实例对象
                    //rs.getInt(columnName) 获取结果集中的某个字段的值
                    field.set(obj, rs.getInt(columnName));
                } else if (fieldType == boolean.class || fieldType == Boolean.class) { // boolean
                    field.set(obj, rs.getBoolean(columnName));
                } else if (fieldType == String.class) { // string
                    field.set(obj, rs.getString(columnName));
                } else if (fieldType == float.class) { // float
                    field.set(obj, rs.getFloat(columnName));
                } else if (fieldType == double.class || fieldType == Double.class) { // double
                    field.set(obj, rs.getDouble(columnName));
                } else if (fieldType == BigDecimal.class) { // bigdecimal
                    field.set(obj, rs.getBigDecimal(columnName));
                } else if (fieldType == short.class || fieldType == Short.class) { // short
                    field.set(obj, rs.getShort(columnName));
                } else if (fieldType == Date.class) { // date
                    field.set(obj, rs.getDate(columnName));
                } else if (fieldType == Timestamp.class) { // timestamp
                    field.set(obj, rs.getTimestamp(columnName));
                } else if (fieldType == Long.class || fieldType == long.class) { // long
                    field.set(obj, rs.getLong(columnName));
                }
                field.setAccessible(false);
            }

        }catch(Exception e) {
            e.printStackTrace();
        }
        return obj;
    }


    /**
     * 方法首字母大写.
     *
     * @param fieldName
     *            字段名.
     * @return 字段名首字母大写.
     */
    private String getFieldNameUpper(String fieldName) {
        char[] cs = fieldName.toCharArray();
        cs[0] -= 32; // 方法首字母大写
        return String.valueOf(cs);
    }
}

***************************************核心模板方法类****************************************************

public class JdbcTemplate {

    private final static String URL = "jdbc:mysql://localhost:3306/test";
    private final static String DRIVER = "com.mysql.jdbc.Driver";
    private final static String USERNAME = "root";
    private final static String PASSWORD = "123456";

    private DataSource dataSource;

//    public JdbcTemplate(){
//        try {
//            Class driver = Class.forName(DRIVER);
//        } catch (ClassNotFoundException e) {
//            System.out.println("注册驱动失败.........");
//            e.printStackTrace();
//        }
//    }

    public JdbcTemplate(DataSource dataSource){
        this.dataSource = dataSource;
    }

    private Connection getConnection() throws  Exception{
        if(dataSource != null) {
            return this.dataSource.getConnection();
        } else {
            Class.forName(DRIVER);
            return DriverManager.getConnection(URL,USERNAME,PASSWORD);
        }
    }

    private PreparedStatement createPreparedStatement(Connection conn,String sql) throws  Exception{
        return  conn.prepareStatement(sql);
    }


    private ResultSet executeQuery(PreparedStatement pstmt,Object [] paramValues) throws  Exception{
        if(paramValues != null) {
            for (int i = 0; i < paramValues.length; i ++){
                pstmt.setObject(i,paramValues[i]);
            }
        }
        return  pstmt.executeQuery();
    }

    private void closeStatement(Statement stmt) throws  Exception{
        stmt.close();
    }

    private void closeResultSet(ResultSet rs) throws  Exception{
        rs.close();
    }

    private void closeConnection(Connection conn) throws  Exception{
        //通常把它放到连接池回收
    }

    

    private List<?> parseResultSet(ResultSet rs,RowMapper rowMapper) throws  Exception{
        List<Object> result = new ArrayList<Object>();
        int rowNum = 1;
        while (rs.next()){
            result.add(rowMapper.mapRow(rs,rowNum ++));
        }
        return result;
    }


    public List<?> executeQuery(String sql,RowMapper<?> rowMapper,Object [] paramValues){
        try {

            //1、获取连接
            Connection conn = this.getConnection();
            //2、创建语句集
            PreparedStatement pstmt = this.createPreparedStatement(conn,sql);
            //3、执行语句集,并且获得结果集
            ResultSet rs = this.executeQuery(pstmt,paramValues);
            //4、解析语句集
            List<?> result = this.parseResultSet(rs,rowMapper);

            //5、关闭结果集
            this.closeResultSet(rs);
            //6、关闭语句集
            this.closeStatement(pstmt);
            //7、关闭连接
            this.closeConnection(conn);

            return result;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

}
public interface RowMapper<T> {

    T mapRow(ResultSet rs, int rowNum) throws Exception;

}

 

很多时候,我们在一个抽象类中定义一个抽象方法,延迟到子类实现,

但是它也是在当前抽象类的模板方法调用中;

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值