反射封装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; }
很多时候,我们在一个抽象类中定义一个抽象方法,延迟到子类实现,
但是它也是在当前抽象类的模板方法调用中;