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