您的位置:首页 > 编程语言

[框架那点事儿-快速开发季]编写自己的数据持久层(7)总结篇 代码

2010-08-03 21:16 1081 查看
AbstractBaseDAO.java

package com.normandy.position.common;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
/**
* DAO抽象父类,提供针对于数据库的基本操作
* 工程名称:NormandyPosition
* 类型名称:AbstractBaseDAO
* 概要:
* <p>
* 	提供针对于DAO基础操作服务
* 	注意使用该类提供的API,必须保证DO类的属性名称,与对应数据库表的名称相同,不区分大小写
* </p>
* 创建时间:2010-7-27 上午12:58:42
* 创建人:quzishen
* 最后修改时间:2010-7-27 上午12:58:42
* 最后修改内容:
* @version 1.0
*/
public abstract class AbstractBaseDAO extends JdbcDaoSupport implements InitializingBean{
//~~~ instance fields

// table name
private String tableName;
//default getter method prefix
public String GET_METHOD_PRE = "get";
//default setter method prefix
public String SET_METHOD_PRE = "set";
//default key name
public String DEFAULT_ID_NAME = "id";
//default serialVersionUID name
public String DEFAULT_SERIALVERSIONUID_NAME = "serialVersionUID";
//default time style of mysql
private String DEFAULT_MYSQL_TIME_STYLE = "yyyy-MM-dd hh:mm:ss";
//default max size of each insert
public int insertPageSize = 500;

//~~~ static final fields start ****************//
private final static String SQL_SELECT = " select ";
private final static String SQL_FROM = " from ";
private final static String SQL_WHERE = " where ";
private final static String SQL_AND = " and ";
private final static String SQL_UPDATE = " update ";
private final static String SQL_SET = " set ";
private final static String SQL_ORDER_BY = " order by ";
private final static String SQL_LIMIT = " limit ";
private final static String SQL_COUNT = " count(*) ";
private final static String SQL_DELETE = "delete ";

private final static String SQL_EQUAL = " = ";
private final static String SQL_SPLIT = " , ";
private final static String SQL_PLACE_HOLDER = " ? ";

private final static String SQL_PLACEHOLDER = "#";

//~~~ static final fields end ****************//

/**************************************///public method begin /*******************************/
/**
* 新增一条记录
* <p>
* 	要求DO:遵循spring风格的getter和setter方法
* 			属性的名称和数据库的名称要对应,大小写不区分
*  示例:
*  -----------------------------------------------------
*  TABLE Person{
*  	ID  BIGINT NOT NULL,
*  	NAME VARCHAR(16) ....
*  }//数据库中字段为大写
*  -----------------------------------------------------
*  class Person{
*  	private long id;
*  	private String name;
*  }//DO类中的字段为小写
*  -----------------------------------------------------
*  Person person = new Person();
*  person.setName("quzishen");
*  long id = insertObject(person);
*
* </p>
* @param 插入对象
* @return 主键ID
* @throws RuntimeException
*/
public int insertObject(Object object) throws RuntimeException{
if(null == object){
throw new RuntimeException("can not inser a null value!");
}
// 获取类型
@SuppressWarnings("rawtypes")
Class objectClass = object.getClass();
// 使用SimpleJdbcInsert完成插入的动作
SimpleJdbcInsert inserActor = getSimpleJdbcInsert(objectClass);
// 获取属性数组
Field[] fields = getFieldsFromClass(objectClass);
// 获取插入数据库sql需要的参数Map
Map<String, Object> paramMap = getParamMap(object, fields);
//简便起见,可以使用SqlParameterSource parameters = new BeanPropertySqlParameterSource(Actor);
// 获取到的参数为空
if(null == paramMap){
throw new RuntimeException("can not insert a null value!");
}

//执行插入并返回主键
return inserActor.executeAndReturnKey(paramMap).intValue();
}

//~~~===============================query object begin===================================~~~//

/**
* 查询单一对象
* <p>
* 	要求:遵循spring风格的getter和setter方法
* 		    属性的名称和数据库的名称要对应,大小写不区分
* 		    这里一定要注意,如果属性的大小写有点个性非常强的个人色彩,
* 		    那么相应的setter方法要保证'set'后的属性首字母大写,其他字母大小写保持不变
* 		   如:pArAm ---->  getPArAm  &  setPArAm
*  示例:
*   -------------------------------------------------------------
*   class Person{
*   	private long id;
*   }
*   -------------------------------------------------------------
*   Map<String,Object> params = new HashMap<String,Object>();
*   params.put("id","10000");
*   Person person = (Person) queryForObject(params,Person.class);
*
* </p>
* @param params 查询条件map,key 属性名字 大小写无所谓
* @param returnClass 对象类型
* @return 查询结果
*/
public Object queryForObject(Map<String,Object> params,@SuppressWarnings("rawtypes") final Class returnClass) throws RuntimeException{
//获取表名
tableName = getTableConfigName(returnClass);
// 组装查询sql,参数使用占位符
String sql = buildQuerySql(null,params,-1,-1,true);

return queryForObjectBySql(sql,returnClass);
}

/**
* 根据自定义sql查询对象,主要封装了rowMapper的转换过程
* 要求:遵循spring风格的getter和setter方法
* 		    属性的名称和数据库的名称要对应,大小写不区分
* 		    这里一定要注意,如果属性的大小写有点个性非常强的个人色彩,
* 		    那么相应的setter方法要保证'set'后的属性首字母大写,其他字母大小写保持不变
* 		   如:pArAm ---->  getPArAm  &  setPArAm
* 使用示例:
* -----------------------------------------------------
* String sql = "select * from Person where name='name' and (address='d1' or address='d2') and type=2;
* Person p = (Person) queryForObjectBySql(sql,Person.class);
*
* @param sql 自定义sql,不适用占位符
* @param returnClass 返回类型
* @return 封装好的对象
*/
public Object queryForObjectBySql(String sql,@SuppressWarnings("rawtypes") final Class returnClass){
return queryForObject(sql,returnClass);
}

/**
* 根据sql和参数查询对象
* 使用示例
* ----------------------------------------------------------
* String sql = "select * from Person where id=#param1# and name=#param2# and age in (#age#) order by #param3# desc";
*
* Map<String,Object> params = new HashMap<String,Object>();
* params.put("param1","10000");
* params.put("param2","quzishen");
* params.put("param3","score");
* params.put("age",new Object[]{25,26,27,28,29});
*
* Person p = (Person) queryForObjectBySql(sql,params,Person.class);
*
* @param sql 查询语句,使用占位符
* @param params 参数,可以null
* @param returnClass 返回对象类型
* @return
*/
public Object queryForObjectBySql(String sql,Map<String,Object> params,@SuppressWarnings("rawtypes") final Class returnClass){
// 自动将sql中的占位符替换成具体值
sql = getSqlFromPlaceHolder(sql,params);

return queryForObject(sql, returnClass);
}

/**
* 根据sql和参数查询部分字段
* 具体sql用法请参见queryForObjectBySql方法
* @param sql 查询语句,使用占位符
* @param params 参数 ,可以null
* @param returnClass 返回对象类型
* @return
*/
public Map<String,Object> queryForMapBySql(String sql,Map<String,Object> params,@SuppressWarnings("rawtypes") final Class returnClass){
List<Map<String,Object>> list = queryForMapList(sql,params,returnClass);
if(null == list || 0 == list.size()){
return null;
}else {
return list.get(0);
}
}
//~~~query object end~~~//

//~~~===============================query object list begin===================================~~~//
/**
* 查询对象列表结果
* <p>
* 	要求:遵循spring风格的getter和setter方法
* 		    属性的名称和数据库的名称要对应,大小写不区分
* 		    这里一定要注意,如果属性的大小写有点个性非常强的个人色彩,
* 		    那么相应的setter方法要保证'set'后的属性首字母大写,其他字母大小写保持不变
* 		   如:pArAm ---->  getPArAm  &  setPArAm
*  示例:
*   -------------------------------------------------------------
*   class Person{
*   	private String desc;
*   }
*   -------------------------------------------------------------
*   Map<String,Object> params = new HashMap<String,Object>();
*   params.put("desc","10000");
*   List<Person> persons = (List<Person>) queryForList(params,Person.class);
*
* </p>
* @param params 参数Map
* @param returnClass 返回列表中的对象类型
* @return
*/
@SuppressWarnings("rawtypes")
public List queryForObjectList(Map<String,Object> params,final Class returnClass){
return queryForObjectListOrderRow(params,returnClass);
}

/**
* 查询对象列表结果,查询按照指定列排序
* <p>
*  关于排序列(可变长度参数部分):
*  根据排序的列的次序依次排列,每个Map中存放一个键值对,允许指定的排序为 asc || desc
*
*  示例:
*  Map<String,String> orderByName = new HashMap<String,String>();
*  orderByName.put("name","asc");
*
*  Map<String,String> orderByAge = new HashMap<String,String>();
*  orderByName.put("age","desc");
*
*  Map<String,String> orderByType = new HashMap<String,String>();
*  orderByName.put("type","asc");
*
*  queryForListOrderRow(params,returnClass,orderByName,orderByAge,orderByType)
* </p>
* @param params
* @param returnClass
* @param orders
* @return
*/
@SuppressWarnings("rawtypes")
public List queryForObjectListOrderRow(Map<String,Object> params,
final Class returnClass,
Map<String,String>... orders){
//获取表名
tableName = getTableConfigName(returnClass);
// 组装查询sql,参数使用占位符替代
String sql = buildQuerySql(null,params,-1,-1,false,orders);
if(logger.isDebugEnabled()){
logger.debug("RUN SQL:"+sql);
}
//执行查询
return queryForList(sql,params,returnClass);
}

/**
* 根据sql查询对象列表,全字段查询并封装成特定类型
* <p>
* 	本方法服务于那些自定义sql进行查询的需求。上述的方法中的查询条件皆为普通的and关系,这个方法可以自定义任何类型的sql
* 	方法主要封装了rowMapper的转换过程。
*  如果外部sql使用占位符?,那么sql中采用的参数不能有针对同一个字段,如between操作,否则无法使用map传递一个字段的两个参数。
*  如果外部sql已经封装成能直接查询的语句,即没有使用占位符?,则params可以传NULL
* </p>
* @param sql 查询sql "select * from person where id=?" or "select * from person where id=1"
* @param params 参数,可以为null
* @param returnClass 返回类型 List<? extends Object>
* @return
*/
@SuppressWarnings("rawtypes")
public List queryForObjectListBySql(String sql,Map<String,Object> params,Class returnClass){
if(logger.isDebugEnabled()){
logger.debug("RUN SQL:"+sql);
}

//执行查询
return queryForList(sql,params,returnClass);
}
/**
* 根据sql和占位符#param#查询
* 提供了另外一种占位符的形式,即用##包含的形式,使得查询更加明确而且功能更加强大
* 使用示例
* -------------------------------------------------------------
* String sql = "select * from table where name=#name# and id between #id1# and #id2#";
* Map<String,String> params = new HashMap<String,String>();
* params.put("name","quzishen");
* params.put("id1","1");
* params.put("id2","10");
*
* queryForObjectListBySqlWithPlaceHolder(sql,params,Person.class);
*
* @param sql
* @param params 可以为NULL
* @param returnClass
* @return
*/
@SuppressWarnings("rawtypes")
public List queryForObjectListBySqlWithPlaceHolder(String sql,Map<String,Object> params,Class returnClass){
// 自动将sql中的占位符替换成具体值
sql = getSqlFromPlaceHolder(sql,params);

return queryForList(sql, null,returnClass);
}
//~~~query object list end~~~//

//~~~===============================query fields list begin===================================~~~//
/**
* 查询部分字段
* <p>
*  根据指定的属性名称查询特定字段,返回一个List<Map<属性名称,属性值>>
*
*  使用示例:
*  ---------------------------------------------------------------
*  //设置查询参数
*  Map<String,Object> params = new HashMap();
*  params.put("city","hangzhou");
*
*  //设置需要查询的字段名称,名称使用DO中的即可
*  List<String> fields = new ArrayList<String>();
*  fields.add("id");
*  fields.add(name);
*  fields.add("address");
*
*  List<Map<String,Object>> resultList = queryFieldsList(Person.class,params,fields);
*  ...
*
* </p>
* @param objectClass 返回属性所在的类
* @param objectClass
* @param params 查询参数map
* @param returnFields 返回字段列表
* @return 返回值,用map保存每一列的结果
*/
public List<Map<String,Object>> queryFieldsList(@SuppressWarnings("rawtypes")final Class objectClass,Map<String,Object> params,List<String> returnFields){
return queryFieldsListOrderRow(objectClass,params,returnFields);
}

/**
* 查询部分字段,查询结果根据指定列排序
* <p>
* 	根据指定的属性名称查询特定字段,并且根据指定的列排序,返回一个List<Map<属性名称,属性值>>
*	使用示例:
*  ---------------------------------------------------------------
*  //设置查询参数
*  Map<String,Object> params = new HashMap();
*  params.put("city","hangzhou");
*
*  //设置需要查询的字段名称,名称使用DO中的即可
*  List<String> fields = new ArrayList<String>();
*  fields.add("id");
*  fields.add(name);
*  fields.add("address");
*
*  Map<String,String> orderByAge = new HashMap<String,String>();
*  orderByName.put("age","desc");
*
*  Map<String,String> orderByType = new HashMap<String,String>();
*  orderByName.put("type","asc");
*
*  List<Map<String,Object>> resultList = queryFieldsList(Person.class,params,fields,orderByAge,orderByType);
*  ...
*
* </p>
* @param objectClass 返回属性所在的类
* @param params 查询参数map
* @param returnFields 返回字段列表
* @param orders 查询语句排序指定字段
* @return 返回值,用map保存每一列的结果
*/
public List<Map<String,Object>> queryFieldsListOrderRow(@SuppressWarnings("rawtypes")final Class objectClass,
Map<String,Object> params,List<String> returnFields,Map<String,String>... orders){
//获取表名
tableName = getTableConfigName(objectClass);
// 组装查询sql,参数使用占位符替代
String sql = buildQuerySql(returnFields,params,-1,-1,false,orders);
return queryForMapList(sql,params,objectClass);
}

/**
* 根据指定sql查询部分字段
* <p>
* 	如果外部封装的sql不使用占位符,则params传NULL
*  如果外部封装的sql使用占位符,则sql不能有针对于一个字段的两个操作如between,否则map无法传递一个参数的两个值
* </p>
* @param sql 查询sql,参数使用占位符
* @param params 查询参数
* @param objectClass 字段所在Do类型
* @return List<Map<String,Object>>
*/
public List<Map<String,Object>> queryFieldsListBySql(String sql,Map<String,Object> params,@SuppressWarnings("rawtypes")final Class objectClass){
return queryForMapList(sql,params,objectClass);
}

/**
* 根据指定的sql和参数查询部分字段
* <p>
* 	参数使用##形式的占位符
*  使用示例
* -------------------------------------------------------------
* String sql = "select id,name,age from table where name=#name# and id between #id1# and #id2#";
* Map<String,String> params = new HashMap<String,String>();
* params.put("name","quzishen");
* params.put("id1","1");
* params.put("id2","10");
*
* queryFieldsListBySqlWithPlaceHolder(sql,params,Person.class);
* </p>
* @param sql sql语句,使用##形式的占位符
* @param params 参数,可以为null
* @param objectClass
* @return
*/
public List<Map<String,Object>> queryFieldsListBySqlWithPlaceHolder(String sql,Map<String,Object> params,@SuppressWarnings("rawtypes")final Class objectClass){
// 自动将sql中的占位符替换成具体值
sql = getSqlFromPlaceHolder(sql,params);

return queryForMapList(sql,null,objectClass);
}
//~~~query fields list end~~~//

/**
* 分页查询对象
* <p>
* 	根据指定参数分页查询对象列表
* 	用法示例:
*  ----------------------------------------------------------
*  //设置查询参数
*  Map<String,Object> params = new HashMap();
*  params.put("city","hangzhou");
*
*  Paginal p = queryObjectListForPaging(Person.class,params,1,10);
*  ...
* </p>
* @param objectClass 对象类型
* @param params	查询参数
* @param pageNomber	页号
* @param pageSize		分页大小
* @return 分页封装
*/
@SuppressWarnings({ "rawtypes"})
public Paginal queryObjectListForPaging(final Class objectClass,Map<String,Object> params,int pageNomber,int pageSize){
return queryObjectListForPagingOrderRow(objectClass,params,pageNomber,pageSize);
}

/**
* 分页-排序查询对象
* <p>
* 	分页查询,结果按照指定的条件排序
*  使用示例
*  ----------------------------------------------------------
*  //设置查询参数
*  Map<String,Object> params = new HashMap();
*  params.put("city","hangzhou");
*
*  Map<String,String> orderByAge = new HashMap<String,String>();
*  orderByName.put("age","desc");
*
*  Map<String,String> orderByType = new HashMap<String,String>();
*  orderByName.put("type","asc");
*
*  Paginal p = queryObjectListForPagingOrderRow(Person.class,params,1,10,orderByAge,orderByType);
*  ...
* </p>
* @param objectClass 字段所在类
* @param params 查询参数
* @param pageNomber 页号
* @param pageSize 分页大小
* @param orders 排序字段
* @return 查询结果
*/
@SuppressWarnings({ "rawtypes", "unchecked"})
public Paginal queryObjectListForPagingOrderRow(final Class objectClass,Map<String,Object> params,int pageNomber,int pageSize,Map<String,String>... orders){
//~~~ return value
Paginal<? extends Object> paginal = new Paginal<Object>();

// 初始化分页器
paginal.setPageNomber(pageNomber);
paginal.setPageSize(pageSize);

//获取表名
tableName = getTableConfigName(objectClass);
//组装查询sql语句
String sql = buildQuerySql(null, params, paginal.getOffset(),paginal.getPageSize(),false,orders);
//查询总记录数
int totalCount = queryCount(params,objectClass);

paginal.setTotalCount(totalCount);//总记录数
paginal.setPageNum(totalCount,paginal.getPageSize());//总页码

//执行查询
List resultList = queryForList(sql,params,objectClass);
paginal.setResultList(resultList);

return paginal;
}

/**
* 根据sql自动分页查询
* 传入的sql不需要关注分页内容,只需要关注于普通查询部分,方法内部自动实现分页查询
* 返回封装好的分页器
* 使用示例
* --------------------------------------------------------------
* String sql = "select * from Person where (name='quzishen' or name='zishenqu') and age=25";
*
* Paginal p = queryObjectListForPagingBySql(sql,Person.class,1,10);
* ...
* @param sql
* @param objectClass
* @param pageNomber
* @param pageSize
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public Paginal queryObjectListForPagingBySql(String sql,final Class objectClass,int pageNomber,int pageSize){
//~~~ return value
Paginal<? extends Object> paginal = getPaginalBySql(sql,pageNomber,pageSize);

//自动添加分页部分
sql = getPagingSql(sql, paginal.getOffset(), paginal.getPageSize());

// 执行查询
List resultList = queryForList(sql,null,objectClass);
paginal.setResultList(resultList);

return paginal;
}

/**
* 分页查询-使用占位符##
* 使用示例
* ----------------------------------------------------------
* 	String sql = "select * from NOR_QUICK_NEWS where name=#name# and prop1=#prop1#";
*
*	Map<String, Object> params = new HashMap<String, Object>();
*	params.put("name", name);
*	params.put("prop1", prop1);
*
*	queryObjectListForPagingBySqlWithPlaceHolder(sql, params,NorQuickNews.class, pageNum, pageSize);
*  ...
* 传入的sql不需要关注分页内容,只需要关注于普通查询部分,方法内部自动实现分页查询
* @param sql
* @param params
* @param objectClass
* @param pageNomber
* @param pageSize
* @return
*/
@SuppressWarnings("rawtypes")
public Paginal queryObjectListForPagingBySqlWithPlaceHolder(String sql,Map<String,Object> params,final Class objectClass,int pageNomber,int pageSize){
sql = getSqlFromPlaceHolder(sql,params);

return queryObjectListForPagingBySql(sql,objectClass,pageNomber,pageSize);
}

/**
* 分页查询部分字段
* <p>
* 	使用示例
*  -----------------------------------------------------------------
*  //设置查询参数
*  Map<String,Object> params = new HashMap();
*  params.put("city","hangzhou");
*
*  //设置需要查询的字段名称,名称使用DO中的即可
*  List<String> fields = new ArrayList<String>();
*  fields.add("id");
*  fields.add(name);
*  fields.add("address");
*
*  Paginal p = queryFieldsListForPaging(objectClass,params,fields,1,10);
*  ...
* </p>
* @param objectClass 字段所在的类
* @param params 查询参数
* @param returnFields 需要查询的字段列表
* @param pageNomber 页号
* @param pageSize 分页大小
* @return 查询结果
*/
@SuppressWarnings({ "rawtypes"})
public Paginal queryFieldsListForPaging(final Class objectClass,Map<String,Object> params,List<String> returnFields,int pageNomber,int pageSize){
return queryFieldsListForPagingOrderRow(objectClass,params,returnFields,pageNomber,pageSize);
}

/**
* 分页-排序查询部分字段
* <p>
* 	使用示例
*  -----------------------------------------------------------------
*  //设置查询参数
*  Map<String,Object> params = new HashMap();
*  params.put("city","hangzhou");
*
*  //设置需要查询的字段名称,名称使用DO中的即可
*  List<String> fields = new ArrayList<String>();
*  fields.add("id");
*  fields.add(name);
*  fields.add("address");
*
*  Map<String,String> orderByAge = new HashMap<String,String>();
*  orderByName.put("age","desc");
*
*  Map<String,String> orderByType = new HashMap<String,String>();
*  orderByName.put("type","asc");
*
*  Paginal p = queryFieldsListForPaging(objectClass,params,fields,1,10,orderByAge,orderByType);
*  ...
* </p>
* @param objectClass 字段所在的类
* @param params 查询参数
* @param returnFields 需要查询的字段列表
* @param pageNomber 页号
* @param pageSize 分页大小
* @param orders 排序字段
* @return 查询结果
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public Paginal queryFieldsListForPagingOrderRow(final Class objectClass,Map<String,Object> params,List<String> returnFields,int pageNomber,int pageSize,Map<String,String>... orders){
//~~~ return value
Paginal<? extends Object> paginal = new Paginal<Object>();

// 初始化分页器
paginal.setPageNomber(pageNomber);
paginal.setPageSize(pageSize);

//获取表名
tableName = getTableConfigName(objectClass);
//组装查询sql语句
String sql = buildQuerySql(returnFields, params, paginal.getOffset(),paginal.getPageSize(),false,orders);
//查询总记录数
int totalCount = queryCount(params,objectClass);

paginal.setTotalCount(totalCount);//总记录数
paginal.setPageNum(totalCount,pageSize);//总页码

//查询 得到 List<Map<String,Object>>
List resultList = queryForMapList(sql,params,objectClass);
paginal.setResultList(resultList);

return paginal;
}

/**
* 根据指定sql查询部分参数
* @param sql
* @param objectClass
* @param pageNomber
* @param pageSize
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public Paginal queryFieldsListForPagingbySql(String sql,final Class objectClass,int pageNomber,int pageSize){
//~~~ return value
Paginal<? extends Object> paginal = getPaginalBySql(sql,pageNomber,pageSize);

//自动添加分页部分
sql = getPagingSql(sql, paginal.getOffset(), paginal.getPageSize());

// 执行查询
List resultList = queryForMapList(sql,null,objectClass);
paginal.setResultList(resultList);

return paginal;
}

/**
* 使用占位符sql分页查询部分参数
* 占位符使用##形式
* @param sql
* @param params
* @param objectClass
* @param pageNomber
* @param pageSize
* @return
*/
@SuppressWarnings("rawtypes")
public Paginal queryFieldsListForPagingbySqlWithPlaceHolder(String sql,Map<String,Object> params,final Class objectClass,int pageNomber,int pageSize){
// 渲染占位符
sql = getSqlFromPlaceHolder(sql, params);
// 执行查询
return queryFieldsListForPagingbySql(sql,objectClass,pageNomber,pageSize);
}

/**
* 查询总记录数
* <p>
* 	根据指定查询条件查询记录总数,一般用于分页中等
* </p>
* @param params 查询条件参数
* @param objectClass 对象类型
* @return 记录数
*/
@SuppressWarnings({ "rawtypes"})
public int queryCount(Map<String,Object> params,Class objectClass){
//获取表名
tableName = getTableConfigName(objectClass);

//组装查询总记录数sql语句
String countsql = buildQueryConteSql(params);
//查询对象,存储查询条件数组
Object[] queryObject = getQueryObject(params,countsql);
//查询总记录数
int totalCount = getJdbcTemplate().queryForInt(countsql, queryObject);

return totalCount;
}

/**
* 通过sql语句查询结果记录数
* @param sql 查询sql
* @return 记录数
*/
public int queryCount(String sql){
sql = getCountSqlFromSelectSql(sql);
//查询总记录数
int totalCount = getJdbcTemplate().queryForInt(sql);

return totalCount;
}

/**
* 根据查询条件修改记录
* 除了ID之外的全字段修改,适用于从数据库取出的对象的修改。不适合单字段或部分字段修改。
* <p>
* 	要求DO:遵循spring风格的getter和setter方法
* 			属性的名称和数据库的名称要对应,大小写不区分
*  示例:
*  -----------------------------------------------------
*  TABLE Person{
*  	ID  BIGINT NOT NULL,
*  	NAME VARCHAR(16) ....
*  }//数据库中字段为大写
*  -----------------------------------------------------
*  class Person{
*  	private long id;
*  	private String name;
*  }//DO类中的字段为小写
*  -----------------------------------------------------
*  Person person = new Person();
*  person.setName("quzishen");
*
*  Map<String,Object> conditions = new HashMap<String,Object>();
*  conditions.put("ID","1");
*
*  long id = updateObject(person);
*
* </p>
* @param 修改后的对象值
* @param 查询条件,可以单独只有一个ID
* @return
* @throws RuntimeException
*/
public int updateObject(Object object,Map<String,Object> conditions) throws RuntimeException{
if(null == object){
throw new RuntimeException("can not insert a null value!");
}
//获取表名
tableName = getTableConfigName(object.getClass());
//获取sql
String sql = buildUpdateObjectSql(object,true,conditions);
//执行更新
return getJdbcTemplate().update(sql);
}

/**
* 根据查询条件更新部分字段
* <p>
* 	适用于更新部分字段情况
*  使用示例:
*  -----------------------------------------------------
*  Map<String,Object> params = new HashMap<String,Object>();
*  params.put("status","expired");
*
*  Map<String,Object> conditions = new HashMap<String,Object>();
*  conditions.put("status","use");
*
*  updateField(params,conditions,Person.class);
*
* </p>
* @param params 需要更新的字段以及值
* @param conditions 查询条件
* @param objectClass 字段所在的DO类的类型
* @return
* @throws RuntimeException
*/
public int updateField(Map<String,Object> params,Map<String,Object> conditions,@SuppressWarnings("rawtypes") Class objectClass) throws RuntimeException{
if(null == params || 0 == params.size()){
throw new RuntimeException("can not insert a null value!");
}

//获取表名
tableName = getTableConfigName(objectClass);
//获取sql
String sql = buildUpdateFieldSql(params, objectClass, true, conditions);

//执行更新
return getJdbcTemplate().update(sql);
}

/**
* 根据sql修改记录,sql使用##形式占位符
* 使用示例:
* ----------------------------------------------------------------
* String sql = "update NOR_QUICK_NEWS set " + propName + "=#prop# where name=#name#";
*
*		Map<String, Object> conditions = new HashMap<String, Object>();
*		conditions.put("prop", propValue);
*		conditions.put("name", name);
*
*		return updateFieldBySqlWithPlaceHolder(sql, conditions,
*				NorQuickNews.class);
*
* @param sql
* @param conditions
* @param objectClass
* @return
*/
public int updateFieldBySqlWithPlaceHolder(String sql,Map<String,Object> conditions,@SuppressWarnings("rawtypes") Class objectClass){
sql = getSqlFromPlaceHolder(sql, conditions);
//执行更新
return getJdbcTemplate().update(sql);
}
/**
* 批量插入
* <p>
* 	批量将对象列表插入到数据库中,主键自动生成。
*  可以选择是否使用分页插入模式,当数据量比较大的时候可以选择,以提升性能;
*  · 开启分页插入模式的条件: 1、moreThanOnce 设置 true 。 2、列表总长度大于单次最大插入数目,默认500,可修改。
*
*  使用示例
*  -------------------------------------------------------
*  List<Person> addlist = new ArrayList<Person>();
*  Person p1 = new Person();
*  p1.init(...);
*  Person p2 = new Person();
*  p2.init(...);
*
*  addlist.add(p1); addlist.add(p2);
*
*  batchInsert(addlist,Person.class);
*  ...
* </p>
* @param updateList 插入列表
* @param objectClass 列表对象类型
* @throws RuntimeException
*/
@SuppressWarnings("rawtypes")
public void batchInsert(List<? extends Object> updateList,Class objectClass,boolean moreThanOnce) throws RuntimeException{
if(null == updateList || 0 == updateList.size()){
throw new RuntimeException("can not inser null value!");
}
// 获取SimpleJdbcInsert
SimpleJdbcInsert inserActor = getSimpleJdbcInsert(objectClass);

// 如果选择批量插入,并且列表长度大于单次插入最大值,则使用分页插入
if(moreThanOnce && insertPageSize < updateList.size()){
// 需要的分页总数
int totalPage = (0==updateList.size() % insertPageSize) ?
(updateList.size() / insertPageSize) : (updateList.size() / insertPageSize+1);
// 开始分页插入
for(int pageNo=1;pageNo<=totalPage;pageNo++){
int fromIndex = 0;
int endIndex = updateList.size() > insertPageSize ? insertPageSize : updateList.size();
List<? extends Object> subList = updateList.subList(fromIndex, endIndex);//[)
//insert into db
insertSqlParameterSourceInfoDB(subList,inserActor);
}
}else {
// 不分页直接插入
insertSqlParameterSourceInfoDB(updateList,inserActor);
}
}

/**
* 根据ID批量更新
* <p>
*  使用示例
*  --------------------------------------------------------------------------------
*  class Person{
*  	①、private static final long serialVersionUID = 4311010571442992834L;//位置可以在这里
*  	private long id;
*  	②、private static final long serialVersionUID = 4311010571442992834L;//位置可以在这里
*  	private String name;
*  	③、private static final long serialVersionUID = 4311010571442992834L;//位置可以在这里
*  }
*  //上述类过滤后的顺序为  id - name
*
*  updateList.add(p1);
*  updateList.add(p2);
*  updateList.add(p3);
*
*  batchUpdate(updateList,Person.class);
*  ...
* </p>
* @param updateList 更新列表
* @param objectClass 更新对象类型
* @throws RuntimeException
*/
@SuppressWarnings("rawtypes")
public void batchUpdate(final List updateList,Class objectClass) throws RuntimeException{
if(null == updateList || 0 == updateList.size()){
throw new RuntimeException("can not inser null value!");
}
// 获取一个对象
Object object = getInstanceByClass(objectClass);
// 生成更新sql,update table set .x = ?.. where id = ?
Map<String,Object> conditions = new HashMap<String,Object>();
conditions.put(DEFAULT_ID_NAME, SQL_PLACE_HOLDER);
//获取表名
tableName = getTableConfigName(object.getClass());
String sql = buildUpdateObjectSql(object, false, conditions);
// 获取属性数组,其中不包括数据库中不含有的字段 serivalversionUID
final Field[] fields = getFieldsMatchedDBFromClass(objectClass,false);

/**
* 执行批量更新操作
* 生成的sql中的占位符的顺序和DO类中顺序固定,所以这里也要按照DO类中的顺序来实施
* 在Fields中包含了部分与数据库不匹配的字段,有serivalversionuid.所以应该去除掉
*/
getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter(){

public int getBatchSize() {
return updateList.size();
}
// 设置参数
public void setValues(PreparedStatement preparedStatement, int index)
throws SQLException {
Object o = updateList.get(index);

for(Field field : fields){
//列从1开始计数,但是方法内部也从0开始计数,所以这里需要加1
int row =1+getFieldIndexOfObject(fields, field.getName());
String value = getValueByName(o,field.getName());
preparedStatement.setString(row, value);
}

// 设置最后的一位,即更新条件,此处为ID,sql中参数总数为fields.length,加1可以判断最后一个ID参数的位置
preparedStatement.setString(fields.length+1, getValueByName(o,DEFAULT_ID_NAME));
}
});
}

/**
* 根据ID删除
* @param id 记录ID
* @param objectClass DO类型
* @return 操作记录数目
*/
public int deletebyId(long id,@SuppressWarnings("rawtypes") Class objectClass){
// 获取表名
tableName = getTableConfigName(objectClass);
// 组装sql
String sql = SQL_DELETE+SQL_FROM+ tableName +SQL_WHERE+ DEFAULT_ID_NAME +"= "+ id;
// 执行删除
return getJdbcTemplate().update(sql);
}

/**
* 根据sql删除,sql使用##占位符
* 使用示例
* ---------------------------------------------------------
*  String sql = "delete from NOR_QUICK_NEWS where name=#name#";
*
*	Map<String, Object> conditions = new HashMap<String, Object>();
*	conditions.put("name", name);
*
*	return deleteBySqlWithPlaceHolder(sql, conditions);
* @param sql 删除sql
* @param params 参数
* @return 操作记录数目
*/
public int deleteBySqlWithPlaceHolder(String sql,Map<String,Object> params){
// 获取sql,渲染参数
sql = getSqlFromPlaceHolder(sql, params);
// 执行删除
return getJdbcTemplate().update(sql);
}

/*****************************///private methods begin .../*****************************/

/**
* 获取SimpleJdbcInsert
* @param objectClass 插入对象的类型
* @return 初始化后的SimpleJdbcInsert实例
*/
private SimpleJdbcInsert getSimpleJdbcInsert(@SuppressWarnings("rawtypes") Class objectClass){
//获取表名
tableName = getTableConfigName(objectClass);
// 使用SimpleJdbcInsert完成插入的动作
SimpleJdbcInsert inserActor = new SimpleJdbcInsert(getJdbcTemplate()).withTableName(tableName);
// 获取该对象的所有的private protected publick的属性
Field[] fields = getFieldsFromClass(objectClass);
// 将属性名字保存下来
List<String> fieldNameSet = getFiledNameList(fields);
// 设置需要更新的字段以及主键
setUsingListFromNameSet(inserActor,fieldNameSet);

return inserActor;
}

/**
* 根据sql获取初始化的分页器
* @param sql 查询sql
* @param pageNomber 页号
* @param pageSize 分页大小
* @return
*/
private Paginal<? extends Object> getPaginalBySql(String sql,int pageNomber,int pageSize){
//~~~ return value
Paginal<? extends Object> paginal = new Paginal<Object>();

// 初始化分页器
paginal.setPageNomber(pageNomber);
paginal.setPageSize(pageSize);

//获取查询总数的语句 将select 到 from中间部分替换成count(*)
//查询总记录数
int totalCount = queryCount(sql);

paginal.setTotalCount(totalCount);//总记录数
paginal.setPageNum(totalCount,paginal.getPageSize());//总页码

return paginal;
}

/**
* 将参数列表插入到数据库中
* @param updateList 插入列表
* @param inserActor 指定的插入执行器
*/
private void insertSqlParameterSourceInfoDB(List<? extends Object> updateList,SimpleJdbcInsert inserActor){
// 使用 SqlParameterSource 封装插入参数
SqlParameterSource[] paramSources = new SqlParameterSource[updateList.size()];
int index = 0;
for(Object o : updateList){
//依次遍历列表,获取插入对象,封装成SqlParameterSource并放入数组
SqlParameterSource paramSource = new BeanPropertySqlParameterSource(o);
paramSources[index++] = paramSource;
}

//执行批量插入,注意这里的返回值是没有意义的,一般由底层jdbc决定,通常会返回-2
inserActor.executeBatch(paramSources);
}

/**
* 查询列表
* @param sql 查询sql,其中参数部分使用占位符?代替具体的值
* @param params 查询条件值的map
* @param returnClass 返回值类型
* @return 查询列表
*/
@SuppressWarnings("rawtypes")
private List queryForList(String sql,Map<String,Object> params,final Class returnClass){
if(null != params){
// 查询对象,存储查询条件数组
Object[] queryObject = getQueryObject(params,sql);
//执行查询,设置rowMapper进行结果从List<Map> -->  List<Object>的转换
return queryObjectListWithQueryObject(sql,queryObject,returnClass);
} else {
//执行查询,设置rowMapper进行结果从List<Map> -->  List<Object>的转换
return queryObjectListWithoutObject(sql,returnClass);
}

}
/**
* 带参数的查询,适用于sql使用占位符的
* @param sql
* @param queryObject
* @param returnClass
* @return
*/
@SuppressWarnings("rawtypes")
private List queryObjectListWithQueryObject(String sql,Object[] queryObject,final Class returnClass){
//执行查询,设置rowMapper进行结果从List<Map> -->  List<Object>的转换
return getJdbcTemplate().query(sql, queryObject,new RowMapper(){
public Object mapRow(ResultSet resultSet, int rowNum) throws SQLException {
//~~~ return value 组装返回对象
Object object = getObjectFromResultSet(resultSet,returnClass);

return object;
}
});
}

/**
* 不带参数的查询,适用于sql不使用占位符的
* @param sql
* @param returnClass
* @return
*/
@SuppressWarnings("rawtypes")
private List queryObjectListWithoutObject(String sql,final Class returnClass){
//执行查询,设置rowMapper进行结果从List<Map> -->  List<Object>的转换
return getJdbcTemplate().query(sql,new RowMapper(){
public Object mapRow(ResultSet resultSet, int rowNum) throws SQLException {
//~~~ return value 组装返回对象
Object object = getObjectFromResultSet(resultSet,returnClass);

return object;
}
});
}

/**
* 查询map列表
* @param sql
* @param params
* @param objectClass
* @return
*/
@SuppressWarnings({ "rawtypes"})
private List<Map<String,Object>> queryForMapList(String sql,Map<String,Object> params,final Class objectClass){
if(null == params){
return queryForMapListWithoutObject(sql,objectClass);
}else {
//获取查询参数
Object[] queryObject = getQueryObject(params,sql);
return queryForMapListWithObject(sql,queryObject,objectClass);
}
}

@SuppressWarnings({ "unchecked", "rawtypes" })
private List<Map<String,Object>> queryForMapListWithObject(String sql,Object[] queryObject,final Class objectClass){
//获取对象声明的属性
final Field[] fields = getFieldsFromClass(objectClass);
return (List<Map<String,Object>>)getJdbcTemplate().query(sql, queryObject, new RowMapper(){
public Object mapRow(ResultSet resultSet, int count) throws SQLException {
try{
Map<String,? extends Object> resultMap = getResultMapFromResultSet(resultSet,fields);
return resultMap;
}catch(Exception e){
throw new RuntimeException("can not get result from resultSet!");
}
}
});
}

@SuppressWarnings({ "unchecked", "rawtypes" })
private List<Map<String,Object>> queryForMapListWithoutObject(String sql,final Class objectClass){
final Field[] fields = getFieldsFromClass(objectClass);
return (List<Map<String,Object>>)getJdbcTemplate().query(sql, new RowMapper(){
public Object mapRow(ResultSet resultSet, int count) throws SQLException {
try{
Map<String,? extends Object> resultMap = getResultMapFromResultSet(resultSet,fields);
return resultMap;
}catch(Exception e){
throw new RuntimeException("can not get result from resultSet!");
}
}
});
}

/**
* 获取注解中配置的表名称
* @param Class 注解所添加位置的类
* @return String 注解中配置的tablename
*/
protected String getTableConfigName(@SuppressWarnings("rawtypes") Class objectClass){
@SuppressWarnings("unchecked")
Table tableAnnotation = (Table)objectClass.getAnnotation(Table.class);
String tableName = tableAnnotation.tableName();
return tableName;
}

/**
* 根据class和resultSet填充对象
* 通过反射,调用setter方法设置DO
* @param resultSet 查询返回值
* @param returnClass 返回值类型
*/
private Object getObjectFromResultSet(ResultSet resultSet,@SuppressWarnings("rawtypes") Class returnClass) throws RuntimeException{
// ~~~ return value
Object object = getInstanceByClass(returnClass);

if(null != object){
if(null == resultSet){
return null;
}

// 根据返回类型获取fields
Field[] fields = getFieldsFromClass(returnClass);
try{
//获取结果map<属性名,属性值>,用于方便的获取属性对应的值
Map<String,? extends Object> resultMap = getResultMapFromResultSet(resultSet,fields);

//遍历列表设置值,通过反射调用setter方法设置
for(Field field : fields){
if(checkIsSerivalVersioinUID(field.getName())){
//如果是序列ID,掠过
continue;
}
// 获取方法名
String methodName = getSetMethod(field.getName());
// 获取方法
Method method = object.getClass().getMethod(methodName, field.getType());
// 获取参数
Object param = resultMap.get(field.getName());//不能直接从resultSet中取值,因为其中的name是数据库的列名
// 特殊类型转换
if(!field.getType().isPrimitive() && field.getType().newInstance() instanceof java.util.Date){
// 非简单类型并且是Date类型
DateFormat df = new SimpleDateFormat(DEFAULT_MYSQL_TIME_STYLE);
java.util.Date time = StringUtils.isBlank(param.toString())? null:df.parse(param.toString());
param = time;
}

// 执行setter方法
method.invoke(object, param);
}
}catch(Exception e){
logger.error("queryForObject exception!",e);
throw new RuntimeException(e);
}
}else {
//获取实例失败,这里抛出异常
throw new RuntimeException("build result object failed!");
}

return object;
}

/**
* 根据传入Map获取查询参数数组对象
* @param params 参数Map
* @return Object[]
*/
private static Object[] getQueryObject(Map<String, Object> params,String sql) {
// 查询对象,存储查询条件数组
Object[] queryObject = new Object[params.size()];
// 获取查询参数
int index = 0;

if(StringUtils.isNotBlank(sql)){
char[] chars = sql.toCharArray();
String key = new String();
List<String> keylist = new ArrayList<String>();

int k = 0;
for(char c : chars){
if(' '==c){
int now = k+1;
while(now<chars.length && chars[now] == ' '){
now++;
}
// 如果空格之后是 = ,则保留key
if(chars[now] == '='){
keylist.add(key);
key = new String();
continue;
}else {
// 如果空格之后不是 = ,则清空key
key="";
}
} else if('=' == c){
keylist.add(key);
key = new String();
continue;
}
key += c;
k++;
}

for(String keys : keylist){
String value = null == params.get(keys.trim())? "":params.get(keys.trim()).toString();
if(StringUtils.isNotBlank(value)){
queryObject[index++] = value;
}
}
}else {
// 初始化查询对象
for (String param : params.keySet()) {
queryObject[index++] = params.get(param);
}
}

return queryObject;
}

/**
* 查询单一对象
* @param sql 执行sql ,使用占位符
* @param params 参数
* @param returnClass 返回类型
* @return
*/
private Object queryForObject(String sql,@SuppressWarnings("rawtypes") final Class returnClass){
//调用queryForObject并且重新RowMapper回调方法
return getJdbcTemplate().queryForObject(sql,new RowMapper() {
public Object mapRow(ResultSet resultSet, int rowNum) throws SQLException {
if(1 < rowNum){
throw new RuntimeException("query result is more than one!");
}
//~~~ return value 组装返回对象
Object object = getObjectFromResultSet(resultSet,returnClass);

return object;
}
});
}

/**
* 组装查询语句
* <p>
* 	目前只支持了全部列查询
* 	关于排序列(可变长度参数部分):
*  @see queryForListOrderRow
* </p>
* @param rows 需要查找的列,如果null,则全字段
* @param params 参数map
* @param offset 偏移量,-1标示不分页
* @param pagesize 分页大小,-1标示不分页
* @param useValue 是否使用参数值作为搜索条件的值,若false,则使用?代替
* @return string 查询sql
*/
private String buildQuerySql(List<String> rows,Map<String,Object> params,int offset,int pagesize,
boolean useValue,Map<String,String>... orders){
// 获取需要查找的列
String listStr = getSelecteKeyFromList(rows);
// 组装sql
String sql = SQL_SELECT+listStr+ SQL_FROM + tableName;

//如果后面不含有查询条件,则直接返回
if(null!=params && 0 < params.size()){
sql = getSqlCondition(sql,params, useValue);
}
// 获取排序部分
sql = getSqlOrder(sql,orders);
// 获取分页部分
sql = getPagingSql(sql,offset,pagesize);

return sql;
}

/**
* 替换sql中的#占位符# 为具体值
* #param# --> paramValue
* @param sql
* @param params
* @return
*/
private static String getSqlFromPlaceHolder(String sql,Map<String,Object> params){
if(null == params || 0 == params.size()){
return sql;
}
for(String param : params.keySet()){
String placeHolder = SQL_PLACEHOLDER+param+SQL_PLACEHOLDER;
Object object = params.get(param);
String value = "";
if(object instanceof Object[]){
for(int i = 0;i < ((Object[])object).length; i++){
value += "'"+((Object[])object)[i].toString()+"'";
value += SQL_SPLIT;
}

int splitPoint = value.lastIndexOf(SQL_SPLIT.trim());
value = getSubString(value,0, value.length()-splitPoint);//去掉最后一个逗号
}else {
value = "'"+object.toString()+"'";
}

sql = sql.replaceAll(placeHolder, value);
}

return sql;
}

/**
* 获取sql的分页部分 limit x,y
* @param sql
* @param offset
* @param pagesize
* @return
*/
private static String getPagingSql(String sql,int offset,int pagesize){
if(-1 != offset || -1 != pagesize){
// limit offset,pagesize
sql += (SQL_LIMIT+offset+SQL_SPLIT+pagesize+" ");
}
return sql;
}

/**
* 组装根据条件查询总记录数的sql
* @param params 条件
* @return sql语句
*/
private String buildQueryConteSql(Map<String,Object> params){
// 获取需要查找的列
String sql = SQL_SELECT+SQL_COUNT+SQL_FROM+ tableName;

//如果后面不含有查询条件,则直接返回
if(null!=params && 0 < params.size()){
sql = getSqlCondition(sql,params, false);
}

return sql;
}

/**
* 从查询列的列表中取出列名,并按照sql的要求逗号隔开,如 a,b,c,d
* 如果传入查询列的列表为空,或者长度为0,怎返回 * ,代表全部字段都查询
* @param rows
* @return
*/
private static String getSelecteKeyFromList(List<String> rows){
if(null == rows || 0 == rows.size()){
return "*";
}
String listStr = rows.toString();
listStr = getSubString(listStr, 1, 1);
return listStr;
}

/**
* 组装更新对象语句
* 除了主键外的全字段更新,限制条件可以自由设定
* @param object 更新对象
* @param useValue 是否使用具体值替代占位符 ?
* @param conditions 查询条件
* @return 组装后的sql
*/
private String buildUpdateObjectSql(Object object,boolean useValue,Map<String,Object> conditions){
//组装更新sql
String sql = SQL_UPDATE + tableName + SQL_SET;

//获取域数组
Field[] fields = getFieldFromObject(object);

//获取属性和值的map,不包括主键和序列ID
Map<String, Object> params = getParamMap(object, fields);

//获取更新sql的set部分
sql = getUpdateSqlSetPart(sql,params,object.getClass(),useValue);

//Be Attention!!!
return getSqlCondition(sql,conditions, useValue);
}

/**
* 组装更新部分字段sql
* @param updateFileds 需要更新的字段以及更新值
* @param objectClass 更新对象
* @param useValue 是否使用具体值替代占位符
* @param conditions 查询条件
* @return
*/
private String buildUpdateFieldSql(Map<String,Object> updateFileds,@SuppressWarnings("rawtypes") Class objectClass,boolean useValue,Map<String,Object> conditions){
//组装更新sql
String sql = SQL_UPDATE + tableName + SQL_SET;

//获取更新sql的set部分
sql = getUpdateSqlSetPart(sql,updateFileds,objectClass,useValue);

//Be Attention!!!
return getSqlCondition(sql,conditions, useValue);
}

/**
* 获取更新sql的set部分
* @param sql sql前半部分
* @param updateFileds 需要更新的字段
* @param objectClass 对象类型
* @param useValue 是否使用占位符
* @return
*/
private static String getUpdateSqlSetPart(String sql,Map<String,Object> updateFileds,@SuppressWarnings("rawtypes") Class objectClass,boolean useValue){
//获取域数组
Field[] fields = getFieldsFromClass(objectClass);

//更新sql必须含有需要修改的字段的内容,否则抛出异常
if(null == updateFileds || 0 >= updateFileds.size()){
throw new RuntimeException("can not update without values!");
}
//添加修改字段的sql片段,set的顺序和DO类中的顺是相同的,以便于后续batch操作
for(Field field : fields){
String rowName = field.getName();
if(updateFileds.containsKey(rowName)){
sql += (rowName + SQL_EQUAL +(useValue? (StringUtils.isBlank(updateFileds.get(rowName).toString())? "null":"'"+updateFileds.get(rowName)+"'"):SQL_PLACE_HOLDER));
sql += SQL_SPLIT;
}
}

int lastD = sql.lastIndexOf(',');
sql = getSubString(sql,0,sql.length()-lastD);//去掉最后的一个逗号

return sql;
}

/**
* 获取sql语句的后半部分,从where开始的条件设定部分
* @param sql sql前半部分,可以是select或者update或者delte,不限
* @param conditions 条件map
* @param useValue 是否使用具体值替代占位符?
* @return
*/
private static String getSqlCondition(String sql,Map<String,Object> conditions,boolean useValue){
if(null == conditions || 0 == conditions.size()){
return sql;
}
//开始组装条件
sql += SQL_WHERE;

for(String key : conditions.keySet()){
sql += (key+SQL_EQUAL);
sql += useValue? "'"+conditions.get(key)+"'":SQL_PLACE_HOLDER;
sql += SQL_AND;
}

return getSubString(sql,0, 5);//取消最后的" and ";
}

/**
* 获取sql的后半order by的部分,如果没有指定排序,那么直接返回sql
* @param sql sql前半部分,通常截止于where语句
* @param orders 排序列的map,按照排序的次序依次排列
* @return 转换后的sql
*/
private static String getSqlOrder(String sql,Map<String,String>... orders){
if(null == orders || 0 == orders.length){
return sql;
}else {
sql += SQL_ORDER_BY;
}

//遍历order组,添加附加的排序条件
for(int i = 0; i < orders.length; i++){
//获取其中的每一组,并获取其中的key和value
Map<String,String> orderItem = orders[i];
if(!orderItem.keySet().isEmpty()){
//使用迭代器取出map中的第一个键值对,通常也是当前map中的唯一一对
Iterator<String> index = orderItem.keySet().iterator();
if(index.hasNext()){
String key = index.next();
sql += (" " + key + " "+orderItem.get(key));//like  name desc
sql += SQL_SPLIT;//like name desc,
}
}
}
int splitPoint = sql.lastIndexOf(SQL_SPLIT.trim());
sql = getSubString(sql,0, sql.length()-splitPoint);//去掉最后一个逗号

return sql;
}

/**
* 获取部分字符串
* @param str
* @param begin 起始位数,从首位开始计数,0开始
* @param end 从末尾开始计数的,截止位
* @return
*/
private static String getSubString(String str,int begin,int end){
return str.substring(begin, str.length()-end);
}

/**
* 从对象中获取Field数组
* @param object
* @return
*/
private Field[] getFieldFromObject(Object object){
@SuppressWarnings("rawtypes")
Class objectclass = object.getClass();
Field[] fields = getFieldsFromClass(objectclass);
return fields;
}

/**
* 获取结果的map<fieldName,fieldValue>
* <p>
* 	从数据库中获取而来的ResultSet,类型为 <数据库字段相同大小写的字符串,数据库字段类型>
*  我们需要转换成:<对象中的属性名称大小写的字符串,对象中的属性的类型>
* </p>
* @param resultSet 结果set
* @param fields 属性数组
* @throws Exception
*/
private Map<String,? extends Object> getResultMapFromResultSet(ResultSet resultSet,Field[] fields) throws Exception{
//~~~ return value
Map<String,Object> map = new HashMap<String,Object>();

//获取元数据
ResultSetMetaData setMetaData = resultSet.getMetaData();
//遍历各列,获取各列的值和在DO类中对应的属性的名称
for(int i=1;i<=setMetaData.getColumnCount();i++){
//获得列名称
String columnName = setMetaData.getColumnName(i);//特别注意,这里的下标从1开始
if(logger.isDebugEnabled()){
logger.debug("get column:"+columnName);
}

//获得当前列的值
Object rowObject = resultSet.getObject(columnName) == null ? "":resultSet.getObject(columnName);

//获取当前列对应的属性在属性组中的下标
int index = getFieldIndexOfObject(fields,columnName);
if(-1 == index){
throw new Exception("can not find index of column :"+columnName+" in fields.");
}

//将当前字段从数据库类型转换成DO中的类型
rowObject = ConvertUtils.convert(rowObject.toString(), fields[index].getType());

//获得当前列在对象中对应的属性名
String realName = getFieldRealNameOfObject(fields,columnName);
if(null == realName || "".equals(realName)){
logger.error("no field match the name:"+columnName);
throw new Exception();
}

map.put(realName, rowObject);
}

return map;
}

/**
* 用于获取fields中当前数据库列对应的名字
* @param fields 属性域数组
* @param rowNameInResultSet
* @return
*/
private String getFieldRealNameOfObject(Field[] fields,String rowNameInResultSet){
List<String> fieldNameSet = getFiledNameList(fields);
//一次遍历,不分大小写,用于解决DO和数据库字段的属性名字大小写不一致的问题
for(String s:fieldNameSet){
if(StringUtils.equalsIgnoreCase(s, rowNameInResultSet)){
return s;
}
}
return null;
}
/**
* 返回当前列对应的属性在field数组中的下标
* @param fields 对象含有的filed数组
* @param rowNameInResultSet 字段名,可以使数据库中的名称也可以是属性名称
* @return
*/
private int getFieldIndexOfObject(Field[] fields,String rowNameInResultSet){
List<String> fieldNameSet = getFiledNameList(fields);
//一次遍历,不分大小写,用于解决DO和数据库字段的属性名字大小写不一致的问题
int index = 0;
for(String s:fieldNameSet){
if(StringUtils.equalsIgnoreCase(s, rowNameInResultSet)){
return index;
}
index++;
}
return -1;
}

/**
* 从select查询语句获取查询count的语句
* @param sql
* @return
*/
private static String getCountSqlFromSelectSql(String sql){
int selectIndex = sql.indexOf(SQL_SELECT.trim());
String pre = StringUtils.substring(sql, 0, selectIndex+7);
int fromIndex = sql.indexOf(SQL_FROM.trim());
String fix = StringUtils.substring(sql, fromIndex, sql.length());

return pre + SQL_COUNT + fix;
}

/**
* 根据class获取一个实例对象
* @param class
* @return null 或者对象实例
*/
private Object getInstanceByClass(@SuppressWarnings("rawtypes") Class className){
Object object = null;
try {
object = className.newInstance();//new 一个对象

//把产生的异常都吃掉,这里返回null可以触发上层抛出异常
} catch (InstantiationException e) {
logger.error("new instance exception!",e);
} catch (IllegalAccessException e) {
logger.error("can not access the instance method!",e);
}
//return null or a object
return object;
}

/**
* 根据类名获取所有声明的属性列表
* 注意其中也包含了不属于数据库对应字段的属性,比如序列号ID
* @param className 类名称
* @return field数组
*/
private static Field[] getFieldsFromClass(@SuppressWarnings("rawtypes") Class className){
Field[] fields = className.getDeclaredFields();
return fields;
}

/**
* 根据类名获取除了SERIALVERSIONUID外的属性列表
* @param className 类名称
* @param isIncludeKeyId 是否包含id
* @return field数组
*/
private Field[] getFieldsMatchedDBFromClass(@SuppressWarnings("rawtypes") Class className,boolean isIncludeKeyId){
Field[] fields = getFieldsFromClass(className);
Field[] newfields = new Field[isIncludeKeyId? fields.length-1:fields.length-2];//如果不包含主键,则比原来少两位

int index = 0;
for(Field f : fields){
if(isIncludeKeyId? !checkIsSerivalVersioinUID(f.getName()):checkIsNeedField(f.getName())){
newfields[index++] = f;
}
}
return newfields;
}

/**
* 根据属性数组获取属性名称的set
* 这里必须使用list,以保持次序
* @param fields
* @return
*/
private static List<String> getFiledNameList(Field[] fields) {
//~~~ return value
List<String> fieldNameSet = new ArrayList<String>();

// get the name of each
for (int i = 0; i < fields.length; i++) {
fieldNameSet.add(fields[i].getName());
}
return fieldNameSet;
}
/**
* 设置需要增加的属性以及主键
* 针对于insert方法,提供需要插入的字段名称,其中不包括主键ID和序列号SerivalVserionId
* @param fieldNameSet
*/
private void setUsingListFromNameSet(SimpleJdbcInsert inserActor,List<String> fieldNameSet) {
//~~~ return value
List<String> usingColums = new ArrayList<String>();

// 使用所有的除了主键和序列号的字段名称
for (String field : fieldNameSet) {
if (StringUtils.equalsIgnoreCase(field,
DEFAULT_SERIALVERSIONUID_NAME)) {
//序列号掠过
continue;
}
if (!StringUtils.equalsIgnoreCase(field, DEFAULT_ID_NAME)) {
//不是主键,放入字段列表
usingColums.add(field);
} else {
//主键作为返回字段
inserActor = inserActor.usingGeneratedKeyColumns(field);
}
}
inserActor.setColumnNames(usingColums);
}

/**
* 检查是否是序列号ID
* @param field
* @return
*/
private boolean checkIsSerivalVersioinUID(String field){
return StringUtils.equalsIgnoreCase(field,DEFAULT_SERIALVERSIONUID_NAME);
}
/**
* 获取插入数据库中的sql需要的参数Map
* 其中不包括主键和序列号
* @param object 实例化后的对象
* @param fields 对象类包含的class
* @return <属性名称,属性值>
* @throws SecurityException
*/
private Map<String, Object> getParamMap(Object object, Field[] fields) throws SecurityException{
//~~~ return value
Map<String, Object> paramMap = new HashMap<String, Object>();
//依次遍历对象的get方法,获取对象的属性值,放入map中
for (int i = 0; i < fields.length; i++) {
if (!checkIsNeedField(fields[i].getName())) {
continue;
} else {
String value = getValueByName(object,fields[i].getName());
paramMap.put(fields[i].getName(), value);
}
}
return paramMap;
}

/**
* 根据名称获取对象中的值
* @param object 对象
* @param name 属性名
* @return
* @throws RuntimeException
*/
private String getValueByName(Object object,String name) throws RuntimeException{
String methodName = getGetMethod(name);
if(logger.isDebugEnabled()){
logger.debug("run method:" + methodName);
}
try {
// 通过代理执行访问器
Method method = object.getClass().getMethod(methodName); // get方法没有参数,不需要获取参数类型,fields[i].getGenericType().getClass()
Object result = method.invoke(object, new Object[] {});//调用get方法获取属性值
String value;

if(null!=result && result instanceof Date){
DateFormat dateFormat = new SimpleDateFormat(DEFAULT_MYSQL_TIME_STYLE);
String timstr = dateFormat.format(result);
value = timstr;
}else {
value = null==result? "":result.toString();
}

return value;
} catch (SecurityException e) {
// 由安全管理器抛出的异常,指示存在安全侵犯
throw e;
} catch (NoSuchMethodException e) {
// 没有该方法
logger.error("There is no method '"+methodName+"' in Class "+object.getClass()+"! Check your getter method name!",e);
return null;
}catch (IllegalArgumentException e) {
// 参数不正确
logger.error("IllegalArgumentException happend because the method '"+methodName+"'"+"' in Class "+object.getClass()+ "has some parameters!",e);
return null;
} catch (IllegalAccessException e) {
// 访问的方法不能被访问,一般是由于private等权限问题
logger.error("The method '"+methodName+"' in Class "+object.getClass()+"can not be accessed!Check your getter method whether it is private of protected!",e);
return null;
} catch (InvocationTargetException e) {
// 映射目标异常
logger.error("The invoke method '"+methodName+"' in Class "+object.getClass()+"is not right!Check your getter method name!",e);
return null;
}
}

/**
* 获取默认的get方法的名字,根据spring的默认规则
* @param fieldName
* @return
*/
private String getGetMethod(String fieldName){
//生成诸如getParam1的方法名称
String methodName = GET_METHOD_PRE + changeFirstChar2upper(fieldName);
return methodName;
}

private String getSetMethod(String fieldName){
//生成诸如setParam1的方法名称
String methodName = SET_METHOD_PRE + changeFirstChar2upper(fieldName);
return methodName;
}
/**
* 将字符串的首字母大写
* @param fieldName
* @return
*/
private static String changeFirstChar2upper(String fieldName){
return fieldName.toUpperCase().charAt(0) + fieldName.substring(1, fieldName.length());
}

/**
* 检查是否是必要的需要修改的字段
* @param fieldName
* @return
*/
private boolean checkIsNeedField(String fieldName){
if (StringUtils.equalsIgnoreCase(fieldName, DEFAULT_SERIALVERSIONUID_NAME)
|| StringUtils.equalsIgnoreCase(fieldName, DEFAULT_ID_NAME)) {
return false;
}
return true;
}
/***************************************///getter & setter //***********************************************
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐