package dao; 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 = "test"; /** * 數據庫密碼 */ private static final String PASSWORD = "test"; /** * 鏈接數據庫的地址 */ private static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:study"; private static Connection conn; /** * 得到一個數據庫鏈接對象 * @return java.sql.Connection實例 */ public static Connection getConnection() { try { if (conn == null) { Class.forName("oracle.jdbc.OracleDriver"); conn = DriverManager.getConnection(URL, USER, PASSWORD); } else { return conn; } } catch (Exception e) { e.printStackTrace(); } return conn; } /** * 釋放數據庫資源 */ public static void release(PreparedStatement ps,ResultSet rs) { try { if (conn != null) { conn.close(); conn = null; } if (ps != null) { ps.close(); ps = null; } if (rs != null) { rs.close(); rs = null; } } catch (SQLException e) { e.printStackTrace(); } } }
package dao; import java.util.List; import java.util.Map; public interface GenericDao<T> { public void save(T t) throws Exception; public void delete(Object id,Class<T> clazz) throws Exception; public void update(T t) throws Exception; public T get(Object id,Class<T> clazz) throws Exception; /** * 根據條件查詢 * @param sqlWhereMap key:條件字段名 value:條件字段值 * @param clazz * @return * @throws Exception */ public List<T> findAllByConditions(Map<String,Object> sqlWhereMap,Class<T> clazz) throws Exception; }
package dao; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.sql.Types; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import annotation.Column; import annotation.Entity; import annotation.Id; import exception.NotFoundAnnotationException; /** * 泛型DAO的JDBC實現 * @author 楊信 * @version 1.0 */ public class JdbcGenericDaoImpl<T> implements GenericDao<T> { //表的別名 private static final String TABLE_ALIAS = "t"; @Override public void save(T t) throws Exception { Class<?> clazz = t.getClass(); //得到表名 String tableName = getTableName(clazz); //得到字段 StringBuilder fieldNames = new StringBuilder(); //字段名 List<Object> fieldValues = new ArrayList<Object>(); //字段值 StringBuilder placeholders = new StringBuilder(); //佔位符 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { PropertyDescriptor pd = new PropertyDescriptor(field.getName(),t.getClass()); if (field.isAnnotationPresent(Id.class)) { fieldNames.append(field.getAnnotation(Id.class).value()).append(","); fieldValues.add(pd.getReadMethod().invoke(t)); } else if(field.isAnnotationPresent(Column.class)) { fieldNames.append(field.getAnnotation(Column.class).value()).append(","); fieldValues.add(pd.getReadMethod().invoke(t)); } placeholders.append("?").append(","); } //刪除最後一個逗號 fieldNames.deleteCharAt(fieldNames.length()-1); placeholders.deleteCharAt(placeholders.length()-1); //拼接sql StringBuilder sql = new StringBuilder(""); sql.append("insert into ").append(tableName) .append(" (").append(fieldNames.toString()) .append(") values (").append(placeholders).append(")") ; PreparedStatement ps = JdbcDaoHelper.getConnection().prepareStatement(sql.toString()); //設置SQL參數佔位符的值 setParameter(fieldValues, ps, false); //執行SQL ps.execute(); JdbcDaoHelper.release(ps, null); System.out.println(sql + "\n" + clazz.getSimpleName() + "添加成功!"); } @Override public void delete(Object id,Class<T> clazz) throws Exception { //得到表名 String tableName = getTableName(clazz); //得到ID字段名和值 String idFieldName = ""; boolean flag = false; Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if(field.isAnnotationPresent(Id.class)) { idFieldName = field.getAnnotation(Id.class).value(); flag = true; break; } } if (!flag) { throw new NotFoundAnnotationException(clazz.getName() + " object not found id property."); } //拼裝sql String sql = "delete from " + tableName + " where " + idFieldName + "=?"; PreparedStatement ps = JdbcDaoHelper.getConnection().prepareStatement(sql); ps.setObject(1, id); //執行SQL ps.execute(); JdbcDaoHelper.release(ps,null); System.out.println(sql + "\n" + clazz.getSimpleName() + "刪除成功!"); } @Override public void update(T t) throws Exception { Class<?> clazz = t.getClass(); //得到表名 String tableName = getTableName(clazz); //得到字段 List<Object> fieldNames = new ArrayList<Object>(); //字段名 List<Object> fieldValues = new ArrayList<Object>(); //字段值 List<String> placeholders = new ArrayList<String>();//佔位符 String idFieldName = ""; Object idFieldValue = ""; Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { PropertyDescriptor pd = new PropertyDescriptor(field.getName(),t.getClass()); if (field.isAnnotationPresent(Id.class)) { idFieldName = field.getAnnotation(Id.class).value(); idFieldValue = pd.getReadMethod().invoke(t); } else if(field.isAnnotationPresent(Column.class)) { fieldNames.add(field.getAnnotation(Column.class).value()); fieldValues.add(pd.getReadMethod().invoke(t)); placeholders.add("?"); } } //ID做爲更新條件,放在集合中的最後一個元素 fieldNames.add(idFieldName); fieldValues.add(idFieldValue); placeholders.add("?"); //拼接sql StringBuilder sql = new StringBuilder(""); sql.append("update ").append(tableName).append(" set "); int index = fieldNames.size() - 1; for (int i = 0; i < index; i++) { sql.append(fieldNames.get(i)).append("=").append(placeholders.get(i)).append(","); } sql.deleteCharAt(sql.length()-1).append(" where ").append(fieldNames.get(index)).append("=").append("?"); //設置SQL參數佔位符的值 PreparedStatement ps = JdbcDaoHelper.getConnection().prepareStatement(sql.toString()); setParameter(fieldValues, ps, false); //執行SQL ps.execute(); JdbcDaoHelper.release(ps, null); System.out.println(sql + "\n" + clazz.getSimpleName() + "修改爲功."); } @Override public T get(Object id,Class<T> clazz) throws Exception { String idFieldName = ""; Field[] fields = clazz.getDeclaredFields(); boolean flag = false; for (Field field : fields) { if (field.isAnnotationPresent(Id.class)) { idFieldName = field.getAnnotation(Id.class).value(); flag = true; break; } } if (!flag) { throw new NotFoundAnnotationException(clazz.getName() + " object not found id property."); } //拼裝SQL Map<String,Object> sqlWhereMap = new HashMap<String, Object>(); sqlWhereMap.put(TABLE_ALIAS + "." + idFieldName, id); List<T> list = findAllByConditions(sqlWhereMap, clazz); return list.size() > 0 ? list.get(0) : null; } @Override public List<T> findAllByConditions(Map<String,Object> sqlWhereMap,Class<T> clazz) throws Exception { List<T> list = new ArrayList<T>(); String tableName = getTableName(clazz); String idFieldName = ""; //存儲全部字段的信息 //經過反射得到要查詢的字段 StringBuffer fieldNames = new StringBuffer(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { String propertyName = field.getName(); if (field.isAnnotationPresent(Id.class)) { idFieldName = field.getAnnotation(Id.class).value(); fieldNames.append(TABLE_ALIAS + "." + idFieldName) .append(" as ").append(propertyName).append(","); } else if (field.isAnnotationPresent(Column.class)) { fieldNames.append(TABLE_ALIAS + "." + field.getAnnotation(Column.class).value()) .append(" as ").append(propertyName).append(","); } } fieldNames.deleteCharAt(fieldNames.length()-1); //拼裝SQL String sql = "select " + fieldNames + " from " + tableName + " " + TABLE_ALIAS; PreparedStatement ps = null; List<Object> values = null; if (sqlWhereMap != null) { List<Object> sqlWhereWithValues = getSqlWhereWithValues(sqlWhereMap); if (sqlWhereWithValues != null) { //拼接SQL條件 String sqlWhere = (String)sqlWhereWithValues.get(0); sql += sqlWhere; //獲得SQL條件中佔位符的值 values = (List<Object>) sqlWhereWithValues.get(1); } } //設置參數佔位符的值 if (values != null) { ps = JdbcDaoHelper.getConnection().prepareStatement(sql); setParameter(values, ps, true); } else { ps = JdbcDaoHelper.getConnection().prepareStatement(sql); } //執行SQL ResultSet rs = ps.executeQuery(); while(rs.next()) { T t = clazz.newInstance(); initObject(t, fields, rs); list.add(t); } //釋放資源 JdbcDaoHelper.release(ps, rs); System.out.println(sql); return list; } /** * 根據結果集初始化對象 */ private void initObject(T t, Field[] fields, ResultSet rs) throws SQLException, IntrospectionException, IllegalAccessException, InvocationTargetException { for (Field field : fields) { String propertyName = field.getName(); Object paramVal = null; Class<?> clazzField = field.getType(); if (clazzField == String.class) { paramVal = rs.getString(propertyName); } else if (clazzField == short.class || clazzField == Short.class) { paramVal = rs.getShort(propertyName); } else if (clazzField == int.class || clazzField == Integer.class) { paramVal = rs.getInt(propertyName); } else if (clazzField == long.class || clazzField == Long.class) { paramVal = rs.getLong(propertyName); } else if (clazzField == float.class || clazzField == Float.class) { paramVal = rs.getFloat(propertyName); } else if (clazzField == double.class || clazzField == Double.class) { paramVal = rs.getDouble(propertyName); } else if (clazzField == boolean.class || clazzField == Boolean.class) { paramVal = rs.getBoolean(propertyName); } else if (clazzField == byte.class || clazzField == Byte.class) { paramVal = rs.getByte(propertyName); } else if (clazzField == char.class || clazzField == Character.class) { paramVal = rs.getCharacterStream(propertyName); } else if (clazzField == Date.class) { paramVal = rs.getTimestamp(propertyName); } else if (clazzField.isArray()) { paramVal = rs.getString(propertyName).split(","); //以逗號分隔的字符串 } PropertyDescriptor pd = new PropertyDescriptor(propertyName,t.getClass()); pd.getWriteMethod().invoke(t, paramVal); } } /** * 根據條件,返回sql條件和條件中佔位符的值 * @param sqlWhereMap key:字段名 value:字段值 * @return 第一個元素爲SQL條件,第二個元素爲SQL條件中佔位符的值 */ private List<Object> getSqlWhereWithValues(Map<String,Object> sqlWhereMap) { if (sqlWhereMap.size() <1 ) return null; List<Object> list = new ArrayList<Object>(); List<Object> fieldValues = new ArrayList<Object>(); StringBuffer sqlWhere = new StringBuffer(" where "); Set<Entry<String, Object>> entrySets = sqlWhereMap.entrySet(); for (Iterator<Entry<String, Object>> iteraotr = entrySets.iterator();iteraotr.hasNext();) { Entry<String, Object> entrySet = iteraotr.next(); fieldValues.add(entrySet.getValue()); Object value = entrySet.getValue(); if (value.getClass() == String.class) { sqlWhere.append(entrySet.getKey()).append(" like ").append("?").append(" and "); } else { sqlWhere.append(entrySet.getKey()).append("=").append("?").append(" and "); } } sqlWhere.delete(sqlWhere.lastIndexOf("and"), sqlWhere.length()); list.add(sqlWhere.toString()); list.add(fieldValues); return list; } /** * 得到表名 */ private String getTableName(Class<?> clazz) throws NotFoundAnnotationException { if (clazz.isAnnotationPresent(Entity.class)) { Entity entity = clazz.getAnnotation(Entity.class); return entity.value(); } else { throw new NotFoundAnnotationException(clazz.getName() + " is not Entity Annotation."); } } /** * 設置SQL參數佔位符的值 */ private void setParameter(List<Object> values, PreparedStatement ps, boolean isSearch) throws SQLException { for (int i = 1; i <= values.size(); i++) { Object fieldValue = values.get(i-1); Class<?> clazzValue = fieldValue.getClass(); if (clazzValue == String.class) { if (isSearch) ps.setString(i, "%" + (String)fieldValue + "%"); else ps.setString(i,(String)fieldValue); } else if (clazzValue == boolean.class || clazzValue == Boolean.class) { ps.setBoolean(i, (Boolean)fieldValue); } else if (clazzValue == byte.class || clazzValue == Byte.class) { ps.setByte(i, (Byte)fieldValue); } else if (clazzValue == char.class || clazzValue == Character.class) { ps.setObject(i, fieldValue,Types.CHAR); } else if (clazzValue == Date.class) { ps.setTimestamp(i, new Timestamp(((Date) fieldValue).getTime())); } else if (clazzValue.isArray()) { Object[] arrayValue = (Object[]) fieldValue; StringBuffer sb = new StringBuffer(); for (int j = 0; j < arrayValue.length; j++) { sb.append(arrayValue[j]).append("、"); } ps.setString(i, sb.deleteCharAt(sb.length()-1).toString()); } else { ps.setObject(i, fieldValue, Types.NUMERIC); } } } }
package annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 數據庫表的的名稱 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Entity { /** * 表名 */ String value(); }
package annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 標識數據庫字段的ID */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Id { /** * ID的名稱 * @return */ String value(); }
package annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 標識數據庫字段的名稱 * @author 楊信 * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Column { /** * 字段名稱 */ String value(); /** * 字段的類型 * @return */ Class<?> type() default String.class; /** * 字段的長度 * @return */ int length() default 0; }
5、定義一個JavaBean,用於測試使用java
要求:sql
1)、類名必須用Entity註解標識,並指定數據庫中對應的表名數據庫
2)、Id屬性必須用Id註解標識,並指定表中所對應的字段名編程
3)、其它屬性必須用Column註解標識,並指定表中所對應的字段名數組
4)、JavaBean屬性的數據類型目前只實現了8大基本數據類型、String和這些基本類型的數組類型。oracle
5)、JavaBean屬性目前沒有作字段的長度與類型的判斷,待之後改進。app
package model; import java.util.Date; import annotation.Column; import annotation.Entity; import annotation.Id; /** * 圖書 */ @Entity("t_book") //表名 public class Book { /** * 圖書編號 */ @Id("t_isbn") private String isbn; /** * 書名 */ @Column("t_name") private String name; /** * 做者 */ @Column("t_author") private String author; /** * 出版社 */ @Column("t_publishing") private String publishing; /** * 出版時間 */ @Column(value = "t_pubdate") private Date pubdate; /** * 價格 */ @Column(value = "t_price") private double price; public String getIsbn() { return isbn; } public void setIsbn(String isbn) { this.isbn = isbn; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getPublishing() { return publishing; } public void setPublishing(String publishing) { this.publishing = publishing; } public Date getPubdate() { return pubdate; } public void setPubdate(Date pubdate) { this.pubdate = pubdate; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "書名: " + name + " 圖書編號: " + isbn + " 做者: " + author + " 出版社: " + publishing + " 出版時間: " + pubdate + " 價格: " + price; } }
package xml; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import model.Book; import org.junit.BeforeClass; import org.junit.Test; import util.DateUtils; import dao.GenericDao; import dao.JdbcGenericDaoImpl; /** * 測試泛型DAO的CRUD操做 */ public class GenericDaoTest { private GenericDao<Book> bookDao = new JdbcGenericDaoImpl<Book>(); private static InputStream is; @BeforeClass public static void setUpBeforeClass() throws Exception { is = XmlParserTest.class.getResourceAsStream("/books.xml"); } @Test public void testSave() throws Exception { List<Book> books = SaxHelper.saxReader(is); for (Book book : books) { bookDao.save(book); } } @Test public void testStudentFindAll1() throws Exception { System.out.println("\n-------------更新、刪除前,測試查詢全部記錄--------------------"); List<Book> books = bookDao.findAllByConditions(null, Book.class); for (Book book : books) { System.out.println(book); } } @Test public void testDelete() throws Exception { System.out.println("\n-------------測試刪除一條記錄--------------------"); bookDao.delete("9787111349662",Book.class); } @Test public void testGet() throws Exception { System.out.println("\n-------------測試查詢一條記錄--------------------"); Book book = bookDao.get("9787121025389", Book.class); System.out.println(book); } @Test public void testUpdate() throws Exception { System.out.println("\n-------------測試修改一條記錄--------------------"); Book book = new Book(); book.setIsbn("9787121025389"); book.setName("JAVA面向對象編程"); book.setAuthor("孫衛琴"); book.setPublishing("電子工業出版社"); book.setPubdate(DateUtils.string2Date("yyyy-MM-dd", "2006-07-01")); book.setPrice(50.6); bookDao.update(book); } @Test public void testStudentFindAll2() throws Exception { System.out.println("\n-------------更新、刪除前,測試根據條件查詢全部記錄--------------------"); Map<String,Object> sqlWhereMap = new HashMap<String, Object>(); //sqlWhereMap.put("t_isbn", "9787111213826"); //sqlWhereMap.put("t_name", "Java"); sqlWhereMap.put("t_publishing", "機械工業出版社"); //sqlWhereMap.put("t_pubdate", new Date(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2007-01-01 12:06:00").getTime())); List<Book> books = bookDao.findAllByConditions(null, Book.class); for (Book book : books) { System.out.println(book); } } }
books.xml請見http://blog.csdn.net/xyang81/article/details/7247169ide
說明:功能比較簡單,代碼寫得也比較笨拙,還有待優化,誠請指教!單元測試