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; } }