Java反射結合JDBC寫的一個通用DAO

以前寫反射只是用在了與設計模式的結合上,並沒有考慮到反射可以與DAO結合。也是一個偶然的機會,被正在上培訓的老師點到這個問題,才考慮到這個可能性,於是上網參考各種代碼,然後自己動手開發了一個通用DAO。

大家除學JDBC時,也會有這種感觸,一般寫的DAO只能用在一張表上,不能通用,如果你的程序有多張表,就需要寫多個DAO,或者使用一些複雜設計來達到這個目的。而這個反射方式實現的DAO,就不需要很複雜的設計,就可以實現DAO的通用。


這個通用是有前提的,就是DAO接受的參數必須是絕對符合JavaBean標準的對象。而且JavaBean的屬性類型,必須跟數據庫中表的數據類型保持一致。否則就會出問題,下面貼出代碼,寫得不好,別見怪


package com.sldll.cms.dao;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

//0oO
public class GeneralDAO {

	//---------------------------------查詢部分--------------------------------------------------------------------------
	/**
	 * 查詢所有記錄
	 * @param obj	表對應的JavaBean對象
	 * @return		所有記錄構成的list
	 * @throws Exception
	 */
	public List<Object> findAll(Object obj) throws Exception {

		List<Object> list = new ArrayList<Object>();
		ResultSet rs = null;
		try {

			// 獲取數據庫連接
			Statement stmt = DBConnectionManager.getConnection()
					.createStatement();
			// 構建sql語句
			String tableName = obj.getClass().getName();
			tableName = tableName.substring(tableName.lastIndexOf(".") + 1);
			String sql = "select * from " + tableName;

			// 執行sql語句
			rs = stmt.executeQuery(sql);

			while (rs.next()) {
				list.add(createObj(rs, obj));
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw e;
		} finally {
			// 關閉連接
			if (rs != null) {
				rs.close();
			}
			DBConnectionManager.closeConnection();
		}

		return list;
	}

	/**
	 * 對指定的表執行指定的sql查詢語句
	 * @param obj
	 * 			以該表對應的JavaBean對象決定表
	 * @param query
	 * 			要對該表執行的sql語句
	 * @return
	 * @throws Exception
	 */
	public List<Object> findByNameQuery(Object obj, String query) throws Exception {
		// TODO Auto-generated method stub
		List<Object> list = null;
		try {
			Statement sql_statement = DBConnectionManager.getConnection()
					.createStatement();
			//執行傳遞的sql語句
			ResultSet rs = sql_statement.executeQuery(query);
			list = new ArrayList<Object>();
			if (rs != null) {
				while (rs.next()) {
					list.add(createObj(rs, obj));
				}
			}
			return list;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw e;
		} finally {
			DBConnectionManager.closeConnection();
		}

	}

	/**
	 * 按條件對指定表進行查詢
	 * @param obj
	 * 		以該表對應的JavaBean對象決定表
	 * @param condition
	 * 		查詢的條件,key:條件		value:值
	 * @param isFuzzzy
	 *		是否支持模糊查詢
	 * @return
	 * @throws Exception
	 */
	public List<Object> findByNameQuery(Object obj, Map<Object,Object> condition,boolean isFuzzy) throws Exception {
		List<Object> list = new ArrayList<Object>();
		try {
			
			String tablename = getTableName(obj);
			StringBuilder sb = new StringBuilder("select * from " + tablename);
			PreparedStatement state = null;
			if(isFuzzy){
				addFuzzyConditionString(sb, condition);
			}
			else{
				addConditionString(sb, condition);
			}
			state = DBConnectionManager.getConnection().prepareStatement(sb.toString());
			state = setSqlValue(state, condition,isFuzzy);
			ResultSet rs = state.executeQuery();
			if (rs != null) {
				while (rs.next()) {
					list.add(createObj(rs, obj));
				}
			}
			return list;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw e;
		} finally {
			DBConnectionManager.closeConnection();
		}
	}



	//-------------------------------------創建部分--------------------------------------------------------------------------
	/**
	 * 在數據庫裏新建一條記錄
	 * @param obj
	 * 		描述記錄的對象,必須是數據庫中某張表對應的JavaBean對象
	 * @return
	 * 		新建成功返回真,否則返回假
	 * @throws Exception
	 */
	public boolean create(Object obj) throws Exception{
		// 獲取數據庫連接
		try {
			// 構建sql語句
			Map<Object, Object> map = getObjectFieldValue(obj);
			String tableName = obj.getClass().getName();
			tableName = tableName.substring(tableName.lastIndexOf(".") + 1);
			StringBuilder sb = new StringBuilder("insert into " + tableName);
			addCreateString(sb, map);
			PreparedStatement  stmt = DBConnectionManager.getConnection()
					.prepareStatement(sb.toString());
			setSqlValue(stmt, map,false);
			int count = stmt.executeUpdate();
			if(count>0){
				return true;
			}
			else{
				return false;
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		} finally {
			DBConnectionManager.closeConnection();
		}
	}

	//-------------------------------------刪除部分----------------------------------------------------------------------------
	/**
	 * 刪除表中所有記錄
	 * @param obj
	 * 			JavaBean對象,決定要刪除的是哪張表
	 * @return
	 * 			刪除成功返回真,否則返回假
	 */
	public boolean deleteAll(Object obj) throws Exception{
		String delete_sql = "delete from "+getTableName(obj);
		PreparedStatement pstmt;
		try {
			pstmt = DBConnectionManager.getConnection().prepareStatement(delete_sql);
			int count = pstmt.executeUpdate();
			if(count>0){
				return true;
			}
			else{
				return false;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw e;
		}
		finally{
			DBConnectionManager.closeConnection();
		}
		
	}
	
	/**
	 * 在指定表中刪除給定ID的記錄
	 * @param obj
	 * 		表示要刪除的表
	 * @param condition
	 * 		刪除的條件 key:字段(一般爲字符串) value:值
	 * @return
	 */
	public boolean delete(Object obj,Map<Object,Object> condition) throws Exception{
		//構建sql語句
		StringBuilder sb = new StringBuilder("delete from "+getTableName(obj));
		addConditionString(sb, condition);
		try {
			PreparedStatement pstmt = DBConnectionManager.getConnection().prepareStatement(sb.toString());
			setSqlValue(pstmt, condition,false);
			int count = pstmt.executeUpdate();
			if(count > 0){
				return true;
			}
			else{
				return false;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw e;
		}
		finally{
			DBConnectionManager.closeConnection();
		}
	}
	
	//-------------------------------------更新部分----------------------------------------------------------------------------
	/**
	 * 更新指定表的記錄
	 * @param obj
	 * 		用來確定表的Java對象
	 * @param map
	 * 		要設置的字段值,key:字段(字符串),value:值
	 * @param condition
	 * 		篩選條件
	 * @return
	 */
	public boolean update(Object obj,Map<Object,Object> map,Map<Object, Object>condition) throws Exception {
		StringBuilder sb = new StringBuilder("update "+getTableName(obj));
		addSetString(sb,map);
		addConditionString(sb, condition);
		try {
			PreparedStatement pstmt = DBConnectionManager.getConnection().prepareStatement(sb.toString());
			List<Object> values =  new ArrayList<Object>();
			getValuesToList(values,map);
			getValuesToList(values, condition);
			setSqlValue(pstmt, values);

			int count = pstmt.executeUpdate();
			if(count > 0){
				return true;
			}
			else{
				return false;
			}
		} catch ( Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw e;
		}
		finally{
			DBConnectionManager.closeConnection();
		}
	}

	private List<Object> getValuesToList(List<Object> values,Map<Object, Object> map) {
		
		for (Iterator<Object> it = map.keySet().iterator(); it.hasNext();) {
			Object value =  map.get(it.next());
			values.add(value);
		}
		return values;
	}
	
	


	/**
	 * 獲取JavaBean對象的字段值放到容器中
	 * @param obj
	 * 			JavaBean對象
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	private Map<Object, Object> getObjectFieldValue(Object obj)
			throws IllegalAccessException, InvocationTargetException {
		Map<Object, Object> map = new HashMap<Object,Object>();
		
		Field fields[] = obj.getClass().getFields();
		Method methods[] = obj.getClass().getMethods();

		// 給字段設置值
		for (int i = 0; i < fields.length; i++) {
			// 用字段的名字構建set方法的名字
			String fieldName = fields[i].getName();
			
			String methodName = "get" + fieldName.substring(0, 1).toUpperCase()
					+ fieldName.substring(1);

			// 查找對應的方法
			Method method = null;
			for (int j = 0; j < methods.length; j++) {
				if (methods[j].getName().equals(methodName)) {
					method = methods[j];
					break;
				}
			}
			// 如果存在這個方法
			if (method != null) {
				// 開始執行方法,獲取當前的JavaBean對象字段值
				Object value = method.invoke(obj, new Object[] { });
				map.put(fieldName, value);
			}
		}
		return map;
	}
	
	private void addSetString(StringBuilder sb, Map<Object, Object> map) {
		// TODO Auto-generated method stub
		if (!map.isEmpty()) {
			sb.append(" set ");
			for (Iterator<Object> it = map.keySet().iterator(); it.hasNext();) {
				String key = (String) it.next();
				if (null == key) {
					continue;
				}
				sb.append(key+"=?,");				
			}
			sb.deleteCharAt(sb.lastIndexOf(","));
			System.out.println(sb.toString());
		}
	}
	
	/**
	 * 在現有sql創建語句後面追加字段名和佔位符
	 * @param sb
	 * @param map
	 */
	private void addCreateString(StringBuilder sb,Map<Object, Object> map) {
		// TODO Auto-generated method stub
		sb.append("(");
		int count = 0;
		for (Iterator<Object> it = map.keySet().iterator(); it.hasNext();) {
			String key = (String) it.next();
			if (null == key) {
				continue;
			}
			sb.append(key + ",");
			count++;
		}
		sb.deleteCharAt(sb.lastIndexOf(","));
		sb.append(") values(");
		for (int i = 0; i < count; i++) {
			sb.append("?,");
		}
		sb.deleteCharAt(sb.lastIndexOf(","));
		sb.append(")");
		System.out.println(sb.toString());
	}

	/**
	 * 在現有sql查詢語句後面追加判斷條件
	 * @param sb  			where之前的sql         
	 * @param condition 	條件(key:字段名;value:值)       
	 * @return	使用佔位符的sql語句
	 */
	private String addConditionString(StringBuilder sb, Map<Object,Object> condition) {
		if (!condition.isEmpty()) {
			sb.append(" where ");
			int i = 0;

			for (Iterator<Object> it = condition.keySet().iterator(); it.hasNext();) {
				String key = (String) it.next();
				if (null == key) {
					continue;
				}
				if (i != 0) {
					sb.append(" and ");
				}
				if (key.indexOf("<") != -1 || key.indexOf(">") != -1
						|| key.indexOf("=") != -1) {
					sb.append(key + "?");
				} else {
					sb.append(key + "=" + "?");
				}

				i++;

			}

		}
		System.out.println(sb.toString());
		return sb.toString();
	}
	
	private String addFuzzyConditionString(StringBuilder sb,Map<Object,Object>condition) {
		if (!condition.isEmpty()) {
			sb.append(" where ");
			int i = 0;

			for (Iterator<Object> it = condition.keySet().iterator(); it.hasNext();) {
				String key = (String) it.next();
				if (null == key) {
					continue;
				}
				if (i != 0) {
					sb.append(" or ");
				}
				sb.append(key + " like " +"?");
				i++;
			}

		}
		System.out.println(sb.toString());
		return sb.toString();
	}
	
	
	/**
	 * 設置現有sql語句的佔位符的值
	 * @param state
	 * @param map
	 * @return
	 * @throws SQLException
	 */
	private PreparedStatement setSqlValue(PreparedStatement state, Map<Object,Object> map,boolean isFuzzy)
			throws SQLException {
		if (!map.isEmpty()) {
			int i = 1;
			for (Iterator<Object> it = map.keySet().iterator(); it.hasNext();) {
				Object value = map.get(it.next());
				if(isFuzzy){
					state.setObject(i++, "%"+value+"%");
				}else{
					state.setObject(i++, value);
				}
			}

		}
		return state;
	}
	private PreparedStatement setSqlValue(PreparedStatement state, List<Object> values)
			throws SQLException {
		if (!values.isEmpty()) {
			int i = 1;
			for (Iterator<Object> it = values.iterator(); it.hasNext();) {
				Object value = it.next();
				state.setObject(i++, value);
			}
			
		}
		return state;
	}
	
	private String getTableName(Object obj) {
		String tablename = obj.getClass().getName();
		tablename = tablename.substring(tablename.lastIndexOf(".") + 1);
		return tablename;
	}
	// 利用反射構建對象
	
	private Object createObj(ResultSet rs, Object obj)
			throws  Exception {
		// TODO Auto-generated method stub
		Object object = obj.getClass().newInstance();
		// 獲取字段
		Field fields[] = obj.getClass().getFields();
		// 獲取方法
		Method methods[] = obj.getClass().getMethods();

		// 給字段設置值
		for (int i = 0; i < fields.length; i++) {
			// 用字段的名字構建set方法的名字
			String fieldName = fields[i].getName();
			String methodName = "set" + fieldName.substring(0, 1).toUpperCase()
					+ fieldName.substring(1);

			// 查找對應的方法
			Method method = null;
			for (int j = 0; j < methods.length; j++) {
				if (methods[j].getName().equals(methodName)) {
					method = methods[j];
					break;
				}
			}

			// 如果存在這個方法
			if (method != null) {
				// 開始執行方法,爲當前的JavaBean對象字段設置值
				Object value = rs.getObject(fieldName);
				method.invoke(object, new Object[] { value });

			}
		}
		return object;
	}
	
	
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章