反射封裝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; }
很多時候,我們在一個抽象類中定義一個抽象方法,延遲到子類實現,
但是它也是在當前抽象類的模板方法調用中;