本人封装的dao层的泛型实现,目前只支持mysql
精华的4个类的代码贴出来了,commons是完整的代码,entityapp是自动代码生成器
这个dao层封装的优点在于:
1.dao层基本不用写任何代码,因为EntityDaoSupport 这个类已经涵盖大多数的数据库操作
2.完整的代码中有个CascadeParamMethodArgumentResolver的类可以用来解决spring mvc中表示层方法参数中复杂对象参数的映射,级联参数格式:a.b.c (表单参数) 或 a[b][c] (ajax请求对象参数),这个类要配置在xml文件中
3.还有一些常用的Converter类,这些也是要配置的,配置后就不需要手工转换了
这个的缺点:
1.底层用了大量的反射和泛型,尚不清楚会不会影响程序的性能,不过我做的项目吞吐量也挺大的,没有发现严重的问题
精华的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;
@Override
public 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;
}
@Override
public 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);
}
@Override
public 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;
//初始化simpleSqlBuilder
simpleSqlBuilder = 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;
}
@Override
public <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) {
//只处理空结果异常,表示没有对应的记录,返回null
logger.warn(e);
return null;
} catch (Exception e) {
throw new DaoAccessException(e);
}
}
return get(Condition.eq(simpleSqlBuilder.getFieldColumnMapping().get(
simpleSqlBuilder.getIdField()), id), associationLink);
}
@Override
public E get(String sql, Object... params) throws DaoAccessException {
return getUniqueEntity(query(sql, params));
}
@Override
public E get(String sql, List<Object> params) throws DaoAccessException {
return get(sql, params.toArray());
}
@Override
public E get(String sql, Map<String, Object> params) throws DaoAccessException {
return getUniqueEntity(query(sql, params));
}
@Override
public E get(Condition condition, Class<?>... associationLink) throws DaoAccessException {
return getUniqueEntity(query(condition, associationLink));
}
@Override
public <K extends Number> K save(E entity) throws DaoAccessException {
return saveWithId(entity, null);
}
@Override
public <K extends Number> void save(E entity, K id) throws DaoAccessException {
saveWithId(entity, id);
}
@Override
public 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);
}
}
@Override
public void saveOrUpdate(E entity) throws DaoAccessException {
if(entity.isTransient()) {
save(entity);
} else {
update(entity);
}
}
@Override
public <K extends Number> void delete(K id) throws DaoAccessException {
try {
jdbcTemplate.update(simpleSqlBuilder.getDeleteSql(), id);
} catch (Exception e) {
throw new DaoAccessException(e);
}
}
@Override
public List<E> query(String sql, Object... params) throws DaoAccessException {
return query(sql, null, params).getDatas();
}
@Override
public List<E> query(String sql, List<Object> params) throws DaoAccessException {
return query(sql, params.toArray());
}
@Override
public List<E> query(String sql, Map<String, Object> params) throws DaoAccessException {
return query(sql, null, params).getDatas();
}
@Override
public List<E> query(Condition condition, Class<?>... associationLink) throws DaoAccessException {
String orders = null;
return query(condition, orders, associationLink);
}
@Override
public List<E> query(Condition condition, String orders, Class<?>... associationLink) throws DaoAccessException {
return query(condition, orders, null, associationLink).getDatas();
}
@Override
public DataStore<E> query(String sql, PagingParameter paging, Object... params) throws DaoAccessException {
sql = handleSimpleSql(sql);
return queryDataStore(sql, params, getRowMapperBySql(sql), paging);
}
@Override
public DataStore<E> query(String sql, PagingParameter paging,
List<Object> params) throws DaoAccessException {
return query(sql, paging, params.toArray());
}
@Override
public DataStore<E> query(String sql, PagingParameter paging,
Map<String, Object> params) throws DaoAccessException {
sql = handleSimpleSql(sql);
return queryDataStore(sql, params, getRowMapperBySql(sql), paging);
}
@Override
public DataStore<E> query(Condition condition, PagingParameter paging, Class<?>... associationLink) throws DaoAccessException {
return query(condition, null, paging, associationLink);
}
@Override
public 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);
}
@Override
public List<E> queryAll(Class<?>... associationLink) throws DaoAccessException {
String orders = null;
return queryAll(orders, associationLink);
}
@Override
public List<E> queryAll(String orders, Class<?>... associationLink) throws DaoAccessException {
return query(null, orders, associationLink);
}
@Override
public DataStore<E> queryAll(PagingParameter paging, Class<?>... associationLink) throws DaoAccessException {
return queryAll(null, paging, associationLink);
}
@Override
public DataStore<E> queryAll(String orders, PagingParameter paging, Class<?>... associationLink) throws DaoAccessException {
return query(null, orders, paging, associationLink);
}
@Override
public int count() throws DaoAccessException {
return count(null);
}
@Override
public 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);
}
}
@Override
public <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);
}
}
@Override
public <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);
}
}
@Override
public 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);
}
}
@Override
public 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);
}
@Override
public E getReferenced(E entity) throws DaoAccessException {
return getReferenced(entity, entityClass);
}
@Override
public E getReferenced(Object referenceValue) throws DaoAccessException {
return getReferenced(referenceValue, entityClass);
}
@Override
public <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);
}
@Override
public <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);
}
}
@Override
public <R extends Entity> List<E> queryReferences(R referenced) throws DaoAccessException {
PagingParameter paging = null;
return queryReferences(referenced, paging).getDatas();
}
@Override
public <R extends Entity> List<E> queryReferences(Class<R> referencedClass, Object referencedValue) throws DaoAccessException {
PagingParameter paging = null;
return queryReferences(referencedClass, referencedValue, paging).getDatas();
}
@Override
public <R extends Entity, S extends Entity> List<S> queryReferences(
R referenced, Class<S> referenceClass) throws DaoAccessException {
return queryReferences(referenced, referenceClass, null).getDatas();
}
@Override
public <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();
}
@Override
public <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);
}
@Override
public <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);
}
@Override
public <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);
}
@Override
public <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
*/
@Override
public void afterPropertiesSet() throws Exception {
//初始化namedParameterJdbcTemplate
namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource());
//初始化pagingSqlBuilder
pagingSqlBuilder = new PagingSqlBuilder(((ComboPooledDataSource)
jdbcTemplate.getDataSource()).getJdbcUrl().replaceAll("://.*$", ""));
}
@Override
public 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);
}
}
@Override
public List<Map<String, Object>> search(String sql, List<Object> params) throws DaoAccessException {
return search(sql, params.toArray());
}
@Override
public 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);
}
}
@Override
public <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;
}
@Override
public <R> List<R> search(String sql, MapRowMapper<R> mapRowMapper,
List<Object> params) throws DaoAccessException {
return search(sql, mapRowMapper, params.toArray());
}
@Override
public <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;
}
@Override
public 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);
}
}
@Override
public DataStore<Map<String, Object>> search(String sql,
PagingParameter paging, List<Object> params) throws DaoAccessException {
return search(sql, paging, params.toArray());
}
@Override
public 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);
}
}
@Override
public <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);
}
@Override
public <R> DataStore<R> search(String sql, MapRowMapper<R> mapRowMapper,
PagingParameter paging, List<Object> params) throws DaoAccessException {
return search(sql, mapRowMapper, paging, params.toArray());
}
@Override
public <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);
}
@Override
public List<Map<String, Object>> join(Condition condition,
Class<?>... classLink) throws DaoAccessException {
String orders = null;
return join(condition, orders, classLink);
}
@Override
public 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;
}
@Override
public <R> List<R> join(Condition condition, MapRowMapper<R> mapRowMapper,
Class<?>... classLink) throws DaoAccessException {
return join(condition, null, mapRowMapper, classLink);
}
@Override
public <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;
}
@Override
public DataStore<Map<String, Object>> join(Condition condition,
PagingParameter paging, Class<?>... classLink) throws DaoAccessException {
String orders = null;
return join(condition, orders , paging, classLink);
}
@Override
public 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);
}
@Override
public <R> DataStore<R> join(Condition condition,
MapRowMapper<R> mapRowMapper, PagingParameter paging,
Class<?>... classLink) throws DaoAccessException {
return join(condition, null, mapRowMapper, paging, classLink);
}
@Override
public <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
*/
@Repository
public 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
*/
@Override
public DbVersion getCurrentVersion() throws DaoAccessException {
return jdbcTemplate.queryForObject(queryCurrentVersionSQL, new RowMapper<DbVersion>(){
@Override
public 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
*/
@Override
public void updateToNextVersion() throws DaoAccessException {
jdbcTemplate.update(updateToNextVersionSQL);
}
/**
* @see com.flong.commons.persistence.dao.DbVersionDao#isInitVersion()
* 创建日期:2013-1-7
* 修改说明:
* @author niezhegang
*/
@Override
public 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
*/
@Override
public 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
*/
@Override
public 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
*/
@Override
public 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.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://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