zoukankan      html  css  js  c++  java
  • Java学习笔记之使用反射+泛型构建通用DAO

    PS:最近简单的学了学后台Servlet+JSP.也就只能学到这里了.没那么多精力去学SSH了,毕竟Android还有很多东西都没学完..

    学习内容:

    1.如何使用反射+泛型构建通用DAO.

    1.使用泛型+反射构建通用DAO.

     DAO的概念曾经写过.其实就是数据访问对象,Date Access Object.其实就是数据库中的数据和Java对象里的一种关联关系的一系列操作.由于以前写过这个概念.就不啰嗦了..简单说一说思想.

     比如说:有两张表 User表和Shop表.

     这是User表中需要进行的操作.

    public interface UserDao {
        void add(User user); 
        void delete(User user);
        void update(User user);
        User select(User user);
    }

     这是Shop表中需要进行的操作.

    public interface ShopDao {
        void add(Shop shop); 
        void delete(Shop shop);
        void update(Shop shop);
        Shop select(Shop shop);
    }

     不 难发现,二者都有相同的操作.这样使得代码冗余度较高.那么能否将这两个DAO相同的方法封装成一个呢.这是可以的.这样就构建了一个BaseDao里面 封装了二者相同的操作.当我们需要操作表的时候,我们将T换成User或者是Shop就可以了.当我们实际项目面对的表有非常多的时候,如果都具有相同的 方法.那么就可以这样进行抽取.

    public interface BaseDao<T> {
        void add(T t); 
        void delete(T t);
        void update(T t);
        T select(T t);
    }

     这样就构建了一个通用的DAO抽象接口.这里我拿User表来说,如果User表还有其他的业务逻辑呢(比如说查询所有信息等等).那么我们只需要这样.

    public interface UserDao extends BaseDao<User> {
    
        //按照行查询,额外的业务逻辑.
        List<User>findAll();
    }

     这样我们只需要定义一个新的UserDao就可以了,它继承了BaseDao中的所有方法,当有额外的业务逻辑的时候,只需要添加额外方法就可以了.这样光有接口当然是不行的.我们需要有具体的实现.

     我们先看BaseDao的实现类BaseDaoImp

     我们来看一下思路.

     先上一张原理图.

     1.首先我们如果想对User表进行操作,那么我们首先需要获取User类型.告诉BaseDaoImp,我们当前是需要对User表进行操作.因此构造函数就是用来干这个的.

     2. 当我们获取了User类型之后,如果想要对其进行操作,那么首先需要知道 sql 语句,因此我们需要对sql语句进行拼接.那么拼接过程中,我们需要知道User表内部到底声明了哪些变量.这样就需要使用反射机制.通过反射机制来获取 User实体类中声明的变量,然后对sql进行相关的拼接.那么getsql函数用来完成sql的拼接过程.

     3. 那么拼接完之后还是不行,因为拼接出来的sql语句是这样的:insert into User(id,username,password,email,grade) values(?,?,?,?,?)我们需要对占位符进行赋值操作.那么首先我们需要获取具体的值,那么setArgs就是来获取属性的具体值的.

     4.当获取了具体的值之后,我们就可以通过sql提供给我们的相关函数来执行sql语句了.

     这里函数其实都非常的简单,只要细看,还是能明白其中的道理的.

    package com.example.daoimp;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.ParameterizedType;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import com.example.dao.BaseDao;
    import com.example.helper.JdbcDaoHelper;
    
    //通用DAO
    
    public class BaseDaoImp<T> implements BaseDao<T> {
    
        /** 操作常量 */
        public static final String SQL_INSERT = "insert";
        public static final String SQL_UPDATE = "update";
        public static final String SQL_DELETE = "delete";
        public static final String SQL_SELECT = "select";
    
        private Class<T> EntityClass; // 获取实体类
    
        private PreparedStatement statement;
    
        private String sql;          
    
        private Object argType[];
    
        private ResultSet rs;
    
        @SuppressWarnings("unchecked")
        public BaseDaoImp() {
            
            /**
             *  传递User就是 com.example.daoimp.BaseDaoImp<com.example.bean.User>
             *  传递Shop就是 com.example.daoimp.BaseDaoImp<com.example.bean.Shop>
             * */
            ParameterizedType type = (ParameterizedType) getClass()
                    .getGenericSuperclass();      
            
            /**
             * 这里如果传递的是User.那么就是class com.example.bean.User 
             * 如果传递的是Shop.       那么就是class com.example.bean.Shop
             * */
            EntityClass = (Class<T>) type.getActualTypeArguments()[0];  
        }
    
        @Override
        public void add(T t) {
            // TODO Auto-generated method stub
            sql = this.getSql(SQL_INSERT);   //获取sql.
            // 赋值.
            try {
                argType = setArgs(t, SQL_INSERT);
                statement = JdbcDaoHelper.getPreparedStatement(sql);  //实例化PreparedStatement.
                //为sql语句赋值.
                statement = JdbcDaoHelper.setPreparedStatementParam(statement,
                        argType);
                statement.executeUpdate(); //执行语句.
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                JdbcDaoHelper.release(statement, null);  //释放资源.
            }
        }
    
        @Override
        public void delete(T t) {
            // TODO Auto-generated method stub
            sql = this.getSql(SQL_DELETE);
            try {
                argType = this.setArgs(t, SQL_DELETE);
                statement = JdbcDaoHelper.getPreparedStatement(sql);
                statement = JdbcDaoHelper.setPreparedStatementParam(statement,
                        argType);
                statement.executeUpdate();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                JdbcDaoHelper.release(statement, null);
            }
        }
    
        @Override
        public void update(T t) {
            // TODO Auto-generated method stub
            sql = this.getSql(SQL_UPDATE);
            try {
                argType = setArgs(t, SQL_UPDATE);
                statement = JdbcDaoHelper.getPreparedStatement(sql);
                statement = JdbcDaoHelper.setPreparedStatementParam(statement,
                        argType);
                statement.executeUpdate();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                JdbcDaoHelper.release(statement, null);
            }
        }
    
        @Override
        public T select(T t) {
            // TODO Auto-generated method stub
            sql = this.getSql(SQL_SELECT);
            T obj = null;
            try {
                argType = setArgs(t, SQL_SELECT);
                statement = JdbcDaoHelper.getPreparedStatement(sql);
                statement = JdbcDaoHelper.setPreparedStatementParam(statement,
                        argType);
                rs = statement.executeQuery();
                Field fields[] = EntityClass.getDeclaredFields();
                while (rs.next()) {
                    obj = EntityClass.newInstance();
                    for (int i = 0; i < fields.length; i++) {
                        fields[i].setAccessible(true);
                        fields[i].set(obj, rs.getObject(fields[i].getName()));
                    }
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return obj;
    
        }
    
        // sql拼接函数 形如 : insert into User(id,username,password,email,grade) values(?,?,?,?,?)
        private String getSql(String operator) {
    
            StringBuffer sql = new StringBuffer();
            // 通过反射获取实体类中的所有变量
            Field fields[] = EntityClass.getDeclaredFields();
    
            // 插入操作
            if (operator.equals(SQL_INSERT)) {
                sql.append("insert into " + EntityClass.getSimpleName());
                sql.append("(");
                for (int i = 0; fields != null && i < fields.length; i++) {
                    fields[i].setAccessible(true);    //这句话必须要有,否则会抛出异常.
                    String column = fields[i].getName();
                    sql.append(column).append(",");
                }
                sql = sql.deleteCharAt(sql.length() - 1);
                sql.append(") values (");
                for (int i = 0; fields != null && i < fields.length; i++) {
                    sql.append("?,");
                }
                sql.deleteCharAt(sql.length() - 1);
                // 是否需要添加分号
                sql.append(")");
            } else if (operator.equals(SQL_UPDATE)) {
                sql.append("update " + EntityClass.getSimpleName() + " set ");
                for (int i = 0; fields != null && i < fields.length; i++) {
                    fields[i].setAccessible(true);
                    String column = fields[i].getName();
                    if (column.equals("id")) {
                        continue;
                    }
                    sql.append(column).append("=").append("?,");
                }
                sql.deleteCharAt(sql.length() - 1);
                sql.append(" where id=?");
            } else if (operator.equals(SQL_DELETE)) {
                sql.append("delete from " + EntityClass.getSimpleName()
                        + " where id=?");
            } else if (operator.equals(SQL_SELECT)) {
                sql.append("select * from " + EntityClass.getSimpleName()
                        + " where id=?");
            }
            return sql.toString();
        }
    
        // 获取参数.
        private Object[] setArgs(T entity, String operator)
                throws IllegalArgumentException, IllegalAccessException {
    
            Field fields[] = EntityClass.getDeclaredFields();
            if (operator.equals(SQL_INSERT)) {
    
                Object obj[] = new Object[fields.length];
                for (int i = 0; obj != null && i < fields.length; i++) {
                    fields[i].setAccessible(true);
                    obj[i] = fields[i].get(entity);
                }
                return obj;
    
            } else if (operator.equals(SQL_UPDATE)) {
    
                Object Tempobj[] = new Object[fields.length];
                for (int i = 0; Tempobj != null && i < fields.length; i++) {
                    fields[i].setAccessible(true);
                    Tempobj[i] = fields[i].get(entity);
                }
    
                Object obj[] = new Object[fields.length];
                System.arraycopy(Tempobj, 1, obj, 0, Tempobj.length - 1);
                obj[obj.length - 1] = Tempobj[0];
                return obj;
    
            } else if (operator.equals(SQL_DELETE)) {
    
                Object obj[] = new Object[1];
                fields[0].setAccessible(true);
                obj[0] = fields[0].get(entity);
                return obj;
            } else if (operator.equals(SQL_SELECT)) {
    
                Object obj[] = new Object[1];
                fields[0].setAccessible(true);
                obj[0] = fields[0].get(entity);
                return obj;
            }
            return null;
        }
    
    }

     这样就对BaseDao进行了具体的实现.因为我们的User表还有其他额外的操作,那么我们只需要这样.它通过继承BaseDaoImp,然后实现UserDao接口,那么UserDaoImp就即具有了BaseDaoImp的通用方法,还具有了自己其他的额外方法.

    package com.example.daoimp;
    
    import java.lang.reflect.ParameterizedType;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.util.ArrayList;
    import java.util.List;
    
    import com.example.bean.User;
    import com.example.dao.UserDao;
    import com.example.helper.JdbcDaoHelper;
    
    public class UserDaoImp extends BaseDaoImp<User> implements UserDao {
    
        private Class<?> EntityClass;
    
        private String sql;
    
        private PreparedStatement statement;
    
        private ResultSet rs;
    
        private List<User> list;
    
        public UserDaoImp() {
    
            ParameterizedType type = (ParameterizedType) getClass()
                    .getGenericSuperclass();
            EntityClass = (Class<?>) type.getActualTypeArguments()[0];
        }
    
        @Override
        public List<User> findAll() {
            // TODO Auto-generated method stub
            StringBuffer b = new StringBuffer();
            list = new ArrayList<User>();
            sql = b.append("select * from " + EntityClass.getSimpleName())
                    .toString();
            try {
                statement = JdbcDaoHelper.getPreparedStatement(sql);
                rs = statement.executeQuery();
                while (rs.next()) {
                    User user = new User();
                    user.setId(rs.getInt("id"));
                    user.setPassword(rs.getString("password"));
                    user.setEmail(rs.getString("email"));
                    user.setUsername(rs.getString("username"));
                    user.setGrade(rs.getInt("grade"));
                    list.add(user);
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return list;
        }
    
    }

     有 了他们,我们就可以进行具体的操作了,如果还有Shop表,那么同理我们可以去创建一个ShopDao去继承BaseDao,然后在自己的ShopDao 定义其他的额外方法就可以了.当表非常多的时候,我们就可以采用这种思想进行封装.这样写出的代码质量就显得非常的高,耦合度也非常的松散.

     在添加上工具类.

    package com.example.helper;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class JdbcDaoHelper {
    
        private static final String USER = "root";
    
        private static final String PASSWORD = "";
    
        private static final String URL = "jdbc:mysql://localhost:3306/usermanager";
    
        private static Connection con;
    
        // 获取数据库连接对象
        public static Connection getConnection() {
    
            if (con == null) {
                try {
                    Class.forName("com.mysql.jdbc.Driver");
                    con = DriverManager.getConnection(URL, USER, PASSWORD);
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } else {
                return con;
            }
            return con;
        }
    
        public static PreparedStatement getPreparedStatement(String sql)
                throws SQLException {
    
            return getConnection().prepareStatement(sql);
        }
    
        public static PreparedStatement setPreparedStatementParam(
                PreparedStatement statement, Object obj[]) throws SQLException {
    
            for (int i = 0; i < obj.length; i++) {
                statement.setObject(i + 1, obj[i]);
            }
            return statement;
        }
    
        // 释放资源
        public static void release(PreparedStatement ps, ResultSet rs) {
            try {
                if (con != null) {
                    con.close();
                    con = null;
                }
                if (ps != null) {
                    ps.close();
                    ps = null;
                }
                if (rs != null) {
                    rs.close();
                    rs = null;
                }
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    
    }

     最后加上UserBean.

    package com.example.bean;
    
    public class User {
    
        private int id;
        private String username;
        private String password;
        private String email;
        private int grade;
        
        public User(){
            
        }
        
        public User(int id,String username,String password,String email,int grade){
            this.id = id;
            this.username = username;
            this.password = password;
            this.email = email;
            this.grade = grade;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        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 getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        public int getGrade() {
            return grade;
        }
    
        public void setGrade(int grade) {
            this.grade = grade;
        }
        
    }

     测试类.

    package com.example.jdbc;
    
    import java.util.List;
    
    import com.example.bean.User;
    import com.example.daoimp.UserDaoImp;
    
    public class Main {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
        
            List<User>list = null;
            UserDaoImp imp = new UserDaoImp();
            list = imp.findAll();
            for(User user:list){
                System.out.println(user.getId()+" "+user.getUsername()+" "+user.getPassword()+" "+user.getEmail()+" "+user.getGrade());
            }
            //insert操作.
            User user = new User();
            user.setId(1);
            user.setUsername("代码如风");
            user.setPassword("123456");
            user.setEmail("123");
            user.setGrade(5);
            imp.add(user);
            //update操作.
            User user_1 = new User();
            user.setId(1);
            user.setUsername("心静如水");
            user.setPassword("123456");
            user.setEmail("123");
            user.setGrade(5);
            imp.update(user_1);
        }
    
    }

     注意(别忘了引入mysql.jar包.)

     最后放上一个源代码:files.cnblogs.com/files/RGogoing/JDBCDao.rar

  • 相关阅读:
    Flash 全局安全性设置面板
    响应式布局的一个例子mark
    移动平台WEB前端开发技巧汇总
    自定义事件机制——观察者模式
    学习之响应式Web设计:Media Queries和Viewports
    常用栅格布局方案
    观察者模式的一个例子
    二进制文件转换为文本工具
    C#面向对象名词比较(二)
    MSN消息提示类
  • 原文地址:https://www.cnblogs.com/RGogoing/p/5325196.html
Copyright © 2011-2022 走看看