首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件开发 >

DAO设计方式(希望大家指正)

2012-11-04 
DAO设计模式(希望大家指正)?? 虽然DAO模式已经有了好多的成熟的框架,但它仍然是一个比较重要的设计模式。要

DAO设计模式(希望大家指正)

?? 虽然DAO模式已经有了好多的成熟的框架,但它仍然是一个比较重要的设计模式。要做一个比较合理的DAO模式,你需要对工厂模式、单例模式、模板模式、策略模式、代理模式、泛型、反射机制、输入输出、异常等知识比较熟悉。下面结合自己理解,设计一个DAO设计模式的例子,希望大家给与指正。

1、数据库连接池的工具类。

???? 在数据库连接池的工具类中,采用了开源的DBCP数据库连接池,调用了DataSource接口,DBCP中关于Datasource的Connection采用了动态代理的方式实现,在这里只是提出,感兴趣可以查看其源码,该工具类采用可配置的方式实现的,代码如下:

?

package com.cvicse.utils;import java.io.InputStream;import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.Properties;import javax.sql.DataSource;import org.apache.commons.dbcp.BasicDataSourceFactory;/** * 数据库连接池操作工具类 *  */public class JDBCUtils {private static DataSource myDataSource = null;private JDBCUtils() {}static {try {Properties prop = new Properties();//采用了类的加载获取路径下数据库的配置信息InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");prop.load(is);myDataSource = BasicDataSourceFactory.createDataSource(prop);} catch (Exception e) {throw new ExceptionInInitializerError(e);}}/** * 获取数据源 *  * @return */public static DataSource getDataSource() {return myDataSource;}/** * 获取连接 *  * @return * @throws SQLException */public static Connection getConnection() throws SQLException {return myDataSource.getConnection();}/** * 关闭资源 * @param rs * @param st * @param conn * @throws SQLException */public static void free(ResultSet rs, Statement st, Connection conn)throws SQLException {try {if (rs != null)rs.close();} catch (SQLException e) {throw new SQLException();} finally {try {if (st != null)st.close();} catch (SQLException e) {throw new SQLException();} finally {if (conn != null)try {conn.close();} catch (Exception e) {throw new SQLException();}}}}}

?数据库配置文件的信息如下dbcpconfig.properties

#连接设置driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/test123username=rootpassword=#<!-- 初始化连接 -->initialSize=10#最大连接数量maxActive=50#<!-- 最大空闲连接 -->maxIdle=20#<!-- 最小空闲连接 -->minIdle=5#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->maxWait=60000#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。connectionProperties=useUnicode=true;characterEncoding=UTF-8#指定由连接池所创建的连接的自动提交(auto-commit)状态。defaultAutoCommit=true#driver default 指定由连接池所创建的连接的只读(read-only)状态。#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)defaultReadOnly=#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLEdefaultTransactionIsolation=READ_UNCOMMITTED

?2、异常定义,用于处理DAO层的异常类,因为异常最好要在业务层进行处理,个人认为这DAO层异常应该在业务层进行处理,所以DAO层的必要异常都抛出。

package com.cvicse.dao.exception;/** * * 定义DAO异常类 * */public class DaoException extends Exception {private static final long serialVersionUID = 1L;/** * @param message * @param cause */public DaoException(String message, Throwable cause) {super(message, cause);}/** * @param message */public DaoException(String message) {super(message);}}package com.cvicse.dao.exception;/** * 传入参数错误异常 * */public class DaoParameterException extends DaoException {private static final long serialVersionUID = 1L;/** * @param message * @param cause */public DaoParameterException(String message, Throwable cause) {super(message, cause);}/** * @param message */public DaoParameterException(String message) {super(message);}}

?

3、定义要操作的pojo类,这里定义了2个pojo类

package com.cvicse.po;/** * 课程持久层对象 * */public class Course {private long id;private String name;/** * 构造函数类 */public Course() {this.id = 0;this.name = null;}/** * @param id * @param name */public Course(long id, String name) {this.id = id;this.name = name;}/** * @return */public long getId() {return id;}/** * @param id */public void setId(long id) {this.id = id;}/** * @return */public String getName() {return name;}/** * @param name */public void setName(String name) {this.name = name;}}package com.cvicse.po;/** * 学生持久层对象 */public class Student {private long id;private String name;public Student() {this.id = 0;this.name = null;}public Student(long id, String name) {this.id = id;this.name = name;}public long getId() {return id;}public void setId(long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}

?

4、定义对象操作的DAO接口,因为面向接口编程,定义接口目的是DAO层的操作能和业务层解耦。

package com.cvicse.dao;import java.util.List;import com.cvicse.dao.exception.DaoException;import com.cvicse.po.Course;/** * 课程DAO层接口 * */public interface CourseDAO {   /** * 获取列表 * @return * @throws DaoException */public List<Course> selectCourses() throws DaoException;/** * 插入记录 * @param course * @throws DaoException */public void insertCourse(Course course) throws DaoException;}package com.cvicse.dao;import java.util.List;import com.cvicse.dao.exception.DaoException;import com.cvicse.po.Student;public interface StudentDAO {/** * 查询方法 * @return * @throws DaoException */public List selectStudents() throws DaoException;/** * 添加方法 * @param student * @throws DaoException */public void insertStudent(Student student) throws DaoException;/** * 删除方法 * @param student * @throws DaoException */public void deleteStudent(Student student) throws DaoException;/** * 修改方法 * @param student * @throws DaoException */public void modifyStudent(Student student) throws DaoException;}

?

5、定义DAO操作的模板类,将DAO层的常用操作类进行提取。

package com.cvicse.util;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.ArrayList;import java.util.List;import com.cvicse.dao.exception.DaoException;import com.cvicse.dao.exception.DaoParameterException;import com.cvicse.dao.refactor.RowMapper;public class DaoOperateTemplate {/** * 查找单个记录对象 *  * @param sql * @param args * @param rowMapper * @return * @throws DaoException */public Object find(String sql, Object[] args, RowMapper rowMapper)throws DaoException {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {conn = JDBCUtils.getConnection();ps = conn.prepareStatement(sql);for (int i = 0; i < args.length; i++)ps.setObject(i + 1, args[i]);rs = ps.executeQuery();Object obj = null;if (rs.next()) {obj = rowMapper.mapRow(rs);}return obj;} catch (SQLException e) {throw new DaoException(e.getMessage(), e);} finally {try {JDBCUtils.free(rs, ps, conn);} catch (SQLException e) {throw new DaoParameterException(e.getMessage(), e);}}}/** * 查找多条记录对象 *  * @param sql * @param args * @param rowMapper * @return * @throws DaoException */public List<Object> Query(String sql, Object[] args, RowMapper rowMapper)throws DaoException {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;List<Object> results = new ArrayList<Object>();try {conn = JDBCUtils.getConnection();ps = conn.prepareStatement(sql);for (int i = 0; i < args.length; i++)ps.setObject(i + 1, args[i]);rs = ps.executeQuery();Object obj = null;while (rs.next()) {obj = rowMapper.mapRow(rs);results.add(obj);}return results;} catch (SQLException e) {throw new DaoException(e.getMessage(), e);} finally {try {JDBCUtils.free(rs, ps, conn);} catch (SQLException e) {throw new DaoParameterException(e.getMessage(), e);}}}/** * 更新操作 *  * @param sql * @param args * @param isGeneralKey * @throws DaoException */public void update(String sql, Object[] args, boolean isGeneralKey)throws DaoException {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {conn = JDBCUtils.getConnection();ps = (isGeneralKey ? conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql));for (int i = 0; i < args.length; i++)ps.setObject(i + 1, args[i]);ps.executeUpdate();} catch (SQLException e) {throw new DaoException(e.getMessage(), e);} finally {try {JDBCUtils.free(rs, ps, conn);} catch (SQLException e) {throw new DaoParameterException(e.getMessage(), e);}}}}

?上面DAO通用操作类中定义接口,用于对象的转化。

package com.cvicse.dao.refactor;import java.sql.ResultSet;import java.sql.SQLException;/** * @author Administrator * */public interface RowMapper {/** * 映射接口 * @param rs * @return * @throws SQLException */public Object mapRow(ResultSet rs) throws SQLException;}

?6、定义具体DAO的实现,在DAO具体实现中,我们采用组合的方式引用通用类,正如设计原则中说的先考虑组合后考虑继承。所以我们在这里选择组合,而不用继承,同时继承对象的转换同样会存在问题。在每个具体DAO操作的实现类中,我们采用了策略模式。

package com.cvicse.dao.impl;import java.sql.ResultSet;import java.sql.SQLException;import java.util.List;import com.cvicse.dao.CourseDAO;import com.cvicse.dao.exception.DaoException;import com.cvicse.dao.refactor.RowMapper;import com.cvicse.po.Course;import com.cvicse.util.DaoOperateTemplate;public class CourseDAOImpl implements CourseDAO {private DaoOperateTemplate daoTemplate = new DaoOperateTemplate();public void insertCourse(Course course) throws DaoException {// TODO Auto-generated method stubString sql = "insert into course(id,name) values (?,?) ";Object[] args = new Object[] { course.getId(), course.getName() };daoTemplate.update(sql, args, false);}public List<Course> selectCourses() throws DaoException {// TODO Auto-generated method stubString sql = "select * from course where id=? ";Object[] args = new Object[] { 1 };List courseList = daoTemplate.Query(sql, args, new courseRowMapper());return courseList;}/** * 内部匿名类 *  * @author Administrator *  */class courseRowMapper implements RowMapper {public Object mapRow(ResultSet rs) throws SQLException {Course course = new Course();course.setId(rs.getLong("id"));course.setName(rs.getString("name"));return course;}}}package com.cvicse.dao.impl;import java.sql.ResultSet;import java.sql.SQLException;import java.util.List;import com.cvicse.dao.StudentDAO;import com.cvicse.dao.exception.DaoException;import com.cvicse.dao.refactor.RowMapper;import com.cvicse.po.Student;import com.cvicse.util.DaoOperateTemplate;public class StudentDAOImpl implements StudentDAO {private DaoOperateTemplate daoTemplate = new DaoOperateTemplate();/* * (non-Javadoc) *  * @see com.cvicse.dao.StudentDAO#deleteStudent(com.cvicse.po.Student) */public void deleteStudent(Student student) throws DaoException {// TODO Auto-generated method stubString sql = "delete from user where id=?";Object[] args = new Object[] { student.getId() };daoTemplate.update(sql, args, false);}/* * (non-Javadoc) *  * @see com.cvicse.dao.StudentDAO#insertStudent(com.cvicse.po.Student) */public void insertStudent(Student student) throws DaoException {// TODO Auto-generated method stubString sql = "insert into student(id,name) values (?,?) ";Object[] args = new Object[] { student.getId(), student.getName() };daoTemplate.update(sql, args, false);}public void modifyStudent(Student student) throws DaoException {// TODO Auto-generated method stubString sql = "update student set name=? where id=? ";Object[] args = new Object[] { student.getName(), student.getId() };daoTemplate.update(sql, args, false);}public List selectStudents() throws DaoException {// TODO Auto-generated method stubString sql = "select * from course where id=? ";Object[] args = new Object[] { 1 };List courseList = daoTemplate.Query(sql, args, new studentRowMapper());return courseList;}/** * 内部匿名类 *  * @author Administrator *  */class studentRowMapper implements RowMapper {public Object mapRow(ResultSet rs) throws SQLException {Student student = new Student();student.setId(rs.getLong("id"));student.setName(rs.getString("name"));return student;}}}

?7、我们定义工厂类,在定义工厂类,考虑到通用性,我们采用了反射机制加配置文件的形式来实现的。同时,在工厂模式中引入了饿汉式单例模式。

/** *  */package com.cvicse.daofactory;import java.io.IOException;import java.io.InputStream;import java.util.Properties;/** * 工厂类方法 *  */public class DaoFactory {private static DaoFactory instance = new DaoFactory();//懒汉法声明对象private static Properties pro;// 配置文件对象private DaoFactory() {try {// 初始化配置文件pro = new Properties();// 采用类加载器方法读取配置文件信息到字节流对象,采用类加载灵活,不用写死InputStream inputStream = DaoFactory.class.getClassLoader().getResourceAsStream("applicationContext.properties");// 加载字节流对象pro.load(inputStream);} catch (IOException e) {throw new ExceptionInInitializerError(e);}}/** * 单例模式获取唯一实例 *  * @return */public static DaoFactory getInstance() {return instance;}/** * 根据配置文件的名字获取类的名字,采用反射机制获取其对象 *  * @param Key * @return */public Object getDAO(String Key) throws Exception {String className = (String) pro.get(Key);return (Class.forName(className).newInstance());}}

?配置文件的内容如下:applicationContext.properties

    courseDao=com.cvicse.dao.impl.CourseDAOImplstudentsDao=com.cvicse.dao.impl.StudentDAOImpl

?8、业务层的调用方式,这里用客户端方式模拟的。在业务层通过接口的方式调用,使得DAO层和业务层能够解耦。

package com.cvicse.Test;import com.cvicse.dao.CourseDAO;import com.cvicse.daofactory.DaoFactory;/** * @author Administrator *  */public class ServiceClient {/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubtry {CourseDAO courseDao = (CourseDAO) DaoFactory.getInstance().getDAO("courseDao");} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

?

总结:在这个DAO设计模式中,涉及到很多java的基础知识,同时,也涉及太多的模式。只有灵活应用,才能体会的其中的灵活。关于DAO具体实现可以采用spring的simpetempate会更能简化其中的实现。

?

private final Object lock; public void update(String sql, final Object[] args, final boolean isGeneralKey) throws DaoException { synchronized (lock) {...}}public interface Entity<IDClass extends java.io.Serializable> {public IDClass getId();public void setId(IDClass id);}

2.GenericDao:所有Dao实现这个接口。
public interface GenericDao<E extends Entity> {/** * 保存一个实体 * @param entity 实体对象 */public void save(E entity);/** * 删除一个实体 * @param id 主键 */public void delete(Serializable id);/** * 删除一个实体 * @param entity 实体对象 */public void delete(E entity);/** * 批量删除实体 * @param entitiesId 实体编号数组 */public void deleteBatchByEntitiesId(Object[] entitiesId);/** * 批量删除实体 * @param entities */public void deleteBatchByEntities(List<E> entities);/** * 查询所有 * @param page 分页对象 * @param sorts 排序对象 * @return 查询结果 */public List getAll(Page page, Sort... sorts);/** * 按页号和每页记录数查询所有 * @param pageIndex 页号 * @param pageSize 每页记录数 * @param sorts 排序 * @return 查询结果 */public List getAll(Integer pageSize, Integer pageIndex, Sort... sorts);/** * 通过主键查询 * @param id 主键 * @return 实体对象 */public E get(Serializable id);/** * 按页号和每页记录数查询结果 * @param ql 查询语句 * @param pageIndex 页号 * @param pageSize 每页记录数 * @param args 查询语句参数 * @return 查询结果 */public List query(String ql, Integer pageSize, Integer pageIndex, Object ... args);/** * 通过查询语句查询 * @param ql 查询语句 * @param page 分页对象 * @param args 参数 * @return 查询结果 */public List query(String ql, Page page, Object... args);/** * 通过查询语句查询,无分页操作 * @param ql 查询语句 * @param args 参数 * @return 查询结果 */public List query(String ql, Object... args);/** * 执行更新 * @param ql 执行更新 * @param args ql参数 * @return 更新所影响的行数 */public int update(String ql, Object... args);/** * 计算记录数 * @param ql 查询语句 * @param args 查询条件参数 * @return 符合条件的记录数 */public int count(String ql, Object... args);}


3.EntityMapper:实体类属性到数据库表字段映射。
public class EntityMapper {// 类名private Class entityClass;// 表明private String tableName;// 列名为map键对应的字段名private Map<String, String> columnMapField = new HashMap<String, String>();// 字段名为map建对应的列名private Map<String, String> fieldMapColumn = new HashMap<String, String>();// get方法名称private Map<String, String> gettersName = new HashMap<String, String>();// set方法名称private Map<String, String> settersName = new HashMap<String, String>();// 被映射的字段个数private Integer mappedColumnCount;// 数据库字段private String[] columns;// 类字段private String[] fields;// 类字段类型private Class[] fieldsType;// 插入语句private String insert;// 删除语句private String delete;// 更新语句private String update;// 查询语句private String select;// 查询所有语句private String all;// 匹配大写字母的正则private static Pattern p = Pattern.compile("(_|[A-Z]+)");// 日志private static Log log = LogFactory.getLog(EntityMapper.class);protected static final Map<String, String> RS_METHOD_NAME;static{RS_METHOD_NAME = new HashMap<String, String>();RS_METHOD_NAME.put("byte", "getByte");RS_METHOD_NAME.put("Byte", "getByte");RS_METHOD_NAME.put("short", "getShort");RS_METHOD_NAME.put("Short", "getShort");RS_METHOD_NAME.put("int", "getInt");RS_METHOD_NAME.put("Integer", "getInt");RS_METHOD_NAME.put("long", "getLong");RS_METHOD_NAME.put("Long", "getLong");RS_METHOD_NAME.put("float", "getFloat");RS_METHOD_NAME.put("Float", "getFloat");RS_METHOD_NAME.put("double", "getDouble");RS_METHOD_NAME.put("Double", "getDouble");RS_METHOD_NAME.put("Date", "getTimestamp");RS_METHOD_NAME.put("boolean", "getBoolean");RS_METHOD_NAME.put("Boolean", "getBoolean");RS_METHOD_NAME.put("String", "getString");}/** * 构造方法初始化类与数据库表的映射关系 * @param className 类名 */public EntityMapper(Class entityClass) throws SQLException{this.entityClass = entityClass;this.tableName = convertName(entityClass.getSimpleName());// 获得该实体类中所有字段名并按规则转换成数据库字段名装入到Map中Field[] fields = entityClass.getDeclaredFields();Map<String, String> fieldsMap = new HashMap<String, String>();for(int i = 0; i < fields.length; i++){fieldsMap.put(this.convertName(fields[i].getName()), fields[i].getName());}Connection conn = null;ResultSet rs = null;try {conn = ((ConnectionProvider)Platform.getInstance().getBean("ConnectionProvider")).getConnection();//  获得数据库中该表所有字段的元数据DatabaseMetaData meta = conn.getMetaData();rs = meta.getColumns(null, null, this.tableName, null);if(log.isDebugEnabled()){log.debug(entityClass.getName() + " -> " + this.tableName);}List<String> columnsName = new ArrayList<String>();List<String> fieldsName = new ArrayList<String>();List<Class> fieldsType = new ArrayList<Class>();String columnName = null;String fieldName = null;// 循环将数据库中与实体类中公有的字段放入Mapwhile(rs.next()){columnName = rs.getString(4);if((fieldName = fieldsMap.get(columnName)) != null){if(log.isDebugEnabled()){log.debug(entityClass.getName() + "." + fieldName + " -> " + this.tableName + "." + columnName);}this.columnMapField.put(columnName, fieldName);this.fieldMapColumn.put(fieldName, columnName);this.gettersName.put(fieldName, this.convertName("get", fieldName));this.settersName.put(fieldName, this.convertName("set", fieldName));columnsName.add(columnName);fieldsName.add(fieldName);fieldsType.add(this.entityClass.getDeclaredField(fieldName).getType());}}this.columns = (String[])columnsName.toArray(new String[columnsName.size()]);this.fields = (String[])fieldsName.toArray(new String[fieldsName.size()]);this.fieldsType = (Class[])fieldsType.toArray(new Class[fieldsType.size()]);this.mappedColumnCount = this.columns.length;// 初始化CRUD语句this.createInsert();this.createDelete();this.createUpdate();this.createSelect();} catch(Exception ex) {log.error("初始化实体映射类失败...",ex);} finally {try{if(rs != null){rs.close();conn.close();}}catch(Exception ex){log.error(ex);}}}/** * 通过结果集创建实体类 * @param rs 结果集 * @return 实体类 */public Entity createFromResultSet(ResultSet rs){try{Entity entity = null;if(rs.next()){entity = (Entity)this.entityClass.newInstance();for(int i = 0; i < fields.length; i++){if(log.isDebugEnabled()){Object value = rs.getClass().getMethod(RS_METHOD_NAME.get(fieldsType[i].getSimpleName()), String.class).invoke(rs, columns[i]);log.debug(this.entityClass.getName() + "." + fields[i] + " -> " + value + " : " + (value == null ? "null" : value.getClass().getName()));}this.entityClass.getMethod(this.setterName(fields[i]), fieldsType[i]).invoke(entity, rs.getClass().getMethod(RS_METHOD_NAME.get(fieldsType[i].getSimpleName()), String.class).invoke(rs, columns[i]));}}return entity;}catch(Exception ex){log.warn("通过结果集创建实体类" + this.entityClass.getName() + "对象时发生错误!");return null;}}/** * 将字段名转换为方法名 * @param prefix 前缀 * @param fieldName 字段名 * @return 方法名 */private String convertName(String prefix, String fieldName){char[] tmp = fieldName.toCharArray();tmp[0] = (tmp[0] + "").toUpperCase().charAt(0);return prefix + new String(tmp);}/** * 将Java命名规则转换成数据库中的命名规则 * @param name Java命名 * @return 数据库命名 */private String convertName(String name){Matcher m = p.matcher(name);StringBuffer t = new StringBuffer();while(m.find()){m.appendReplacement(t, "_$1");}m.appendTail(t);//类名一般第一个字母大写,所以会多一个'_'符号,如果有符号则需要删除掉if(t.charAt(0) == '_'){t.deleteCharAt(0);}return t.toString().toUpperCase().replaceAll("_+", "_");}/** * 初始化插入语句 */private void createInsert(){StringBuffer insert = new StringBuffer("insert into ");StringBuffer values = new StringBuffer("values(");insert.append(this.tableName);insert.append("(");for(int i = 0; i < this.columns.length; i++){insert.append(this.columns[i]);insert.append(", ");values.append("?, ");}insert.delete(insert.length() - 2, insert.length());values.delete(values.length() - 2, values.length());this.insert = insert.append(") ").append(values).append(")").toString();log.debug(this.entityClass.getName() + " insert SQL -> " + this.insert);}/** * 初始化删除语句 */private void createDelete(){StringBuilder delete = new StringBuilder("delete from ");delete.append(this.tableName);delete.append(" t where t.ID = ?");this.delete = delete.toString();log.debug(this.entityClass.getName() + " delete SQL -> " + this.delete);}/** * 初始化更新语句 */private void createUpdate(){StringBuilder update = new StringBuilder("update ");update.append(this.tableName);update.append(" t set ");for(int i = 0; i < this.columns.length; i++){if(this.columns[i].equals("ID")){continue;}update.append("t.");update.append(this.columns[i]);update.append(" = ?, ");}update.deleteCharAt(update.length() - 2);update.append("where t.ID = ?");this.update = update.toString();log.debug(this.entityClass.getName() + " update SQL -> " + this.update);}/** * 创建查询语句 */private void createSelect(){StringBuilder select = new StringBuilder("select ");for(int i = 0; i < this.columns.length; i++){select.append("t.");select.append(this.columns[i]);select.append(", ");}select.deleteCharAt(select.length() - 2);select.append(" from ");select.append(this.tableName);select.append(" t");this.all = select.toString();select.append(" where t.ID = ?");this.select = select.toString();log.debug(this.entityClass.getName() + " all SQL -> " + this.all);log.debug(this.entityClass.getName() + " select SQL -> " + this.select);}/** * 通过类字段名取得get方法 * @param field 字段名  * @return get方法名 */public String getterName(String field){return this.gettersName.get(field);}/** * 通过类字段名取得set方法名 * @param field 字段名 * @return set方法名 */public String setterName(String field){return this.settersName.get(field);}/** * 通过类字段名取得数据库列明 * @param field 字段名 * @return 列名 */public String getColumn(String field){return this.fieldMapColumn.get(field);}/** * 通过数据库列明取得类字段名 * @param column 列明 * @return 字段名 */public String getField(String column){return this.columnMapField.get(column);}/** * @return the tableName */public String getTableName() {return tableName;}/** * @return the entityClass */public Class getEntityClass() {return entityClass;}/** * @return the delete */public String getDelete() {return delete;}/** * @return the insert */public String getInsert() {return insert;}/** * @return the select */public String getSelect() {return select;}/** * @return the update */public String getUpdate() {return update;}/** * @return the columns */public String[] getColumns() {return columns;}/** * @return the fields */public String[] getFields() {return fields;}/** * @return the mappedColumnCount */public Integer getMappedColumnCount() {return mappedColumnCount;}/** * @return the all */public String getAll() {return all;}/** * @return the fieldsType */public Class[] getFieldsType() {return fieldsType;}}


4.GenericDaoDefault:简单扩展了一下Spring的JdbcDaoSupport,统一处理了几个比较令人厌恶的琐碎代码。
public class GenericDaoDefault<E extends Entity> extends JdbcDaoSupport implements GenericDao<E> {// 泛型类型protected Class entityClass;// 实体描述类private EntityMapper entity;// 删除order by字句使用的正则表达式private static Pattern removeOrderByPattern = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);// 分页处理器private PaginationProcessor paginationProcessor;// 主键生成器private IDGenerator iDGenerator;/** * 构造方法 */public GenericDaoDefault(){try{this.entityClass = GenericUtils.getGenericClass(this.getClass());if(this.entityClass != null){this.entity = new EntityMapper(this.entityClass);}}catch(Exception ex){logger.error("初始化" + this.getClass() + "失败", ex);}}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#executeUpdate(java.lang.String, java.lang.Object[]) */public int update(String ql, Object... args) {if(logger.isDebugEnabled()){logger.debug("Update SQL: "" + ql + """);}return this.getJdbcTemplate().update(ql, args);}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#delete(java.io.Serializable) */public void delete(Serializable id) {this.update(this.entity.getDelete(), id);}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#delete(com.funstool.platform.common.dao.Entity) */public void delete(E entity) {this.delete(entity.getId());}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#get(java.io.Serializable) */public E get(Serializable id) {try{Connection conn = super.getConnection();if(logger.isDebugEnabled()){logger.debug("Select SQL: "" + this.entity.getSelect() + """);}PreparedStatement ps = conn.prepareStatement(this.entity.getSelect());ps.setObject(1, id);ResultSet rs = ps.executeQuery();return (E)this.entity.createFromResultSet(rs);} catch(SQLException ex) {logger.warn("获取实体错误", ex);return null;}}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#get(java.lang.String, com.funstool.platform.common.dao.Page, java.lang.Object[]) */public List query(String ql, Page page, Object... args) {ql = (String)this.paginationProcessor.analyse(ql, page);if(logger.isDebugEnabled()){logger.debug("Query SQL: "" + ql + """);}page.setRecord(super.getJdbcTemplate().queryForList(ql, args));return page.getRecord();}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#get(java.lang.String, java.lang.Object[]) */public List query(String ql, Object... args) {if(logger.isDebugEnabled()){logger.debug("Query SQL: "" + ql + """);}return super.getJdbcTemplate().queryForList(ql, args);}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#getAll(com.funstool.platform.common.dao.Page, com.funstool.platform.common.dao.Sort[]) */public List getAll(Page page, Sort... sorts) {String sql = null;if(sorts != null && sorts.length > 0){StringBuilder s = new StringBuilder(this.entity.getAll());s.append(" order by ");for(int i = 0; i < sorts.length; i++){if(sorts[i] == null){continue;}s.append(sorts[i].toString());s.append(", ");}s.delete(s.length() - 2, s.length());sql = (String)this.paginationProcessor.analyse(s.toString(), page);if(logger.isDebugEnabled()){logger.debug("Select SQL: "" + sql + """);}page.setRecord(super.getJdbcTemplate().queryForList(sql));return page.getRecord();} else {sql = (String)this.paginationProcessor.analyse(this.entity.getAll(), page);if(logger.isDebugEnabled()){logger.debug("Select SQL: "" + sql + """);}page.setRecord(super.getJdbcTemplate().queryForList(sql));return page.getRecord();}}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#save(java.lang.Object) */public void save(E entity) {String[] fields = this.entity.getFields();Object[] values = new Object[fields.length];try{if(entity.getId() == null){entity.setId(iDGenerator.generate(super.getConnection()));for(int i = 0; i < fields.length; i++){values[i] = this.entityClass.getMethod(this.entity.getterName(fields[i])).invoke(entity);}this.update(this.entity.getInsert(), values);} else {int idx = 0;for(int i = 0; i < fields.length; i++){if(fields[i].equals("id")){continue;}values[idx++] = this.entityClass.getMethod(this.entity.getterName(fields[i])).invoke(entity);}values[values.length - 1] = entity.getId();this.update(this.entity.getUpdate(), values);}} catch(Exception ex) {logger.warn("保存实体错误", ex);throw new RuntimeException(ex);}}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#count(java.lang.String, java.lang.Object[]) */public int count(String ql, Object... args) {String sql = "select count(*) " + removeSelect(this.removeOrderBy(ql));if(logger.isDebugEnabled()){logger.debug("Count SQL: "" + sql + """);}return super.getJdbcTemplate().queryForInt(sql, args);}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#deleteBatchByEntitiesId(java.util.List) */public void deleteBatchByEntitiesId(Object[] entitiesId) {StringBuilder str = new StringBuilder("delete from ");str.append(this.entity.getTableName());str.append(" t where t.id in (");for(int i = 0; i < entitiesId.length; i++){str.append("?,");}str.deleteCharAt(str.length() - 1);str.append(")");this.update(str.toString(), entitiesId);}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#deleteBatchByEntities(com.funstool.platform.common.dao.EntityListWrapper) */public void deleteBatchByEntities(List<E> entities) {StringBuilder str = new StringBuilder("delete from ");str.append(this.entity.getTableName());str.append(" t where t.id in (");for(int i = 0; i < entities.size(); i++){str.append("?,");}str.deleteCharAt(str.length() - 1);str.append(")");if(!(entities instanceof EntityListWrapper)){entities = new EntityListWrapper(entities);}this.update(str.toString(), ((EntityListWrapper)entities).getEntitiesId());}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#getAll(java.lang.Integer, java.lang.Integer, com.funstool.platform.common.dao.Sort[]) */public List getAll(Integer pageSize, Integer pageIndex, Sort... sorts) {Page page = new Page(pageSize, pageIndex, false);return this.getAll(page, sorts);}/* * (non-Javadoc) * @see com.funstool.platform.common.dao.GenericDao#query(java.lang.String, java.lang.Integer, java.lang.Integer, java.lang.Object[]) */public List query(String ql, Integer pageSize, Integer pageIndex, Object... args) {Page page = new Page(pageSize, pageIndex, false);return this.query(ql, page, args);}/** * 删除ql语句中的order by字句 * @param ql 查询语句 * @return 删除后的查询语句 */private String removeOrderBy(String ql){if(ql != null && !"".equals(ql)){    Matcher m = removeOrderByPattern.matcher(ql);    StringBuffer sb = new StringBuffer();    while (m.find()) {      m.appendReplacement(sb, "");    }    m.appendTail(sb);    return sb.toString();}return "";}/** * 去除ql语句中的select子句 * @param ql 查询语句 * @return 删除后的语句 */private String removeSelect(String ql) {Assert.hasText(ql);int beginPos = ql.toLowerCase().indexOf("from");Assert.isTrue(beginPos != -1, " sql : " + ql + " must has a keyword 'from'");return ql.substring(beginPos);}public void setPaginationProcessor(PaginationProcessor paginationProcessor) {this.paginationProcessor = paginationProcessor;}public void setIDGenerator(IDGenerator idGen) {this.iDGenerator = idGen;}}
/** * 查找多条记录对象 * * @param sql * @param args * @param rowMapper * @return * @throws DaoException */ 这个方法弱弱的问一下楼主,如果是你写的一句SQL根据条件查询出来是100条,此时你如何确定你返回的List里面 就是100个元素? public List<Object> Query(String sql, Object[] args, RowMapper rowMapper) throws DaoException { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; List<Object> results = new ArrayList<Object>(); try { conn = JDBCUtils.getConnection(); ps = conn.prepareStatement(sql); for (int i = 0; i < args.length; i++) ps.setObject(i + 1, args[i]); rs = ps.executeQuery(); Object obj = null; while (rs.next()) { obj = rowMapper.mapRow(rs); results.add(obj); } return results; } catch (SQLException e) { throw new DaoException(e.getMessage(), e); } finally { try { JDBCUtils.free(rs, ps, conn); } catch (SQLException e) { throw new DaoParameterException(e.getMessage(), e); } } } /** * 更新操作 * * @param sql * @param args * @param isGeneralKey * @throws DaoException */ update方法都是清一色的void试问下你如果判断是否更改成功或者是你更改的条数? 有时候update不成功,但是他也不一定会catch到Exception,你想修改的效果没有达到,但程序没任何异常咋办? public void update(String sql, Object[] args, boolean isGeneralKey) throws DaoException { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = JDBCUtils.getConnection(); ps = (isGeneralKey ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn .prepareStatement(sql)); for (int i = 0; i < args.length; i++) ps.setObject(i + 1, args[i]); ps.executeUpdate(); } catch (SQLException e) { throw new DaoException(e.getMessage(), e); } finally { try { JDBCUtils.free(rs, ps, conn); } catch (SQLException e) { throw new DaoParameterException(e.getMessage(), e); } } } } 48 楼 ketty303 2010-06-22   看了以后有种行云流水的感觉!!
2个字:流畅! 49 楼 smartinvoke 2010-06-22   代理量太大了,看得我头发晕!
spring在一定程度上会引起类的爆炸效应
一个不做j2ee的java程序员飘过。。。 50 楼 slaser 2010-06-25   smartinvoke 写道代理量太大了,看得我头发晕!
spring在一定程度上会引起类的爆炸效应
一个不做j2ee的java程序员飘过。。。
啥叫Ioc, 你写业务代码的看那些有什么用。 51 楼 yuantong 2010-06-27   xiaojunjava 写道自得其乐吧

热点排行