分享

SpringJdbcTemplate操作Clob和Blob的通用类封装

 凌氏 2014-08-27

        项目中使用SpringJdbcTemplate来操作数据库,简单方便实用(根据项目需求选择技术),目前用到Oracle10g数据库,由于其操作大文本使用Clob类型,故而研究了下jdbctemplate对clob和Blob的操作。  

       jdbctemplate对clob和blob的操作使用起来也很简单,网友提供很多实例和代码。例如:

http://hi.baidu.com/sileader/item/0b3335f512378fb731c19999

主要是利用jdbctemplate提供的两个类来操作:LobCreator和LobHandler,具体使用方法可参考该链接。

但是如果某个Bean属性字段太多的话,代码写起来将会很麻烦。是否可以提供一种通用的方法,让每个业务方法操作数据库Clob和Blob时候也可以像操作其他基本数据类型一样,一句代码就完成。例如插入和修改Bean:

Java代码  收藏代码
  1. public <T> void saveOrUpdate(String sql, T bean) {  
  2.     namedParameterJdbcTemplate.update(sql, new BeanPropertySqlParameterSource(bean));  
  3. }  

 经过一些尝试和摸索,我使用反射和注解,写了一个通用类,可以操作查询、修改、添加,满足了项目中的需求。

1、定义了一个注解类,用于bean中属性上,主要是提供属性的数据库字段名以及其数据库类型。

Java代码  收藏代码
  1. /** 
  2.  * @description  
  3.  * @author aokunsang 
  4.  * @date 2013-7-4 
  5.  */  
  6. @Target({ElementType.FIELD,ElementType.METHOD})  
  7. @Retention(RetentionPolicy.RUNTIME)   
  8. @Documented  
  9. @Inherited  
  10. public @interface PmcColumn {  
  11.     /** 
  12.      * 数据库中字段类型 
  13.      * @return 
  14.      */  
  15.     int type();  
  16.     /** 
  17.      * 数据库中字段名 
  18.      * @return 
  19.      */  
  20.     String columnName();  
  21.     /** 
  22.      * 查询时候是否忽略 
  23.      * @return 
  24.      */  
  25.     boolean ignore() default false;  
  26. }  

 2、定义一个反射的工具类,反射操作属性字段的setter和getter方法注入和获取属性值、

Java代码  收藏代码
  1. /** 
  2.  * @description 对bean的反射操作 
  3.  * @author aokunsang 
  4.  * @date 2013-7-3 
  5.  */  
  6. public class BeanUtils {  
  7.   
  8.       /**  
  9.      * @param obj 操作的对象  
  10.      * @param att 操作的属性  
  11.      * */  
  12.     public static Object getter(Object obj, String att) {   
  13.         try {   
  14.             Method method = obj.getClass().getMethod("get" + StringUtils.capitalize(att));   
  15.             return method.invoke(obj);   
  16.         } catch (Exception e) {   
  17.             e.printStackTrace();   
  18.         }  
  19.         return null;   
  20.     }  
  21.     /** 
  22.      * 注入数据 
  23.      * @param obj   类的实例 
  24.      * @param att   属性名 
  25.      * @param value 注入数据内容 
  26.      * @param type  返回的数据类型 
  27.      *  
  28.      */  
  29.     public static void setter(Object obj, String att, Object value, Class<?> type) {   
  30.         try {   
  31.             Method method = obj.getClass().getMethod("set" + StringUtils.capitalize(att), type);   
  32.             method.invoke(obj, value);   
  33.         } catch (Exception e) {   
  34.             e.printStackTrace();   
  35.         }  
  36.     }  
  37.       
  38.     /** 
  39.      * 获取某个属性字段的ignore信息 
  40.      * @param field 
  41.      * @return 
  42.      */  
  43.     public static boolean getPmcColumnIgnore(Field field){  
  44.         Annotation annotation = field.getAnnotation(PmcColumn.class);  
  45.         boolean ignore = false;  
  46.         if(annotation!=null){  
  47.             ignore = ((PmcColumn)annotation).ignore();  
  48.         }  
  49.         return ignore;  
  50.     }  
  51.       
  52.     /** 
  53.      * 获取某个属性的Type信息 
  54.      * @param field 
  55.      * @return 
  56.      */  
  57.     public static int getPmcColumnType(Field field){  
  58.         Annotation annotation = field.getAnnotation(PmcColumn.class);  
  59.         int type = Types.VARCHAR;  
  60.         if(annotation!=null){  
  61.             type = ((PmcColumn)annotation).type();  
  62.         }  
  63.         return type;  
  64.     }  
  65.       
  66.     /** 
  67.      * 获取某个属性的数据库中字段名 
  68.      * @param field 
  69.      * @return 
  70.      */  
  71.     public static String getPmcColumnName(Field field){  
  72.         Annotation annotation = field.getAnnotation(PmcColumn.class);  
  73.         String columnName = "";  
  74.         if(annotation!=null){  
  75.             columnName = ((PmcColumn)annotation).columnName();  
  76.         }  
  77.         return columnName;  
  78.     }  
  79. }  

 3、定义一个对sql语句的转换类,sql语句进行转变,变成需要的字符串。

如:insert into t1 values(:a,:b,:c)  ---->   insert into t1(A,B,C) values(?,?,?);

或者update t1 set A=:a,B=:b where C=:c   ----> update t1 set A=?,B=? where C=?

Java代码  收藏代码
  1. /** 
  2.  * @description 工具类 
  3.  * @author aokunsang 
  4.  * @date 2013-1-9 
  5.  */  
  6. public class Util {  
  7.   
  8.     /** 
  9.      * 分割插入、修改的sql语句 
  10.      * @param sql 
  11.      * @param columnMaps   <属性名,数据库中字段名> 
  12.      * @return 
  13.      */  
  14.     public static Map<String,List<String>> spQuerysql(String sql,Map<String,String> columnMaps){  
  15.         if(StringUtils.isEmpty(sql)) return null;  
  16.         String _sql = sql + " ";  
  17.         String key = _sql.replaceAll(":(.+?),\\s*", "?,").replaceAll(":(.+?)[)]\\s*", "?)").replaceAll(":(.+?)\\s+", "? ");  
  18.         Map<String,List<String>> result = new HashMap<String, List<String>>();  
  19.         List<String> fieldList = new LinkedList<String>();  
  20.         Pattern pattern = Pattern.compile(":(.+?)[)|,|\\s*]");  
  21.         Matcher matcher = pattern.matcher(_sql);  
  22.         StringBuffer insertString = new StringBuffer();  
  23.         while(matcher.find()){  
  24.             String value = matcher.group(1);  
  25.             fieldList.add(value);  
  26.             insertString.append(columnMaps.get(value)+ ",");  
  27.         }  
  28.         if(fieldList.isEmpty() || key.equals(_sql)) return null;  
  29.         StringBuffer key_sb = new StringBuffer(key);  
  30.         if(!key.trim().matches("insert\\s*into\\s*[\\w|_]+?\\(.*?\\)\\s*values.*") && !key.trim().contains("update")){  //判断insert语句是否有数据库字段,比如:insert into t1(ID,NAME)   
  31.             key_sb.insert(key_sb.indexOf("values")-1, "("+insertString.substring(0,insertString.length()-1)+")");  
  32.         }  
  33.         result.put(key_sb.toString(), fieldList);  
  34.         return result;  
  35.     }  
  36. }  

 4、定义一个对clob和blob的通用类[[关键类],也可以说是已经存在的Dao类的扩展类。

Java代码  收藏代码
  1. /** 
  2.  * @description 增强版数据库操作类[添加对clob和blob的部分操作] 
  3.  * @author aokunsang 
  4.  * @date 2013-7-4 
  5.  */  
  6. public class StGenericDao extends GenericDao {  
  7.       
  8.     /** 
  9.      * 查询单条记录 
  10.      * @param <T> 
  11.      * @param sql 
  12.      * @param clazz 
  13.      * @param args 
  14.      * @return 
  15.      */  
  16.     public <T> T _find(String sql,final Class<T> clazz,Object... args){  
  17.         printSqlInfo(sql,args!=null ? Arrays.toString(args) : "");  
  18.         try {  
  19.             return jdbcTemplate.queryForObject(sql,new RowMapper<T>(){  
  20.                 @Override  
  21.                 public T mapRow(ResultSet rs, int rownum) throws SQLException {  
  22.                     T bean = null;  
  23.                     try {  
  24.                         bean = clazz.newInstance();  
  25.                         Field[] fields = clazz.getDeclaredFields();   //获取所有属性  
  26.                         for(Field field : fields){  
  27.                             if(field.getAnnotation(PmcColumn.class)==null) continue;  
  28.                             if(BeanUtils.getPmcColumnIgnore(field)) continue;  
  29.                             switch(BeanUtils.getPmcColumnType(field)) {  //如果Bean中增加了类型,需要在这里以及下面方法中添加case  
  30.                                 case Types.CLOB:{  
  31.                                     BeanUtils.setter(bean, field.getName(), lobHandler.getClobAsString(rs, BeanUtils.getPmcColumnName(field)), field.getType());  
  32.                                     break;  
  33.                                 }  
  34.                                 case Types.BLOB:{  
  35.                                     BeanUtils.setter(bean, field.getName(), lobHandler.getBlobAsBytes(rs, BeanUtils.getPmcColumnName(field)), field.getType());  
  36.                                     break;  
  37.                                 }  
  38.                                 case Types.TIMESTAMP:{  
  39.                                     BeanUtils.setter(bean, field.getName(),rs.getTimestamp(BeanUtils.getPmcColumnName(field)), field.getType());  
  40.                                     break;  
  41.                                 }  
  42.                                 case Types.DATE:{  
  43.                                     BeanUtils.setter(bean, field.getName(),rs.getDate(BeanUtils.getPmcColumnName(field)), field.getType());  
  44.                                     break;  
  45.                                 }  
  46.                                 case Types.INTEGER:{  
  47.                                     BeanUtils.setter(bean, field.getName(),rs.getInt(BeanUtils.getPmcColumnName(field)), field.getType());  
  48.                                     break;  
  49.                                 }  
  50.                                 case Types.VARCHAR:{  
  51.                                     BeanUtils.setter(bean, field.getName(),rs.getString(BeanUtils.getPmcColumnName(field)), field.getType());  
  52.                                     break;  
  53.                                 }  
  54.                                 case Types.NUMERIC:{  
  55.                                     BeanUtils.setter(bean, field.getName(),rs.getLong(BeanUtils.getPmcColumnName(field)), field.getType());  
  56.                                     break;  
  57.                                 }  
  58.                                 case Types.FLOAT:{  
  59.                                     BeanUtils.setter(bean, field.getName(),rs.getFloat(BeanUtils.getPmcColumnName(field)), field.getType());  
  60.                                     break;  
  61.                                 }  
  62.                             }  
  63.                         }  
  64.                     } catch (Exception e) {  
  65.                         e.printStackTrace();  
  66.                     }  
  67.                     return bean;  
  68.                 }  
  69.             },args);  
  70.         } catch (EmptyResultDataAccessException e) {  
  71.             return null;  
  72.         } catch (DataAccessException e) {  
  73.             throw new DaoRuntimeException("----------数据库错误saveOrUpdate()------", e);  
  74.         }  
  75.     }  
  76.     /** 
  77.      * 添加或修改某条记录 
  78.      * @param <T> 
  79.      * @param sql 
  80.      * @param bean 
  81.      */  
  82.     public <T> void _saveOrUpdate(String sql,final T bean){  
  83.         final Map<String,Integer> columnTypes = new HashMap<String,Integer>();  
  84.         Map<String,String> columnMaps = new HashMap<String,String>();  
  85.         Field[] fields = bean.getClass().getDeclaredFields();   //获取所有属性  
  86.         for(Field field : fields){  
  87.             columnTypes.put(field.getName(), BeanUtils.getPmcColumnType(field));  
  88.             columnMaps.put(field.getName(), BeanUtils.getPmcColumnName(field));  
  89.         }  
  90.         final Map<String,List<String>> resultMap = Util.spQuerysql(sql,columnMaps);  
  91.         if(resultMap==null) throw new PmcRuntimeException(String.format("你提供的SQL语句有问题,请详细检查再次尝试运行。SQL:[s%]",sql));  
  92.         Object[] validSql = resultMap.keySet().toArray();   //改变后的Sql语句  
  93.         printSqlInfo(sql+"<<----->>"+validSql[0].toString(),"");   //打印改变前后的sql语句  
  94.         final List<String> fieldList = resultMap.get(validSql[0]);   //对应插入的bean字段  
  95.         jdbcTemplate.execute(validSql[0].toString(),new AbstractLobCreatingPreparedStatementCallback(this.lobHandler) {  
  96.             @Override  
  97.             protected void setValues(PreparedStatement ps, LobCreator lobCreater)  
  98.                     throws SQLException, DataAccessException {  
  99.                 for(int i=0,length=fieldList.size();i<length;i++){  
  100.                     String filedValue = fieldList.get(i);  
  101.                     switch (columnTypes.get(filedValue)) {  
  102.                         case Types.CLOB:{  
  103.                             lobCreater.setClobAsString(ps, i+1, BeanUtils.getter(bean, filedValue)==null ? null : BeanUtils.getter(bean, filedValue).toString());  
  104.                             break;  
  105.                         }  
  106.                         case Types.BLOB:{  
  107.                             lobCreater.setBlobAsBytes(ps, i+1, BeanUtils.getter(bean, filedValue)==null ? null : (byte[])BeanUtils.getter(bean, filedValue));  
  108.                             break;  
  109.                         }  
  110.                         case Types.TIMESTAMP:{  
  111.                             ps.setTimestamp(i+1, BeanUtils.getter(bean, filedValue)==null ? null : (Timestamp)BeanUtils.getter(bean, filedValue));  
  112.                             break;  
  113.                         }  
  114.                         case Types.DATE:{  
  115.                             ps.setDate(i+1, BeanUtils.getter(bean, filedValue)==null ? null : (Date)BeanUtils.getter(bean, filedValue));  
  116.                             break;  
  117.                         }  
  118.                         case Types.INTEGER:{  
  119.                             ps.setInt(i+1, BeanUtils.getter(bean, filedValue)==null ? null : (Integer)BeanUtils.getter(bean, filedValue));  
  120.                             break;  
  121.                         }  
  122.                         case Types.VARCHAR:{  
  123.                             ps.setString(i+1, BeanUtils.getter(bean, filedValue)==null ? null : BeanUtils.getter(bean, filedValue).toString());  
  124.                             break;  
  125.                         }  
  126.                         case Types.NUMERIC:{  
  127.                             ps.setLong(i+1, BeanUtils.getter(bean, filedValue)==null ? null : (Long)BeanUtils.getter(bean, filedValue));  
  128.                             break;  
  129.                         }  
  130.                         case Types.FLOAT:{  
  131.                             ps.setFloat(i+1, BeanUtils.getter(bean, filedValue)==null ? null : (Float)BeanUtils.getter(bean, filedValue));  
  132.                             break;  
  133.                         }  
  134.                     }  
  135.                 }  
  136.             }  
  137.         });  
  138.     }  
  139. }  

 5、对JDBC的配置文件修改,添加lobHandler类,并且注入到StGenericDao中。

Xml代码  收藏代码
  1. <!-- JDBC上传附件时候使用 -->  
  2. <bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" />  
  3.      
  4.    <!-- 默认数据源[showsql-是否显示sql语句] 如果需要操作clob和blob,则声明StGenericDao-->  
  5.    <bean id="genericDao" class="com.pmc.dwa.common.dao.StGenericDao">  
  6.     <property name="simpleJdbcTemplate" ref="dataSource"></property>  
  7.     <property name="showsql" value="true"></property>  
  8.     <property name="lobHandler" ref="lobHandler"></property>  
  9.    </bean>  

 如何使用以上方法,需要注意以下2个方面:

其一:如果某个Bean类中包括Clob和Blob字段,那么该Bean的字段类型需要加入PmcColumn注解。如:

Java代码  收藏代码
  1. /** 
  2.  * @description  
  3.  * @author aokunsang 
  4.  * @date 2013-7-4 
  5.  */  
  6. public class TDemo implements Serializable{  
  7.       
  8.     @PmcColumn(columnName="ID",type=Types.NUMERIC)  
  9.     private Long id;  
  10.     @PmcColumn(columnName="NAME",type=Types.VARCHAR)  
  11.     private String name;  
  12.     @PmcColumn(columnName="DEMO_PIC",type=Types.BLOB)  
  13.     private byte[] pic;       //BLOB类型,属性字段类型为byte[]  
  14.     @PmcColumn(columnName="CONTENT",type=Types.CLOB)  
  15.     private String content;   //CLOB类型,属性字段类型为String  
  16.   
  17.   
  18.     setter and  getter...  
  19. }  

 其二:Service业务方法中注入StGenericdao类,使用其方法即可;当然如果你操作的Bean类没有Clob和Blob类型字段就无需写PmcColumn注解,注入IGenericDao接口也可以。

Java代码  收藏代码
  1. /** 
  2.  * @description  
  3.  * @author aokunsang 
  4.  * @date 2013-7-4 
  5.  */  
  6. @Service  
  7. public class DemoServiceImpl implements IDemoService{  
  8.       
  9.     @Resource(name="genericDao")  
  10.     private StGenericDao genericDao;  
  11.   
  12.     public void saveDemo(TDemo demo){  
  13.         genericDao._saveOrUpdate("insert into tdemo values(:id,:name,:pic,:content)",demo);  
  14.     }  
  15. }  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约