SpringMVC jdbctemplate实现底层架构封装

来源:互联网 发布:极致游戏优化版win7 编辑:程序博客网 时间:2024/06/02 11:58
本人封装的dao层的泛型实现,目前只支持mysql
精华的4个类的代码贴出来了,commons是完整的代码,entityapp是自动代码生成器
这个dao层封装的优点在于:
1.dao层基本不用写任何代码,因为EntityDaoSupport 这个类已经涵盖大多数的数据库操作
2.完整的代码中有个CascadeParamMethodArgumentResolver的类可以用来解决spring mvc中表示层方法参数中复杂对象参数的映射,级联参数格式:a.b.c (表单参数) 或 a[b][c] (ajax请求对象参数),这个类要配置在xml文件中
3.还有一些常用的Converter类,这些也是要配置的,配置后就不需要手工转换了
这个的缺点:
1.底层用了大量的反射和泛型,尚不清楚会不会影响程序的性能,不过我做的项目吞吐量也挺大的,没有发现严重的问题

2.代码写的比较久了,可能存在一些特殊的情况没有考虑到的,也许会有错误,这个就需要大家一起来改进啦

文章来自这个牛人大哥:http://www.oschina.net/code/snippet_1245103_33821


   注意这个架构经过本人改造的。环境是Eclipse4.4.x以上。JDK是1.7,Maven是4.x也就是说Eclipse自带的,MySQL是5.x以上,在学这个架构之前必须懂这些Maven运用。




package com.flong.commons.persistence;import java.beans.PropertyDescriptor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.math.BigDecimal;import java.util.ArrayList;import java.util.List;import com.flong.commons.persistence.annotation.Column;import com.flong.commons.persistence.annotation.Id;import com.flong.commons.persistence.dao.impl.BaseDomain;import com.flong.commons.persistence.exception.AnnotationNotFoundException;import com.flong.commons.persistence.exception.ErrorCode;import com.flong.commons.persistence.exception.FieldColumnMappingException;import com.flong.commons.utils.ObjectUtil;/** * 实体抽象类 * * 创建日期:2012-9-24 * @author wangk */public abstract class Entity extends BaseDomain implements Comparable<Entity> {/** 序列化版本标识 */private static final long serialVersionUID = 4224390531787078169L;/** 列访问操作符 */public static final String COLUMN_ACCESS_OPERATOR = ".";/** 表后缀连接符 */public static final String TABLE_SUFFIX_CONNECTOR = "_";/** 降序排序常量 */public static final String ORDER_DESCENDING = "DESC";/** 关联链(全部的关联类型)常量 */public static final Class<?>[] ASSOCIATION_LINK_ALL = null;/** 注解表名默认值 */public static final String TABLE_NAME_DEFAULT = "";/** 注解列名默认值 */public static final String COLUMN_NAME_DEFAULT = "";/** 注解列类型默认值 */public static final int COLUMN_TYPE_DEFAULT = 0;/** 注解列长度默认值 */public static final int COLUMN_SIZE_DEFAULT = 0;/** 注解外键引用实体类类型默认值 */public static final Class<? extends Entity> REFERENCE_CLASS_DEFAULT = Entity.class;@Overridepublic int hashCode() {final int prime = 31;int result = super.hashCode();String idstr = identityString();Long id = idstr == null ? 0 : Long.valueOf(idstr);result = prime * result + (int) (id ^ (id >>> 32));return result;}@Overridepublic boolean equals(Object obj) {if (this == obj) {return true;}if (obj == null || getClass() != obj.getClass()) {return false;}Entity other = (Entity) obj;String idstr = identityString();String oidstr = other.identityString();if(idstr == oidstr) {return true;}if(idstr == null) {return false;}return idstr.equals(oidstr);}@Overridepublic int compareTo(Entity other) {String idstr = identityString();String oidstr = other.identityString();if(idstr == null && oidstr == null) {return 0;}if(idstr == null) {return 1;}if(oidstr == null) {return -1;}return new BigDecimal(idstr).compareTo(new BigDecimal(oidstr));}/** * 获得实体对象的ID值的字符串形式 * * @return * 创建日期:2012-9-24 * 修改说明: * @author wangk */public String identityString() {Class<? extends Entity> clazz = getClass();for (Field field : ObjectUtil.getAllField(clazz)) {Id id = field.getAnnotation(Id.class);if(id != null) {try {Object value = new PropertyDescriptor(field.getName(), clazz).getReadMethod().invoke(this);return value == null ? null : value.toString();} catch (Exception e) {throw new RuntimeException(e);}}}throw new AnnotationNotFoundException(ErrorCode.ANNOTATION_NOT_FOUND_AS_ID, "Annotation " + Id.class.getName() + " not found for " + clazz.getName());}/** * 获得当前对象和other对象属性值不同的列集合,当other的类型和当前对象所属类型不同时将抛出RuntimeException * * @param other         比较的对象 * @return List<String> 属性值不同的列集合       * 创建日期:2012-11-21 * 修改说明: * @author wangk */public List<String> getDifferentColumns(Entity other) {List<String> differentColumns = new ArrayList<String>();Class<? extends Entity> clazz = getClass();for (Field field  : ObjectUtil.getAllField(clazz)) {Column column = field.getAnnotation(Column.class);if(column == null) {continue;}String name = column.value();if(name.equals(COLUMN_NAME_DEFAULT)) {name = field.getName().toUpperCase();}Object value = null;Object otherValue = null;try {Method method = new PropertyDescriptor(field.getName(), clazz).getReadMethod();value = method.invoke(this);otherValue = method.invoke(other);} catch (Exception e) {throw new RuntimeException(e);}if(value==null && otherValue!=null || value!=null && !value.equals(otherValue)) {differentColumns.add(name);}}return differentColumns;}/** * 获得指定列名的属性值 * * @param <T>         属性类型参数,必须用属性的实际类型及其父类型接收返回值,否则将抛出类型转换异常 *   指定的列为空或不存在时将抛出RuntimeException * @param columnName  列名 * @return T          属性值 * 创建日期:2012-11-21 * 修改说明: * @author wangk */public <T> T getFieldValue(String columnName) {Class<? extends Entity> clazz = getClass();for (Field field  : ObjectUtil.getAllField(clazz)) {Column column = field.getAnnotation(Column.class);if(column == null) {continue;}String name = column.value();if(name.equals(COLUMN_NAME_DEFAULT)) {name = field.getName().toUpperCase();}if(name.equalsIgnoreCase(columnName)) {try {@SuppressWarnings("unchecked")T value = (T)new PropertyDescriptor(field.getName(), clazz).getReadMethod().invoke(this);return value;} catch (Exception e) {throw new RuntimeException(e);}}}throw new FieldColumnMappingException(ErrorCode.FIELD_COLUMN_MAPPING_AS_NOT_EXIST_COLUMN, "Column name " + columnName + " not exist for " + clazz.getName());}/** * 判断实体对象的状态是否为瞬时状态(ID值为空) * * @return * 创建日期:2012-9-24 * 修改说明: * @author wangk */public boolean isTransient() {return identityString() == null;}}
package com.flong.commons.persistence.dao.impl;import java.beans.PropertyDescriptor;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.ArrayList;import java.util.HashSet;import java.util.List;import java.util.Map;import java.util.Set;import java.util.Stack;import org.apache.commons.collections.CollectionUtils;import org.apache.commons.lang3.StringUtils;import org.apache.log4j.Logger;import org.springframework.dao.EmptyResultDataAccessException;import org.springframework.jdbc.core.RowMapper;import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;import org.springframework.jdbc.support.GeneratedKeyHolder;import org.springframework.jdbc.support.KeyHolder;import com.flong.commons.lang.exception.DaoAccessException;import com.flong.commons.persistence.Entity;import com.flong.commons.persistence.annotation.Association;import com.flong.commons.persistence.annotation.Reference;import com.flong.commons.persistence.bean.DataStore;import com.flong.commons.persistence.bean.PagingParameter;import com.flong.commons.persistence.builder.SimpleSqlBuilder;import com.flong.commons.persistence.condition.Condition;import com.flong.commons.persistence.dao.EntityDao;import com.flong.commons.persistence.exception.AnnotationNotFoundException;import com.flong.commons.persistence.exception.DuplicateRecordException;import com.flong.commons.persistence.exception.ErrorCode;import com.flong.commons.persistence.exception.FieldColumnMappingException;import com.flong.commons.persistence.exception.IllegalRecordException;import com.flong.commons.utils.ObjectUtil;/** * 实体Dao支持类 * * 创建日期:2012-9-24 * @author wangk */@SuppressWarnings("all")public abstract class EntityDaoSupport<E extends Entity> extends BaseDaoSupport implements EntityDao<E> {/** 日志对象 */private static final Logger logger = Logger.getLogger(BaseDaoSupport.class);/** 条件关键字集合 */private static final List<String> CONDITION_KEYWORDS = new ArrayList<String>();/** 条件运算符(正则表达式形式)集合 */private static final List<String> CONDITION_OPERATORS = new ArrayList<String>();static {/** 初始化条件关键字集合 */CONDITION_KEYWORDS.add("IS");CONDITION_KEYWORDS.add("NOT");CONDITION_KEYWORDS.add("NULL");CONDITION_KEYWORDS.add("LIKE");CONDITION_KEYWORDS.add("BETWEEN");CONDITION_KEYWORDS.add("AND");CONDITION_KEYWORDS.add("OR");CONDITION_KEYWORDS.add("IN");CONDITION_KEYWORDS.add("ASC");CONDITION_KEYWORDS.add("DESC");/** 初始化条件运算符集合(= < > + - * / % ( ) , ?),组合符号(<> <= >=)需要特殊处理 */CONDITION_OPERATORS.add("=");CONDITION_OPERATORS.add("<");CONDITION_OPERATORS.add(">");CONDITION_OPERATORS.add("\\+");CONDITION_OPERATORS.add("\\-");CONDITION_OPERATORS.add("\\*");CONDITION_OPERATORS.add("/");CONDITION_OPERATORS.add("%");CONDITION_OPERATORS.add("\\(");CONDITION_OPERATORS.add("\\)");CONDITION_OPERATORS.add("\\,");CONDITION_OPERATORS.add("\\?");}/** SQL语句构建对象 */protected SimpleSqlBuilder<E> simpleSqlBuilder;/** 实体类类型 */private Class<E> entityClass;/** * 构造方法  通过反射初始化entityClass * 创建日期:2012-10-8 * 修改说明: * @author wangk */public EntityDaoSupport() {//获得EntityDaoSupport包含泛型实参的类型ParameterizedType parameterizedType = (ParameterizedType)getClass().getGenericSuperclass();Type[] params = parameterizedType.getActualTypeArguments();Class<E> entityClass = (Class<E>)params[0];init(entityClass);}/** * 构造方法 * @param entityClass 实体类类型 * 创建日期:2012-9-25 * 修改说明: * @author wangk */public EntityDaoSupport(Class<E> entityClass) {init(entityClass);}/** * 初始化方法 * * @param entityClass  实体类类型 * 创建日期:2012-10-11 * 修改说明: * @author wangk */private void init(Class<E> entityClass) {this.entityClass = entityClass;//初始化simpleSqlBuildersimpleSqlBuilder = new SimpleSqlBuilder<E>(entityClass);//检查实体所有的引用属性列是否存在和引用属性类型和被引用属性类型是否相同simpleSqlBuilder.checkReferenceFields();//检查关联属性是否存在非自身循环关联并记录debug级别日志for (Class<?> association : simpleSqlBuilder.getAssociationLink()) {logger.debug(association.getName());}}/** * 获得SQL语句构建对象 * * @return * 创建日期:2012-9-25 * 修改说明: * @author wangk */public SimpleSqlBuilder<E> getSimpleSqlBuilder() {return simpleSqlBuilder;}@Overridepublic <K extends Number> E get(K id, Class<?>... associationLink) throws DaoAccessException {if(associationLink != null && associationLink.length == 0) {try {return jdbcTemplate.queryForObject(simpleSqlBuilder.getQuerySimpleSql(), simpleSqlBuilder.getRowMapper(), id);} catch (EmptyResultDataAccessException e) {//只处理空结果异常,表示没有对应的记录,返回nulllogger.warn(e);return null;} catch (Exception e) {throw new DaoAccessException(e);}}return get(Condition.eq(simpleSqlBuilder.getFieldColumnMapping().get(simpleSqlBuilder.getIdField()), id), associationLink);}@Overridepublic E get(String sql, Object... params) throws DaoAccessException {return getUniqueEntity(query(sql, params));}@Overridepublic E get(String sql, List<Object> params) throws DaoAccessException {return get(sql, params.toArray());}@Overridepublic E get(String sql, Map<String, Object> params) throws DaoAccessException {return getUniqueEntity(query(sql, params));}@Overridepublic E get(Condition condition, Class<?>... associationLink) throws DaoAccessException {return getUniqueEntity(query(condition, associationLink));}@Overridepublic <K extends Number> K save(E entity) throws DaoAccessException {return saveWithId(entity, null);}@Overridepublic <K extends Number> void save(E entity, K id) throws DaoAccessException {saveWithId(entity, id);}@Overridepublic void update(E entity) throws DaoAccessException {try {if(entity.isTransient()) {throw new IllegalRecordException(ErrorCode.ILLEGAL_RECORD_AS_UPDATE_TRANSIENT,"The record " + entity + " is transient!");}Map<String, Object> params = simpleSqlBuilder.getSqlParameters(entity);namedParameterJdbcTemplate.update(simpleSqlBuilder.getUpdateSql(params.keySet()), params);} catch (Exception e) {throw new DaoAccessException(e);}}@Overridepublic void saveOrUpdate(E entity) throws DaoAccessException {if(entity.isTransient()) {save(entity);} else {update(entity);}}@Overridepublic <K extends Number> void delete(K id) throws DaoAccessException {try {jdbcTemplate.update(simpleSqlBuilder.getDeleteSql(), id);} catch (Exception e) {throw new DaoAccessException(e);}}@Overridepublic List<E> query(String sql, Object... params) throws DaoAccessException {return query(sql, null, params).getDatas();}@Overridepublic List<E> query(String sql, List<Object> params) throws DaoAccessException {return query(sql, params.toArray());}@Overridepublic List<E> query(String sql, Map<String, Object> params) throws DaoAccessException {return query(sql, null, params).getDatas();}@Overridepublic List<E> query(Condition condition, Class<?>... associationLink) throws DaoAccessException {String orders = null;return query(condition, orders, associationLink);}@Overridepublic List<E> query(Condition condition, String orders, Class<?>... associationLink) throws DaoAccessException {return query(condition, orders, null, associationLink).getDatas();}@Overridepublic DataStore<E> query(String sql, PagingParameter paging, Object... params) throws DaoAccessException {sql = handleSimpleSql(sql);return queryDataStore(sql, params, getRowMapperBySql(sql), paging);}@Overridepublic DataStore<E> query(String sql, PagingParameter paging,List<Object> params) throws DaoAccessException {return query(sql, paging, params.toArray());}@Overridepublic DataStore<E> query(String sql, PagingParameter paging,Map<String, Object> params) throws DaoAccessException {sql = handleSimpleSql(sql);return queryDataStore(sql, params, getRowMapperBySql(sql), paging);}@Overridepublic DataStore<E> query(Condition condition, PagingParameter paging, Class<?>... associationLink) throws DaoAccessException {return query(condition, null, paging, associationLink);}@Overridepublic DataStore<E> query(Condition condition, String orders, PagingParameter paging, Class<?>... associationLink) throws DaoAccessException {Object[] params = new Object[0];if(condition != null) {params = condition.getParameters();}if(associationLink != null && associationLink.length == 0) {String sql = condition==null?"":condition.toSqlString();if(orders == null) {orders = simpleSqlBuilder.getFieldColumnMapping().get(simpleSqlBuilder.getIdField());}if(!sql.equals("")) {sql += " ";} sql += "ORDER BY " + orders;return query(sql, paging, params);}return queryDataStore(buildAssociationSql(condition, orders, associationLink), params, simpleSqlBuilder.getRowMapper(associationLink), paging);}@Overridepublic List<E> queryAll(Class<?>... associationLink) throws DaoAccessException {String orders = null;return queryAll(orders, associationLink);}@Overridepublic List<E> queryAll(String orders, Class<?>... associationLink) throws DaoAccessException {return query(null, orders, associationLink);}@Overridepublic DataStore<E> queryAll(PagingParameter paging, Class<?>... associationLink) throws DaoAccessException {return queryAll(null, paging, associationLink);}@Overridepublic DataStore<E> queryAll(String orders, PagingParameter paging, Class<?>... associationLink) throws DaoAccessException {return query(null, orders, paging, associationLink);}@Overridepublic int count() throws DaoAccessException {return count(null);}@Overridepublic int count(Condition condition) throws DaoAccessException {try {String sql = simpleSqlBuilder.getQueryCountSql();if(condition == null) {return jdbcTemplate.queryForInt(sql);}sql += " WHERE " + condition.toSqlString();logger.debug(sql);return jdbcTemplate.queryForInt(sql, condition.getParameters());} catch (Exception e) {throw new DaoAccessException(e);}}@Overridepublic <K extends Number> void deletes(List<K> ids) throws DaoAccessException {if(CollectionUtils.isEmpty(ids)) {return;}try {List<Object[]> batchArgs = new ArrayList<Object[]>();for (K id : ids) {batchArgs.add(new Object[]{id});}jdbcTemplate.batchUpdate(simpleSqlBuilder.getDeleteSql(), batchArgs);} catch (Exception e) {throw new DaoAccessException(e);}}@Overridepublic <K extends Number> void saves(List<E> entitys, K... ids) throws DaoAccessException {if(CollectionUtils.isEmpty(entitys)) {return;}try {int entityCount = entitys.size();int idCount = ids.length;if(idCount > entityCount) {idCount = entityCount;}List<E> withIdEntitys = entitys.subList(0, idCount);List<E> withoutIdEntitys = entitys.subList(idCount, entityCount);if(CollectionUtils.isNotEmpty(withIdEntitys)) {Map<String, Object>[] batchArgs = new Map[idCount];for (int i = 0; i < idCount; i++) {E entity = withIdEntitys.get(i);if(!entity.isTransient()) {throw new DuplicateRecordException(ErrorCode.DUPLICATE_RECORDE_AS_SAVE_ENTITY, "The record that whoes id equals " + entity.identityString() + " is already exist!");}batchArgs[i] = simpleSqlBuilder.getAllSqlParameter(entity);batchArgs[i].put(simpleSqlBuilder.getIdField(), ids[i]);}namedParameterJdbcTemplate.batchUpdate(simpleSqlBuilder.getIncludeIdFieldInsertSql(), batchArgs);}if(CollectionUtils.isNotEmpty(withoutIdEntitys)) {Map<String, Object>[] batchArgs = new Map[withoutIdEntitys.size()];for (int i = 0; i < batchArgs.length; i++) {E entity = withoutIdEntitys.get(i);if(!entity.isTransient()) {throw new DuplicateRecordException(ErrorCode.DUPLICATE_RECORDE_AS_SAVE_ENTITY, "The record that whoes id equals " + entity.identityString() + " is already exist!");}batchArgs[i] = simpleSqlBuilder.getAllSqlParameter(entity);}namedParameterJdbcTemplate.batchUpdate(simpleSqlBuilder.getInsertSql(), batchArgs);}} catch (Exception e) {throw new DaoAccessException(e);}}@Overridepublic void updates(List<E> entitys) throws DaoAccessException {if(CollectionUtils.isEmpty(entitys)) {return;}try {Map<String, Object>[] batchArgs = new Map[entitys.size()];for (int i = 0; i < batchArgs.length; i++) {E entity = entitys.get(i);if(entity.isTransient()) {throw new IllegalRecordException(ErrorCode.ILLEGAL_RECORD_AS_UPDATE_TRANSIENT,"The record " + entity + " is transient!");}batchArgs[i] = simpleSqlBuilder.getAllSqlParameter(entity);}namedParameterJdbcTemplate.batchUpdate(simpleSqlBuilder.getUpdateSql(), batchArgs);} catch (Exception e) {throw new DaoAccessException(e);}}@Overridepublic void saveOrUpdates(List<E> entitys) throws DaoAccessException {if(CollectionUtils.isEmpty(entitys)) {return;}List<E> saves = new ArrayList<E>();List<E> updates = new ArrayList<E>();for (E entity : entitys) {if(entity.isTransient()) {saves.add(entity);} else {updates.add(entity);}}saves(saves);updates(updates);}@Overridepublic E getReferenced(E entity) throws DaoAccessException {return getReferenced(entity, entityClass);}@Overridepublic E getReferenced(Object referenceValue) throws DaoAccessException {return getReferenced(referenceValue, entityClass);}@Overridepublic <R extends Entity> R getReferenced(E entity, Class<R> referencedClass) throws DaoAccessException {Object value = null;try {String field = simpleSqlBuilder.getReferenceField(referencedClass);if(field == null) {throw new AnnotationNotFoundException(ErrorCode.ANNOTATION_NOT_FOUND_AS_REFERENCE, "Annotation " + Reference.class.getName() + " not found for referenced " +referencedClass.getName() + " of " + entityClass.getName());}value = new PropertyDescriptor(field, entityClass).getReadMethod().invoke(entity);} catch (Exception e) {throw new DaoAccessException(e);}if(value == null) {return null;}return getReferenced(value, referencedClass);}@Overridepublic <R extends Entity> R getReferenced(Object referenceValue,Class<R> referencedClass) throws DaoAccessException {try {String referencedColumn = simpleSqlBuilder.getReferencedColumn(referencedClass);if(referencedColumn == null) {throw new AnnotationNotFoundException(ErrorCode.ANNOTATION_NOT_FOUND_AS_REFERENCE, "Annotation " + Reference.class.getName() + " not found for referenced " +referencedClass.getName() + " of " + entityClass.getName());}SimpleSqlBuilder<R> referencedSqlBuilder = new SimpleSqlBuilder<R>(referencedClass);String sql = referencedSqlBuilder.getQueryAllSql() + " WHERE " + referencedColumn + " = ?";logger.debug(sql);return jdbcTemplate.queryForObject(sql, referencedSqlBuilder.getRowMapper(), referenceValue);} catch (Exception e) {throw new DaoAccessException(e);}}@Overridepublic <R extends Entity> List<E> queryReferences(R referenced) throws DaoAccessException {PagingParameter paging = null;return queryReferences(referenced, paging).getDatas();}@Overridepublic <R extends Entity> List<E> queryReferences(Class<R> referencedClass, Object referencedValue) throws DaoAccessException {PagingParameter paging = null;return queryReferences(referencedClass, referencedValue, paging).getDatas();}@Overridepublic <R extends Entity, S extends Entity> List<S> queryReferences(R referenced, Class<S> referenceClass) throws DaoAccessException {return queryReferences(referenced, referenceClass, null).getDatas();}@Overridepublic <R extends Entity, S extends Entity> List<S> queryReferences(Class<R> referencedClass, Object referencedValue,Class<S> referenceClass) throws DaoAccessException {return queryReferences(referencedClass, referencedValue, referenceClass, null).getDatas();}@Overridepublic <R extends Entity> DataStore<E> queryReferences(R referenced,PagingParameter paging) throws DaoAccessException {Object value = getReferencedValue(referenced);if(value == null) {return null;}return queryReferences(referenced.getClass(), value, paging);}@Overridepublic <R extends Entity> DataStore<E> queryReferences(Class<R> referencedClass, Object referencedValue,PagingParameter paging) throws DaoAccessException {String sql = null;try {String field = simpleSqlBuilder.getReferenceField(referencedClass);if(field == null) {throw new AnnotationNotFoundException(ErrorCode.ANNOTATION_NOT_FOUND_AS_REFERENCE, "Annotation " + Reference.class.getName() + " not found for referenced " +referencedClass.getName() + " of " + entityClass.getName());}sql = simpleSqlBuilder.getQueryAllSql() + " WHERE " + simpleSqlBuilder.getFieldColumnMapping().get(field) + " = ? ORDER BY " +simpleSqlBuilder.getFieldColumnMapping().get(simpleSqlBuilder.getIdField());} catch (Exception e) {throw new DaoAccessException(e);}return queryDataStore(sql, new Object[]{referencedValue}, simpleSqlBuilder.getRowMapper(), paging);}@Overridepublic <R extends Entity, S extends Entity> DataStore<S> queryReferences(R referenced, Class<S> referenceClass, PagingParameter paging) throws DaoAccessException {Object value = getReferencedValue(referenced);if(value == null) {return null;}return queryReferences(referenced.getClass(), value, referenceClass, paging);}@Overridepublic <R extends Entity, S extends Entity> DataStore<S> queryReferences(Class<R> referencedClass, Object referencedValue,Class<S> referenceClass, PagingParameter paging) throws DaoAccessException {String sql = null;SimpleSqlBuilder<S> referenceSqlBuilder = null;try {String referencedColumn = simpleSqlBuilder.getReferencedColumn(referenceClass);if(referencedColumn == null) {throw new AnnotationNotFoundException(ErrorCode.ANNOTATION_NOT_FOUND_AS_REFERENCE, "Annotation " + Reference.class.getName() + " not found for referenced " +referenceClass.getName() + " of " + entityClass.getName());}String field = simpleSqlBuilder.getReferenceField(referencedClass);if(field == null) {throw new AnnotationNotFoundException(ErrorCode.ANNOTATION_NOT_FOUND_AS_REFERENCE, "Annotation " + Reference.class.getName() + " not found for referenced " +referencedClass.getName() + " of " + entityClass.getName());}referenceSqlBuilder = new SimpleSqlBuilder<S>(referenceClass);sql = referenceSqlBuilder.getQueryAllSql() + " WHERE " + referencedColumn + " IN (SELECT " + simpleSqlBuilder.getFieldColumnMapping().get(simpleSqlBuilder.getReferenceField(referenceClass)) + " FROM " + simpleSqlBuilder.getTableName() + " WHERE " + simpleSqlBuilder.getFieldColumnMapping().get(field) + " = ?) ORDER BY " + referenceSqlBuilder.getFieldColumnMapping().get(referenceSqlBuilder.getIdField());} catch (Exception e) {throw new DaoAccessException(e);}return queryDataStore(sql, new Object[]{referencedValue}, referenceSqlBuilder.getRowMapper(), paging);}/** * 根据被引用对象获得外键属性值 * * @param <R> * @param referenced * @return * 创建日期:2012-10-8 * 修改说明: * @author wangk */private <R extends Entity> Object getReferencedValue(R referenced) throws DaoAccessException {try {Class<R> referencedClass = (Class<R>)referenced.getClass();String referencedColumn = simpleSqlBuilder.getReferencedColumn(referencedClass);if(referencedColumn == null) {throw new AnnotationNotFoundException(ErrorCode.ANNOTATION_NOT_FOUND_AS_REFERENCE, "Annotation " + Reference.class.getName() + " not found for referenced " +referencedClass.getName() + " of " + entityClass.getName());}SimpleSqlBuilder<R> referencedSqlBuilder = new SimpleSqlBuilder<R>(referencedClass);String columnField = referencedSqlBuilder.getColumnField(referencedColumn);if(columnField == null) {throw new FieldColumnMappingException(ErrorCode.FIELD_COLUMN_MAPPING_AS_NOT_EXIST_COLUMN, "ColumnName " + referencedColumn + " not exist for " + referencedClass.getName());}return new PropertyDescriptor(columnField, referencedClass).getReadMethod().invoke(referenced);} catch (Exception e) {throw new DaoAccessException(e);}}/** * 构建关联查询SQL语句 * * @param condition       查询条件 * @param orders          排序对象 * @param associationLink 关联链 * @return String         关联查询SQL语句 * 创建日期:2012-12-5 * 修改说明: * @author wangk */@SuppressWarnings({ "rawtypes", "unchecked" })private String buildAssociationSql(Condition condition, String orders, Class<?>[] associationLink) throws DaoAccessException {try {if(associationLink == null) {associationLink = simpleSqlBuilder.getAssociationLink();}StringBuilder sb1 = new StringBuilder();StringBuilder sb2 = new StringBuilder();String tableName = simpleSqlBuilder.getTableName() + "_0";Map<String, String> fieldColumnMapping = simpleSqlBuilder.getFieldColumnMapping();for (String field : fieldColumnMapping.keySet()) {sb1.append(tableName +  "." + fieldColumnMapping.get(field) + " AS " + tableName +  "_" + fieldColumnMapping.get(field) + ", ");}sb2.append(simpleSqlBuilder.getTableName()).append(" AS ").append(tableName);//关联类型三标志(被关联类型下标、被关联类型、关联类型)集合List<List<Object>> associationFlags = new ArrayList<List<Object>>();for (int i = 0;i < associationLink.length;i++) {Class<?> tempClass = associationLink[i];if(!ObjectUtil.isExtends(tempClass, Entity.class)) {throw new FieldColumnMappingException(ErrorCode.FIELD_COLUMN_MAPPING_AS_ASSOCIATION_TYPE_ERROR,"Association " + tempClass.getName() + " type error for " +entityClass.getName() + ", the type must extends Entity!");}Class<? extends Entity> associationClass = (Class<? extends Entity>)tempClass;SimpleSqlBuilder<? extends Entity> associationSqlBuilder = new SimpleSqlBuilder(associationClass);Class<? extends Entity> clazz = null;SimpleSqlBuilder<? extends Entity> sqlBuilder = null;int j = -1;for (; j < i; j++) {if(j >= 0) {clazz = (Class<? extends Entity>)associationLink[j];} else {clazz = entityClass;}sqlBuilder = new SimpleSqlBuilder(clazz);if(sqlBuilder.getAssociationField(associationClass) != null) {List<Object> associationFlag = new ArrayList<Object>();associationFlag.add(j + 1);associationFlag.add(clazz);associationFlag.add(associationClass);if(!associationFlags.contains(associationFlag)) {//检查指定的关联类型对应的引用属性是否存在sqlBuilder.checkExistReferenceField(associationClass);associationFlags.add(associationFlag);break;}}}if(j == i) {throw new AnnotationNotFoundException(ErrorCode.ANNOTATION_NOT_FOUND_AS_ASSOCIATION,"Annotation " + Association.class.getName() + " not found for association " +associationClass.getName() + " of " + entityClass.getName());}String tableName2 = associationSqlBuilder.getTableName() + "_" + (i + 1);Map<String, String> fieldColumnMapping2 = associationSqlBuilder.getFieldColumnMapping();for (String field : fieldColumnMapping2.keySet()) {sb1.append(tableName2 +  "." + fieldColumnMapping2.get(field) + " AS " + tableName2 +  "_" + fieldColumnMapping2.get(field) + ", ");}String tableName1 = sqlBuilder.getTableName() + "_" + (j + 1);Map<String, String> fieldColumnMapping1 = sqlBuilder.getFieldColumnMapping();sb2.append(" LEFT JOIN " + associationSqlBuilder.getTableName() + " AS " + tableName2 + " ON " + tableName1 + "." + fieldColumnMapping1.get(sqlBuilder.getReferenceField(associationClass)) + " = " + tableName2 + "." + sqlBuilder.getReferencedColumn(associationClass));}sb1.delete(sb1.length() - 2, sb1.length());String sql = "SELECT " + sb1 + " FROM " + sb2;if(condition != null) {sql += " WHERE " + handleSqlColumnPrefix(condition.toSqlString(), associationLink);}if(orders == null) {orders = simpleSqlBuilder.getFieldColumnMapping().get(simpleSqlBuilder.getIdField());}sql += " ORDER BY " + handleSqlColumnPrefix(orders, associationLink);logger.debug(sql);return sql;} catch (Exception e) {throw new DaoAccessException(e);}}/** * 处理SQL子句的列名前缀,以区分来自不同的表 * 1. 没有前缀则加上:entityClass#tableName_0. *  2. 有前缀但没有下标则加上下标,如entityClass#tableName.处理成entityClass#tableName_0. *     (关联链中有两个相同的类型时如果没有下标则加上第一次出现的下标,要指定后面类型的列必须带下标) *  3. entityClass下标为0,associationLink的第一个元素下标为1,依次类批(即数组下标加一) *  4. 出现的表名不能以'_数字'结尾 * * @param sql              条件SQL语句 * @param associationLink  关联链 * @return * 创建日期:2012-12-5 * 修改说明: * @author wangk */private String handleSqlColumnPrefix(String sql, Class<?>[] associationLink) {if(sql == null) {return null;}StringBuilder sb = new StringBuilder();int start = 0;int end = 0;for (int i = 0; i < sql.length(); i++) {char ch = sql.charAt(i);if(ch == '\'') {end = i;sb.append(handleSubSqlColumnPrefix(sql.substring(start, end), associationLink));start = end;for (i++; i < sql.length(); i++) {if(sql.charAt(i) == ch) {end = i + 1;sb.append(sql.substring(start, end));start = end;break;}}} else if(ch == '(' && sql.substring(i+1).trim().toUpperCase().startsWith("SELECT")) {end = i;sb.append(handleSubSqlColumnPrefix(sql.substring(start, end), associationLink));start = end;Stack<Character> stack = new Stack<Character>();stack.push(ch);for (i++; i < sql.length(); i++) {char ch2 = sql.charAt(i);if(ch2 == ch) {stack.push(ch);} else if(ch2 == ')') {stack.pop();}if(stack.isEmpty()) {end = i + 1;sb.append(sql.substring(start, end));start = end;break;}}}}end = sql.length();sb.append(handleSubSqlColumnPrefix(sql.substring(start, end), associationLink));return sb.toString().trim();}/** * 处理一段SQL子句的列名前缀,不包含子查询和字符串数据 * * @param subSql          一段SQL子句 * @param associationLink 关联链 * @return String         处理结果,结尾带空格 * 创建日期:2012-12-6 * 修改说明: * @author wangk */private String handleSubSqlColumnPrefix(String subSql, Class<?>[] associationLink) {//处理组合符号(= -> #, < -> @, > -> &)subSql = subSql.replaceAll("\\s*<>\\s*", " @& ").replaceAll("\\s*<=\\s*", " @# ").replaceAll("\\s*>=\\s*", " &# ");for (String operator : CONDITION_OPERATORS) {//处理单个符号subSql = subSql.replaceAll("\\s*" + operator + "\\s*", " " + operator + " ");}subSql = subSql.replaceAll("@&", "<>").replaceAll("@#", "<=").replaceAll("&#", ">=");String[] strings = subSql.split("\\s+");StringBuilder sb = new StringBuilder();for (String string : strings) {if(string.matches("^[A-Za-z_][\\w]*(\\.\\w+)?$") && !CONDITION_KEYWORDS.contains(string.toUpperCase())) {sb.append(handleColumnPrefix(string, associationLink));} else {sb.append(string);}sb.append(" ");}return sb.toString();}/** * 处理列名前缀 * * @param column           列名 * @param associationLink  关联链 * @return String          带前缀的列名 * 创建日期:2012-12-5 * 修改说明: * @author wangk */@SuppressWarnings({ "rawtypes", "unchecked" })private String handleColumnPrefix(String column, Class<?>[] associationLink) {if(column.indexOf(".") < 0) {return simpleSqlBuilder.getTableName() + "_0." + column;}String[] strings = column.split("\\.");String tableName = strings[0];if(!tableName.matches("^.*_\\d+$")) {int index = 0;if(!tableName.equalsIgnoreCase(simpleSqlBuilder.getTableName())) {int i = 0;for (; i < associationLink.length; i++) {if(tableName.equalsIgnoreCase(new SimpleSqlBuilder(associationLink[i]).getTableName())) {break;}}index = i + 1;}return tableName + "_" + index + "." + strings[1];}return column;}/** * 获得指定entitys的唯一实体对象,没有返回null,两个及以上抛出DuplicateRecordException * * @param entitys    实体集合 * @return * 创建日期:2012-12-6 * 修改说明: * @author wangk */private E getUniqueEntity(List<E> entitys) {if(CollectionUtils.isEmpty(entitys)) {return null;}if(entitys.size() == 1) {return entitys.get(0);}throw new DuplicateRecordException(ErrorCode.DUPLICATE_RECORDE_AS_GET_ENTITY);}/** * 保存实体对象,ID值由参数指定,如果ID指定为null则由数据库生成 * * @param <K>     ID类型参数 * @param entity  实体对象 * @param id      ID值 * @return * 创建日期:2012-12-3 * 修改说明: * @author wangk */private <K extends Number> K saveWithId(E entity, K id) throws DaoAccessException {try {if(!entity.isTransient()) {throw new DuplicateRecordException(ErrorCode.DUPLICATE_RECORDE_AS_SAVE_ENTITY,"The record " + entity + " is exist!");}Class<K> idFieldType = (Class<K>)new PropertyDescriptor(simpleSqlBuilder.getIdField(), entityClass).getPropertyType();Map<String, Object> params = simpleSqlBuilder.getSqlParameters(entity);if(id == null) {String sql = simpleSqlBuilder.getInsertSql(params.keySet());KeyHolder keyHolder = new GeneratedKeyHolder();namedParameterJdbcTemplate.update(sql, new MapSqlParameterSource(params), keyHolder);id = idFieldType.getConstructor(String.class).newInstance(keyHolder.getKey().toString());} else {params.put(simpleSqlBuilder.getIdField(), id);String sql = simpleSqlBuilder.getIncludeIdFieldInsertSql(params.keySet());namedParameterJdbcTemplate.update(sql, params);}//设置entity的ID值new PropertyDescriptor(simpleSqlBuilder.getIdField(), entityClass).getWriteMethod().invoke(entity, id);return id;} catch (Exception e) {throw new DaoAccessException(e);}}/** * 处理单表查询的SQL语句,SQL为null或空字符串或只指定WHERE子句时处理成查询全部记录 * * @param sql       SQL语句 * @return String   处理后的SQL语句 * 创建日期:2012-12-6 * 修改说明: * @author wangk */private String handleSimpleSql(String sql) {if(StringUtils.isBlank(sql)) {sql = simpleSqlBuilder.getQueryAllSql();} else if(!sql.trim().toUpperCase().startsWith("SELECT")) {if(!sql.trim().toUpperCase().startsWith("WHERE") && !sql.trim().toUpperCase().startsWith("ORDER")) {sql = "WHERE " + sql;}sql = simpleSqlBuilder.getQueryAllSql() + " " + sql;}logger.debug(sql);return sql;}/** * 根据SQL语句获取不同的RowMapper,如果指定了投影列则只映射指定列对应的属性,其他属性为null,否则映射全部属性 * * @param sql           SQL语句 * @return RowMapper<E> 记录映射对象 * 创建日期:2012-12-6 * 修改说明: * @author wangk */private RowMapper<E> getRowMapperBySql(String sql) {sql = sql.trim().toUpperCase();String projection = sql.substring(sql.indexOf("SELECT")+6, sql.indexOf("FROM")).trim();if(projection.indexOf("*") >=0) {return simpleSqlBuilder.getRowMapper();}Set<String> columns = new HashSet<String>();for (String column : projection.split(",")) {columns.add(column.trim().replaceAll("\\s.*$", ""));}return simpleSqlBuilder.getRowMapper(columns);}/** * 查询分页数据,如果指定的paging为null或参数不正确则查询出全部的数据 * * @param <T>           SQL参数类型,限制只能使用Object[]或Map<String, Object> * @param sql           SQL语句 * @param params        SQL参数 * @param rowMapper     记录映射对象 * @param paging        分页参数 * @return DataStore<E> 分页数据 * @throws DaoAccessException DAO访问异常 * 创建日期:2012-12-6 * 修改说明: * @author wangk */private <P, S extends Entity> DataStore<S> queryDataStore(String sql, P params, RowMapper<S> rowMapper, PagingParameter paging) throws DaoAccessException {try {if(paging == null || paging.isInvalid()) {if(params instanceof Map) {return new DataStore<S>(paging, namedParameterJdbcTemplate.query(sql, new MapSqlParameterSource((Map<String, Object>)params), rowMapper));}return new DataStore<S>(paging, jdbcTemplate.query(sql, rowMapper, (Object[])params));}int records = 0;if(params instanceof Map) {records = namedParameterJdbcTemplate.queryForInt(pagingSqlBuilder.getCountSql(sql), (Map<String, Object>)params);} else {records = jdbcTemplate.queryForInt(pagingSqlBuilder.getCountSql(sql), (Object[])params);}if(records < 0) {return null;}if(records == 0) {return new DataStore<S>(records, new ArrayList<S>());}if(params instanceof Map) {return new DataStore<S>(records, namedParameterJdbcTemplate.query(pagingSqlBuilder.getPagingSql(sql, paging), new MapSqlParameterSource((Map<String, Object>)params), rowMapper));}return new DataStore<S>(records, jdbcTemplate.query(pagingSqlBuilder.getPagingSql(sql, paging), rowMapper, (Object[])params));} catch (Exception e) {throw new DaoAccessException(e);}}}


package com.flong.commons.persistence.dao;import java.util.List;import java.util.Map;import com.flong.commons.lang.exception.DaoAccessException;import com.flong.commons.persistence.bean.DataStore;import com.flong.commons.persistence.bean.PagingParameter;import com.flong.commons.persistence.condition.Condition;import com.flong.commons.persistence.interfaces.MapRowMapper;/** * 数据查询DAO接口 * * 创建日期:2012-9-26 * @author wangk */public interface BaseDao {/** * 查询SQL语句 * * @param sql                        SQL语句 * @param params                     SQL参数 * @return List<Map<String, Object>> 查询结果 * 创建日期:2012-9-26 * 修改说明: * @author wangk */public List<Map<String, Object>> search(String sql, Object... params) throws DaoAccessException;public List<Map<String, Object>> search(String sql, List<Object> params) throws DaoAccessException;public List<Map<String, Object>> search(String sql, Map<String, Object> params) throws DaoAccessException;/** * 查询SQL语句 * * @param <R>           行记录类型 * @param sql           SQL语句 * @param mapRowMapper  Map行数据映射对象 * @param params        SQL参数  * @return List<R>      查询结果 * 创建日期:2012-9-26 * 修改说明: * @author wangk */public <R> List<R> search(String sql, MapRowMapper<R> mapRowMapper, Object... params) throws DaoAccessException;public <R> List<R> search(String sql, MapRowMapper<R> mapRowMapper, List<Object> params) throws DaoAccessException;public <R> List<R> search(String sql, MapRowMapper<R> mapRowMapper, Map<String, Object> params) throws DaoAccessException;/** * 分页查询数据 * * @param sql                             SQL语句 * @param paging                          分页参数 * @param params                          SQL参数 * @return DataStore<Map<String, Object>> 分页数据 * 创建日期:2012-9-26 * 修改说明: * @author wangk */public DataStore<Map<String, Object>> search(String sql, PagingParameter paging, Object... params) throws DaoAccessException;public DataStore<Map<String, Object>> search(String sql, PagingParameter paging, List<Object> params) throws DaoAccessException;public DataStore<Map<String, Object>> search(String sql, PagingParameter paging, Map<String, Object> params) throws DaoAccessException;/** * 分页查询数据 * * @param <R>           行记录类型 * @param sql           SQL语句 * @param mapRowMapper  Map行数据映射对象 * @param paging        分页参数 * @param params        SQL参数 * @return DataStore<R> 分页数据 * 创建日期:2012-9-26 * 修改说明: * @author wangk */public <R> DataStore<R> search(String sql, MapRowMapper<R> mapRowMapper, PagingParameter paging, Object... params) throws DaoAccessException;public <R> DataStore<R> search(String sql, MapRowMapper<R> mapRowMapper, PagingParameter paging, List<Object> params) throws DaoAccessException;public <R> DataStore<R> search(String sql, MapRowMapper<R> mapRowMapper, PagingParameter paging, Map<String, Object> params) throws DaoAccessException;/** * 连接查询 * * @param condition                  查询条件,指定列格式:表名.列名 * @param classLink                  连接实体类类型链 * @return List<Map<String, Object>> 查询结果,Map.key: 对象名(Class指定的类名的首字母小写形式).属性名 * 创建日期:2012-10-19 * 修改说明: * @author wangk */public List<Map<String, Object>> join(Condition condition, Class<?>... classLink) throws DaoAccessException;/** * 连接查询 * * @param condition 查询条件 * @param orders    排序对象 * @param classLink 连接实体类类型链 * @return          查询结果 * 创建日期:2012-10-19 * 修改说明: * @author wangk */public List<Map<String, Object>> join(Condition condition, String orders, Class<?>... classLink) throws DaoAccessException;/** * 连接查询(内连接) * * @param <R>          映射类型参数 * @param condition    查询条件 * @param mapRowMapper 行匹配对象 * @param classLink    连接实体类型链(从子表到父表的顺序) * @return * 创建日期:2012-10-19 * 修改说明: * @author wangk */public <R> List<R> join(Condition condition, MapRowMapper<R> mapRowMapper, Class<?>... classLink) throws DaoAccessException;/** * 连接查询 * * @param <R>          映射类型参数 * @param condition    查询条件 * @param orders       排序对象 * @param mapRowMapper 行匹配对象 * @param classLink    连接实体类型链 * @return * 创建日期:2012-10-19 * 修改说明: * @author wangk */public <R> List<R> join(Condition condition, String orders, MapRowMapper<R> mapRowMapper, Class<?>... classLink) throws DaoAccessException;/** * 连接查询 * * @param condition   查询条件 * @param paging      分页参数 * @param classLink   连接实体类型链 * @return * 创建日期:2012-10-19 * 修改说明: * @author wangk */public DataStore<Map<String, Object>> join(Condition condition, PagingParameter paging, Class<?>... classLink) throws DaoAccessException;/** * 连接查询 * * @param condition  查询条件 * @param orders     排序对象 * @param paging     分页参数 * @param classLink  连接实体类型链 * @return * 创建日期:2012-10-19 * 修改说明: * @author wangk */public DataStore<Map<String, Object>> join(Condition condition, String orders, PagingParameter paging, Class<?>... classLink) throws DaoAccessException;/** * 连接查询 * * @param <R>          映射类型参数 * @param condition    查询条件 * @param mapRowMapper 行匹配对象 * @param paging       分页参数 * @param classLink    连接实体类型链 * @return * 创建日期:2012-10-19 * 修改说明: * @author wangk */public <R> DataStore<R> join(Condition condition, MapRowMapper<R> mapRowMapper, PagingParameter paging, Class<?>... classLink) throws DaoAccessException;/** * 连接查询 * * @param <R>          映射类型参数 * @param condition    查询条件 * @param orders       排序对象 * @param mapRowMapper 行匹配对象 * @param paging       分页参数 * @param classLink    连接实体类型链 * @return * 创建日期:2012-10-19 * 修改说明: * @author wangk */public <R> DataStore<R> join(Condition condition, String orders, MapRowMapper<R> mapRowMapper, PagingParameter paging, Class<?>... classLink) throws DaoAccessException;}

package com.flong.commons.persistence.dao.impl;import java.util.ArrayList;import java.util.List;import java.util.Map;import org.apache.commons.collections.CollectionUtils;import org.apache.log4j.Logger;import org.springframework.beans.factory.InitializingBean;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;import com.flong.commons.lang.exception.DaoAccessException;import com.flong.commons.persistence.Entity;import com.flong.commons.persistence.bean.DataStore;import com.flong.commons.persistence.bean.PagingParameter;import com.flong.commons.persistence.builder.PagingSqlBuilder;import com.flong.commons.persistence.builder.SimpleSqlBuilder;import com.flong.commons.persistence.condition.Condition;import com.flong.commons.persistence.dao.BaseDao;import com.flong.commons.persistence.interfaces.ISQLQuery;import com.flong.commons.persistence.interfaces.MapRowMapper;import com.mchange.v2.c3p0.ComboPooledDataSource;/** * 数据查询DAO支持类 * * 创建日期:2012-9-26 * @author wangk */public abstract class BaseDaoSupport implements BaseDao, InitializingBean {/** 日志对象 */private static final Logger logger = Logger.getLogger(BaseDaoSupport.class);/** 实现类日志对象 */protected final Logger log = Logger.getLogger(getClass());@Autowired protected ISQLQuery iSQLQuery;/** JDBC模版对象 */@Autowired protected JdbcTemplate jdbcTemplate;/** SQL语句参数带名称的JDBC模版对象 */protected NamedParameterJdbcTemplate namedParameterJdbcTemplate;/** 分页SQL语句创建对象 */protected PagingSqlBuilder pagingSqlBuilder;/** * 获得JDBC模版对象 * * @return * 创建日期:2012-9-25 * 修改说明: * @author wangk */public JdbcTemplate getJdbcTemplate() {return jdbcTemplate;}/** * 获得SQL语句参数带名称的JDBC模版对象 * * @return * 创建日期:2012-12-19 * 修改说明: * @author wangk */public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {return namedParameterJdbcTemplate;}/** * 获得分页SQL语句创建对象 * * @return * 创建日期:2012-10-8 * 修改说明: * @author wangk */public PagingSqlBuilder getPagingSqlBuilder() {return pagingSqlBuilder;}/** * 初始化非注入的属性 *  * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() * 创建日期:2012-12-19 * 修改说明: * @author wangk */@Overridepublic void afterPropertiesSet() throws Exception {//初始化namedParameterJdbcTemplatenamedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource());//初始化pagingSqlBuilderpagingSqlBuilder = new PagingSqlBuilder(((ComboPooledDataSource)jdbcTemplate.getDataSource()).getJdbcUrl().replaceAll("://.*$", ""));}@Overridepublic List<Map<String, Object>> search(String sql, Object... params) throws DaoAccessException {try {logger.debug(sql);return jdbcTemplate.queryForList(sql, params);} catch (Exception e) {throw new DaoAccessException(e);}}@Overridepublic List<Map<String, Object>> search(String sql, List<Object> params) throws DaoAccessException {return search(sql, params.toArray());}@Overridepublic List<Map<String, Object>> search(String sql, Map<String, Object> params) throws DaoAccessException {try {logger.debug(sql);return namedParameterJdbcTemplate.queryForList(sql, params);} catch (Exception e) {throw new DaoAccessException(e);}}@Overridepublic <R> List<R> search(String sql, MapRowMapper<R> mapRowMapper, Object... params) throws DaoAccessException {List<Map<String, Object>> list = search(sql, params);if(list == null) {return null;}List<R> ret = new ArrayList<R>();for (int i = 0; i < list.size(); i++) {ret.add(mapRowMapper.mapRow(list.get(i), i));}return ret;}@Overridepublic <R> List<R> search(String sql, MapRowMapper<R> mapRowMapper,List<Object> params) throws DaoAccessException {return search(sql, mapRowMapper, params.toArray());}@Overridepublic <R> List<R> search(String sql, MapRowMapper<R> mapRowMapper,Map<String, Object> params) throws DaoAccessException {List<Map<String, Object>> list = search(sql, params);if(list == null) {return null;}List<R> ret = new ArrayList<R>();for (int i = 0; i < list.size(); i++) {ret.add(mapRowMapper.mapRow(list.get(i), i));}return ret;}@Overridepublic DataStore<Map<String, Object>> search(String sql, PagingParameter paging,Object... params) throws DaoAccessException {try {PagingSqlBuilder pagingSqlBuilder = getPagingSqlBuilder();int records = jdbcTemplate.queryForInt(pagingSqlBuilder.getCountSql(sql), params);if(records < 0) {return null;}if(records == 0) {return new DataStore<Map<String, Object>>(records, new ArrayList<Map<String, Object>>());}return new DataStore<Map<String, Object>>(records, search(pagingSqlBuilder.getPagingSql(sql, paging), params));} catch (Exception e) {throw new DaoAccessException(e);}}@Overridepublic DataStore<Map<String, Object>> search(String sql,PagingParameter paging, List<Object> params) throws DaoAccessException {return search(sql, paging, params.toArray());}@Overridepublic DataStore<Map<String, Object>> search(String sql,PagingParameter paging, Map<String, Object> params) throws DaoAccessException {try {PagingSqlBuilder pagingSqlBuilder = getPagingSqlBuilder();int records = namedParameterJdbcTemplate.queryForInt(pagingSqlBuilder.getCountSql(sql), params);if(records < 0) {return null;}if(records == 0) {return new DataStore<Map<String, Object>>(records, new ArrayList<Map<String, Object>>());}return new DataStore<Map<String, Object>>(records, search(pagingSqlBuilder.getPagingSql(sql, paging), params));} catch (Exception e) {throw new DaoAccessException(e);}}@Overridepublic <R> DataStore<R> search(String sql, MapRowMapper<R> mapRowMapper, PagingParameter paging, Object... params) throws DaoAccessException {DataStore<Map<String, Object>> dataStore = search(sql, paging, params);if(dataStore == null) {return null;}if(dataStore.getDatas() == null) {return new DataStore<R>(dataStore.getRecords(), null);}List<R> list = new ArrayList<R>();for (int i = 0; i < dataStore.getDatas().size(); i++) {list.add(mapRowMapper.mapRow(dataStore.getDatas().get(i), i));}return new DataStore<R>(dataStore.getRecords(), list);}@Overridepublic <R> DataStore<R> search(String sql, MapRowMapper<R> mapRowMapper,PagingParameter paging, List<Object> params) throws DaoAccessException {return search(sql, mapRowMapper, paging, params.toArray());}@Overridepublic <R> DataStore<R> search(String sql, MapRowMapper<R> mapRowMapper,PagingParameter paging, Map<String, Object> params) throws DaoAccessException {DataStore<Map<String, Object>> dataStore = search(sql, paging, params);if(dataStore == null) {return null;}if(dataStore.getDatas() == null) {return new DataStore<R>(dataStore.getRecords(), null);}List<R> list = new ArrayList<R>();for (int i = 0; i < dataStore.getDatas().size(); i++) {list.add(mapRowMapper.mapRow(dataStore.getDatas().get(i), i));}return new DataStore<R>(dataStore.getRecords(), list);}@Overridepublic List<Map<String, Object>> join(Condition condition,Class<?>... classLink) throws DaoAccessException {String orders = null;return join(condition, orders, classLink);}@Overridepublic List<Map<String, Object>> join(Condition condition, String orders,Class<?>... classLink) throws DaoAccessException {String sql = buildJoinSql(condition, orders, classLink);List<Map<String, Object>> result = null;if(condition == null) {result = search(sql);} else {result = search(sql, condition.getParameters());}convertJoinResult(result, classLink);return result;}@Overridepublic <R> List<R> join(Condition condition, MapRowMapper<R> mapRowMapper,Class<?>... classLink) throws DaoAccessException {return join(condition, null, mapRowMapper, classLink);}@Overridepublic <R> List<R> join(Condition condition, String orders,MapRowMapper<R> mapRowMapper, Class<?>... classLink) throws DaoAccessException {List<Map<String, Object>> list = join(condition, orders, classLink);if(list == null) {return null;}List<R> ret = new ArrayList<R>();for (int i = 0; i < list.size(); i++) {ret.add(mapRowMapper.mapRow(list.get(i), i));}return ret;}@Overridepublic DataStore<Map<String, Object>> join(Condition condition,PagingParameter paging, Class<?>... classLink) throws DaoAccessException {String orders = null;return join(condition, orders , paging, classLink);}@Overridepublic DataStore<Map<String, Object>> join(Condition condition,String orders, PagingParameter paging,Class<?>... classLink) throws DaoAccessException {PagingSqlBuilder pagingSqlBuilder = getPagingSqlBuilder();String sql = buildJoinSql(condition, orders, classLink);Object[] params = new Object[0];if(condition != null) {params = condition.getParameters();}int records = 0;try {records = jdbcTemplate.queryForInt(pagingSqlBuilder.getCountSql(sql), params);} catch (Exception e) {throw new DaoAccessException(e);}if(records < 0) {return null;}if(records == 0) {return new DataStore<Map<String, Object>>(records, new ArrayList<Map<String, Object>>());}List<Map<String, Object>> datas = null;datas = search(pagingSqlBuilder.getPagingSql(sql, paging), params);convertJoinResult(datas, classLink);return new DataStore<Map<String, Object>>(records, datas);}@Overridepublic <R> DataStore<R> join(Condition condition,MapRowMapper<R> mapRowMapper, PagingParameter paging,Class<?>... classLink) throws DaoAccessException {return join(condition, null, mapRowMapper, paging, classLink);}@Overridepublic <R> DataStore<R> join(Condition condition, String orders,MapRowMapper<R> mapRowMapper, PagingParameter paging,Class<?>... classLink) throws DaoAccessException {DataStore<Map<String, Object>> dataStore = join(condition, orders, paging, classLink);if(dataStore == null) {return null;}if(dataStore.getDatas() == null) {return new DataStore<R>(dataStore.getRecords(), null);}List<R> list = new ArrayList<R>();for (int i = 0; i < dataStore.getDatas().size(); i++) {list.add(mapRowMapper.mapRow(dataStore.getDatas().get(i), i));}return new DataStore<R>(dataStore.getRecords(), list);}/** * 构建(内)连接SQL语句 * * @param condition * @param orders * @param classLink * @return * 创建日期:2012-10-19 * 修改说明: * @author wangk */@SuppressWarnings({ "rawtypes", "unchecked" })private String buildJoinSql(Condition condition, String orders,Class<?>... classLink) throws DaoAccessException {try {StringBuilder sb1 = new StringBuilder();StringBuilder sb2 = new StringBuilder();for (int i = 0;i < classLink.length;i++) {Class<? extends Entity> clazz = (Class<? extends Entity>)classLink[i];SimpleSqlBuilder<? extends Entity> sqlBuilder1 = new SimpleSqlBuilder(clazz);String tableName1 = sqlBuilder1.getTableName();Map<String, String> fieldColumnMapping1 = sqlBuilder1.getFieldColumnMapping();for (String field : sqlBuilder1.getFieldColumnMapping().keySet()) {sb1.append(tableName1 +  "." + fieldColumnMapping1.get(field) + " AS " + tableName1 +  "_" + fieldColumnMapping1.get(field) + ", ");}if(i == classLink.length - 1) {break;}Class<? extends Entity> rClass = (Class<? extends Entity>)classLink[i+1];SimpleSqlBuilder<? extends Entity> sqlBuilder2 = new SimpleSqlBuilder(rClass);String tableName2 = sqlBuilder2.getTableName();if(i == 0) {sb2.append(tableName1);}sb2.append(" JOIN " + tableName2 + " ON " + tableName1 + "." + fieldColumnMapping1.get(sqlBuilder1.getReferenceField(rClass)) + " = " + tableName2 + "." + sqlBuilder1.getReferencedColumn(rClass));}sb1.delete(sb1.length() - 2, sb1.length());String sql = "SELECT " + sb1 + " FROM " + sb2;if(condition != null) {sql += " WHERE " + condition.toSqlString();}if(orders != null) {sql += " ORDER BY " + orders;}logger.debug(sql);return sql;} catch (Exception e) {throw new DaoAccessException(e);}}/** * 转换连接查询结果,Map对象的key值为:对象名.属性名 * * @param result * @param classLink * 创建日期:2012-10-19 * 修改说明: * @author wangk */private void convertJoinResult(List<Map<String, Object>> result, Class<?>... classLink) throws DaoAccessException {if(CollectionUtils.isEmpty(result)) {return;}for (Map<String, Object> map : result) {try {for (Class<?> clazz : classLink) {@SuppressWarnings({ "rawtypes", "unchecked" })SimpleSqlBuilder<? extends Entity> sqlBuilder = new SimpleSqlBuilder(clazz);String tableName = sqlBuilder.getTableName();Map<String, String> fieldColumnMapping = sqlBuilder.getFieldColumnMapping();String className = clazz.getSimpleName();String variableName = className.substring(0, 1).toLowerCase() + className.substring(1);for (String field : fieldColumnMapping.keySet()) {map.put(variableName + "." + field, map.remove(tableName + "_" + fieldColumnMapping.get(field)));}}} catch (Exception e) {throw new DaoAccessException(e);}}}}

package com.flong.commons.persistence.dao.impl;import java.io.BufferedReader;import java.io.File;import java.io.FileReader;import java.sql.Connection;import java.sql.DatabaseMetaData;import java.sql.ResultSet;import java.sql.SQLException;import javax.sql.DataSource;import org.apache.commons.lang3.StringUtils;import org.apache.log4j.Logger;import org.springframework.jdbc.core.RowMapper;import org.springframework.jdbc.datasource.DataSourceUtils;import org.springframework.stereotype.Repository;import com.flong.commons.lang.exception.DaoAccessException;import com.flong.commons.persistence.DbVersion;import com.flong.commons.persistence.SqlScriptReader;import com.flong.commons.persistence.dao.DbVersionDao;/** * 数据库版本dao实现 * 创建日期:2013-1-7 * @author niezhegang */@Repositorypublic class DbVersionDaoImpl extends EntityDaoSupport<DbVersion> implements DbVersionDao {/**目前支持的可升级数据库类型名称*/private String[] dbTypeNames = {"mysql"};/***/private Logger logger = Logger.getLogger(this.getClass());/**查询当前版本的SQL语句*/private String queryCurrentVersionSQL = "select id,version from "+DbVersion.TABLENAME;private String updateToNextVersionSQL = "update " + DbVersion.TABLENAME+" set version = version + 1";/** * @see com.flong.commons.persistence.dao.DbVersionDao#getCurrentVersion() * 创建日期:2013-1-7 * 修改说明: * @author niezhegang */@Overridepublic DbVersion getCurrentVersion() throws DaoAccessException {return jdbcTemplate.queryForObject(queryCurrentVersionSQL, new RowMapper<DbVersion>(){@Overridepublic DbVersion mapRow(ResultSet arg0, int arg1)throws SQLException {DbVersion version = new DbVersion();version.setId(arg0.getLong(1)); version.setVersionNumber(arg0.getInt(2)); return version;}});}/** * @see com.flong.commons.persistence.dao.DbVersionDao#updateToNextVersion() * 创建日期:2013-1-7 * 修改说明: * @author niezhegang */@Overridepublic void updateToNextVersion() throws DaoAccessException {jdbcTemplate.update(updateToNextVersionSQL);}/** * @see com.flong.commons.persistence.dao.DbVersionDao#isInitVersion() * 创建日期:2013-1-7 * 修改说明: * @author niezhegang */@Overridepublic boolean isInitVersion() throws DaoAccessException {Connection conn = null;boolean ret = false;DataSource dataSource = jdbcTemplate.getDataSource();try{conn = DataSourceUtils.getConnection(dataSource);DatabaseMetaData dbmd = conn.getMetaData();ResultSet rs = dbmd.getTables(null,null,"SYS_DBVERSION",null);if(!rs.next()){ret = true;}return ret;}catch(Exception e){throw new DaoAccessException("判断是否初始化版本失败!",e);}finally{DataSourceUtils.releaseConnection(conn, dataSource);}}/** * @see com.flong.commons.persistence.dao.DbVersionDao#executeOneSQLFile(java.io.File) * 创建日期:2013-1-8 * 修改说明: * @author niezhegang */@Overridepublic void executeOneSQLFile(File updateFile) throws DaoAccessException {SqlScriptReader scriptReader = null;try{BufferedReader bufferedReader = new BufferedReader(new FileReader(updateFile));scriptReader = new SqlScriptReader(bufferedReader);String sql = scriptReader.readOneSQL();while(sql != null){if(!StringUtils.isBlank(sql)){logger.debug(sql);jdbcTemplate.execute(sql);}sql = scriptReader.readOneSQL();}}catch(Exception exception){throw new DaoAccessException(exception);}finally{if(scriptReader != null)scriptReader.close();}}/** * @see com.flong.commons.persistence.dao.DbVersionDao#getVersionDatabaseTypeName() * 创建日期:2013-1-8 * 修改说明: * @author niezhegang */@Overridepublic String getVersionDatabaseTypeName() throws DaoAccessException{Connection conn = null;String ret = null;DataSource dataSource = jdbcTemplate.getDataSource();try{conn = DataSourceUtils.getConnection(dataSource);DatabaseMetaData dbmd = conn.getMetaData();ret = queryMatchedDbname(dbmd);return ret;}catch(Exception e){throw new DaoAccessException("获取!",e);}finally{DataSourceUtils.releaseConnection(conn, dataSource);}} /** * 根据数据库元数据匹配目前支持的数据库名 * @param dbmd * @return * 创建日期:2013-1-8 * 修改说明: * @author niezhegang */private String queryMatchedDbname(DatabaseMetaData dbmd) throws SQLException{String ret = null;String driverName = dbmd.getDriverName();for(int i = 0; i < dbTypeNames.length ; i++){if(StringUtils.containsIgnoreCase(driverName, dbTypeNames[i])){ret = dbTypeNames[i];break;}}if(StringUtils.isBlank(ret))throw new RuntimeException("不支持的数据库类型:"+driverName);return ret;}}
package com.flong.commons.persistence.dao.impl;import java.beans.PropertyDescriptor;import java.io.Serializable;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import org.apache.commons.collections.CollectionUtils;import org.apache.commons.lang3.builder.ToStringBuilder;import com.flong.commons.utils.ObjectUtil;/** * 数据模型基础类 * * 创建日期:2012-11-13 * @author wangk */public abstract class BaseDomain implements Cloneable, Serializable {private static final long serialVersionUID = -3707046914855595598L;/** * @see java.lang.Object#toString() * 创建日期:2012-11-13 * 修改说明: * @author wangk */@Overridepublic String toString() {return ToStringBuilder.reflectionToString(this);}/** * 浅层复制(如果属性为引用类型则只复制属性的引用值)当前对象 * * @param <T> * @return * 创建日期:2013-1-25 * 修改说明: * @author wangk */public <T> T simpleClone() {try {@SuppressWarnings("unchecked")T ret = (T)clone();return ret;} catch (Exception e) {throw new RuntimeException(e);}}/** * 获取指定属性的值集合 * @description * @param fieldNames * @return * 创建日期:2013-1-19 * 修改说明: * @author wangk */public List<Object> getFieldValues(List<String> fieldNames) {List<Object> list = new ArrayList<Object>();if(CollectionUtils.isNotEmpty(fieldNames)){for (String fieldName : fieldNames) {try {list.add(new PropertyDescriptor(fieldName, getClass()).getReadMethod().invoke(this));} catch (Exception e) {throw new RuntimeException(e);} }}return list;}/** * 将当前对象转换成属性和值的映射 * * @return * 创建日期:2013-1-29 * 修改说明: * @author wangk */public Map<String, Object> toFieldMapping() {Map<String, Object> entrys = new HashMap<String, Object>();Map<String, Method> readMethodMapping = ObjectUtil.getReadMethodMapping(getClass());for (String field : readMethodMapping.keySet()) {try {entrys.put(field, readMethodMapping.get(field).invoke(this));} catch (Exception e) {throw new RuntimeException(e);}}return entrys;}}



<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">        <description>Spring MVC Configuration</description>         <!-- 加载配置属性文件 --><context:property-placeholder ignore-unresolvable="true" location="classpath*:/prop/DBSource.properties" /><!-- 使用Annotation自动注册Bean,只扫描@Controller --><context:component-scan base-package="com.flong"><!-- base-package 如果多个,用“,”分隔 --><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan><!-- 设置请求映射编码,解决@ResponseBody乱码问题 --><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">        <property name="messageConverters">            <list>                <bean class="org.springframework.http.converter.StringHttpMessageConverter">                    <property name="supportedMediaTypes">                        <list>                            <value>text/plain;charset=UTF-8</value>                            <!--    <value>text/html;charset=UTF-8</value> -->                            <value>application/json;charset=UTF-8</value>                           </list>                    </property>                </bean> <ref bean="mappingJacksonHttpMessageConverter"/>             </list>        </property>    </bean>    <!-- 处理JSON数据转换的 --> <!-- 为了处理返回的JSON数据的编码,默认是ISO-88859-1的,这里把它设置为UTF-8,解决有乱码的情况 --><bean id="mappingJacksonHttpMessageConverter"          class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">   <property name="supportedMediaTypes">                <list>                   <!--   <value>text/html;charset=UTF-8</value> -->                  <value>application/json;charset=UTF-8</value>          </list>           </property>        </bean>  <!-- 默认的注解映射的支持,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping --><mvc:annotation-driven/><!-- 对静态资源文件的访问, 将无法mapping到Controller的path交给default servlet handler处理 --><mvc:default-servlet-handler/> <!-- 视图文件解析配置 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="${web.view.prefix}"/><property name="suffix" value="${web.view.suffix}"/></bean><!-- 定义无Controller的path<->view直接映射 --><mvc:view-controller path="/" view-name="redirect:${web.view.index}"/> <!-- 上传文件拦截,设置最大上传文件大小   10M=10*1024*1024(B)=10485760 bytes -->      <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">          <property name="maxUploadSize" value="${web.maxUploadSize}" />      </bean>      <!-- 这个映射配置主要是用来进行静态资源的访问  对静态资源文件的访问, 将无法mapping到Controller的path交给default servlet handler处理 <mvc:default-servlet-handler/>同等如下配置  <mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"/> <mvc:resources mapping="/css/**" location="/css/" />  <mvc:resources mapping="/**/**" location="/" />      <mvc:resources mapping="/WEB-INF/view/**" location="/WEB-INF/view/" />  -->  </beans>




项目图解分析简单说明









代码下载 http://download.csdn.net/detail/jilongliang/9321581

1 0
原创粉丝点击