java學習 -- 利用類的反射和泛型自己動手寫jdbc封裝小類庫
阿新 • • 發佈:2019-02-17
自己動手來封裝jdbc訪問類庫
在公司開發專案(ssh框架)的時候,我特別煩躁的一點就是每次用jdbc方式寫一個數據訪問(hibernate 可以用但是個人覺得對於複雜查詢難以做到和好的控制,可能自己還要慢慢研究吧,自己喜歡mybatis),每次都要寫一大堆模板程式碼,比較繁瑣!
下面說下我的思路。
第一步,分析抽象
從已有的程式碼,出發會發現,訪問資料庫的套路
-->讀取配置檔案(不是必須的,但是專案中這樣做,當然可以tomcat配置資料來源之類的啊)
-->獲取Connection
-->獲取statement或者preparestatement
--->編寫你的sql(這裡說一下,如果你用的statement這裡直接憑藉字元,如果用的preparestatement就是設定引數,以後的sql語句最好不要用statement,因為他很不安全!!一個很大的問題的sql注入!no zuo no die!)
-->執行sql命令
-->封裝結果
-->返回資料
所以,抽象出來,需要做的是
1.抽象出執行查詢和執行更新(update,insert,delete)
2.抽象結果處理
主要完成的就是著兩個問題
第二步,接上一步編寫執行sql的函式
1.sql執行方法
/** * 執行sql * @param sql sql文 * @param params 引數 * @return */ public static boolean executeSQL(String sql,String...params){ boolean flag = false; Connection connection = null; PreparedStatement statement = null; try { connection = getConnection(); statement = connection.prepareStatement(sql); for(int i = 0,n = params.length;i<n;i++){ statement.setString(i+1, params[i]); } statement.execute(sql); flag = true; } catch (Exception e) { e.printStackTrace(); }finally { if(statement!=null){ try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } return flag; }
2.sql的查詢方法
* 查詢結果 * @param sql sql文 * @param params 引數 * @param handler 結果處理集 * @return 返回結果集 */ public static<T> List<?> queryResult(String sql,String[] params,ResultMapper<T> handler,Class<T> c){ List<Map<String,Object>> results = null; Connection connection = null; ResultSet resultSet = null; PreparedStatement statement = null; try { connection = getConnection(); statement = connection.prepareStatement(sql); for (int i = 0, n = (params!=null?params.length:0); i < n; i++) { statement.setString(i, params[i]); } resultSet = statement.executeQuery(); if(resultSet!=null){ results = new ArrayList<>(); String[] name = null; ResultSetMetaData rsm = null; while(resultSet.next()){ if(rsm==null){ rsm = resultSet.getMetaData(); System.out.println(JSON.toJSONString(rsm)); int count = rsm.getColumnCount(); System.out.println(count); name = new String[count]; for(int i = 0;i<count;i++){ name[i] = rsm.getColumnName(i+1); } } Map<String, Object> map = new HashMap<>(); // 開始填充值 for(String keys:name){ map.put(keys, resultSet.getString(keys)); } results.add(map); } } } catch (Exception e) { e.printStackTrace(); }finally { if(statement!=null){ try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } if(resultSet!=null){ try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } // 開始處理結合 List<T> lists = new ArrayList<>(); if(results!=null){ for(Map<String, Object> e:results){ T t = (T) handler.convert(e,c); lists.add(t); } return lists; }else{ return null; } }
第三步,編寫資料對映介面和預設實現類
package com.handkoo.dao;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
public class DButils<T> {
private static final Logger logger = LoggerFactory.getLogger(DButils.class);
private static String url = "";
private static String user = "";
private static String password = "";
static {
InputStream inputStream = DButils.class.getResourceAsStream("/jdbc.properties");
Properties properties = new Properties();
try {
properties.load(inputStream);
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static Connection getConnection() {
Connection connection = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(url, user, password);
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
/**
* 執行sql
*
* @param sql
* sql文
* @param params
* 引數
* @return
*/
public static boolean executeSQL(String sql, String... params) {
boolean flag = false;
Connection connection = null;
PreparedStatement statement = null;
try {
connection = getConnection();
statement = connection.prepareStatement(sql);
for (int i = 0, n = params.length; i < n; i++) {
statement.setString(i + 1, params[i]);
}
statement.execute(sql);
flag = true;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return flag;
}
/**
* 查詢結果
*
* @param sql
* sql文
* @param params
* 引數
* @param handler
* 結果處理集
* @return 返回結果集
*/
public static <T> List<?> queryResult(String sql, String[] params, ResultMapper<T> handler, Class<T> c) {
List<Map<String, Object>> results = null;
Connection connection = null;
ResultSet resultSet = null;
PreparedStatement statement = null;
try {
connection = getConnection();
statement = connection.prepareStatement(sql);
for (int i = 0, n = (params != null ? params.length : 0); i < n; i++) {
statement.setString(i+1, params[i]);
}
resultSet = statement.executeQuery();
if (resultSet != null) {
results = new ArrayList<>();
String[] name = null;
ResultSetMetaData rsm = null;
while (resultSet.next()) {
if (rsm == null) {
rsm = resultSet.getMetaData();
System.out.println(JSON.toJSONString(rsm));
int count = rsm.getColumnCount();
System.out.println(count);
name = new String[count];
for (int i = 0; i < count; i++) {
name[i] = rsm.getColumnName(i + 1);
}
}
Map<String, Object> map = new HashMap<>();
// 開始填充值
for (String keys : name) {
map.put(keys, resultSet.getString(keys));
}
results.add(map);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 開始處理結合
List<T> lists = new ArrayList<>();
if (results != null) {
for (Map<String, Object> e : results) {
T t = (T) handler.convert(e, c);
lists.add(t);
}
return lists;
} else {
return null;
}
}
/**
* 型別轉化介面
*
* @author PengChan
*
* @param <T>
*/
public interface ResultMapper<T> {
@SuppressWarnings("hiding")
<T> T convert(Map<String, Object> resource, Class<T> c);
}
/**
* 預設的型別實現
*
* @author PengChan
*
*/
public class DefaultMapper implements ResultMapper<T> {
@SuppressWarnings("hiding")
public <T> T getInstance(Class<T> c) throws InstantiationException, IllegalAccessException {
return c.newInstance();
}
/**
* 轉化的核心方法
*/
@SuppressWarnings("hiding")
@Override
public <T> T convert(Map<String, Object> resource, Class<T> c) {
T t = null;
try {
t = getInstance(c);
// 獲取所有的成員變數
Field[] declaredFields = t.getClass().getDeclaredFields();
// 迴圈遍歷設定值
for (Field f : declaredFields) {
setValute(f, t, resource.get(f.getName()));
}
} catch (Exception e) {
e.printStackTrace();
}
return t;
}
/**
* 設定型別的值
*
* @param fieldType
* @param value
*/
@SuppressWarnings({ "hiding", "rawtypes" })
private <T> void setValute(Field field, T t, Object value) {
try {
Class fieldType = field.getType();
field.setAccessible(true);
if (fieldType.equals(int.class)) {// 如果是整形
field.setInt(t, (int) value);
} else if (fieldType.equals(float.class)) {
field.setFloat(t, (float) value);
} else if (fieldType.equals(boolean.class)) {
field.setBoolean(t, (boolean) value);
} else if (fieldType.equals(double.class)) {
field.setDouble(t, (double) value);
} else if (fieldType.equals(byte.class)) {
field.setByte(t, (byte) value);
} else if (fieldType.equals(short.class)) {
field.setShort(t, (short) value);
} else if (fieldType.equals(long.class)) {
field.setLong(t, (long) value);
} else if (fieldType.equals(char.class)) {
field.setChar(t, (char) value);
} else {
field.set(t, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
呼叫方式:
DButils.queryResult(sql, null, new DButils().new DefaultMapper(), FitType.class);
注意:該工具類有一個侷限性,就是對應的java類的屬性名稱需要與資料庫的名稱一致才能匹配。(如果這樣,還需要配置xml檔案來建立實體類和資料庫表之間的對映,這不在考慮的範圍之內,建議使用mybatis)
執行的結果如下:
以上就是我全部的分析內容了,有的地方還需要完善。