zoukankan      html  css  js  c++  java
  • Spring JdbcTemplate 查询结果集Map反向生成Java实体(转)

    原文地址:Spring JdbcTemplate 查询结果集Map反向生成Java实体

    以前写过一篇文章吐槽过Spring JdbcTemplate的queryForList方法(参见:http://blog.csdn.net/will_awoke/article/details/12617383),因为这个方法只支持单数据类型泛型实体,而想返回自定义实体时还得自己写callback方法,笔者不想在每个返回自定义实体的query方法中都去写callback处理返回的map,于是索性就自己造了个轮子,有点像hibernate的orm的赶脚。话说,现在用惯了SpringJDBC,反而又不喜欢hibernate了,感觉hibernate太重了,人就是这么奇怪。O(∩_∩)O~

    回归正题,下面讲下造的这个轮子,轮子的应用场景如下:

    1.已使用了 List<Map<String, Object>> org.springframework.jdbc.core.JdbcTemplate.queryForList(String sql, Object[] args, int[] argTypes) throws DataAccessException 方法,想将此方法返回的Map反向生成对应的实体Instance;

    2.而你又不想在使用到上述方法的每处都override callback方法去处理map(和笔者一样懒,O(∩_∩)O~);

    3.你的实体类字段和DBTable中的字段命名不一样,关于这一点下文会提到,其实,真正按着编程规范来的话,实体类是绝对不可能和DB中字段命名一样的。

    如果你具备了上述应用场景,那么可以继续向下看轮子了。

    我们知道jdbcTemplate.queryForList(sql, params, types)返回的是个List<Map<String,Object>>,如:{USER_ID=5438,LOGIN_NAME=admin,PASSWORD=admin123456},其中key是大写的。想根据map反向生成JavaBeanInstance,首先你得拥有一个实体类,下面是一个轮子中用到的Bean.java:

    import java.io.Serializable;
    
    import javax.persistence.Column;
    
    import com.alibaba.fastjson.JSON;
    
    /**
     * 系统用户
     * 
     * column注解配置与hibernate一致,不过只需要name属性,其他属性不再需要
     * name属性值对应数据库中字段名称,忽略大小写
     * 该注解用于map反向生成modelbean
     * 另请参考:ReflectUtil.java
     * 
     * @author will_awoke
     * @version 2014-5-29
     * @see SysUser
     * @since
     */
    public class SysUser implements Serializable
    {
    
        /**
         * 序列号<br>
         */
        private static final long serialVersionUID = 7931705053661707847L;
    
        @Column(name = "USER_ID")
        private Long userId;
    
        @Column(name = "LOGIN_NAME")
        private String loginName;
    
        @Column(name = "PASSWORD")
        private String password;
    
        /**
         * 构造器
         */
        public SysUser()
        {
    
        }
    
        @Override
        public String toString()
        {
            return JSON.toJSONString(this);
        }
    
        //setter getter
        public Long getUserId()
        {
            return userId;
        }
    
        public void setUserId(Long userId)
        {
            this.userId = userId;
        }
    
        public String getLoginName()
        {
            return loginName;
        }
    
        public void setLoginName(String loginName)
        {
            this.loginName = loginName;
        }
    
        public String getPassword()
        {
            return password;
        }
    
        public void setPassword(String password)
        {
            this.password = password;
        }
    
    }

    实体类中使用了@Column注解,用于绑定实体field字段和DB中column字段,思想类似于Hibernate。

    关于@Column 可以使用Hibernate提供的jar:

    <dependency>  
        <groupId>org.hibernate</groupId>  
        <artifactId>ejb3-persistence</artifactId>  
        <version>1.0.2.GA</version>  
    </dependency>  

    或者是自己可以手写个注解:

    /**
     * 注解映射
     * 
     * @author will_awoke
     * @version 
     * @see Column
     * @since
     */
    @Target(java.lang.annotation.ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Column {
    
        String name() default "";
    
    }


    核心反射工具类如下:

    import java.lang.annotation.Annotation;
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    import javax.persistence.Column;
    
    import com.alibaba.fastjson.JSON;
    import com.iss.rabc.bean.SysUser;
    
    
    /**
     * 
     * @author will_awoke
     * @version 2014-5-30
     * @see ReflectUtil
     * @since
     */
    public class ReflectUtil
    {
    
        /**
         * 将jdbcTemplate查询的map结果集 反射生成对应的bean
         * @param clazz 意向反射的实体.clazz
         * @param jdbcMapResult 查询结果集  key is UpperCase
         * @return 
         * @see
         */
        public static <T> T reflect(Class<T> clazz, Map<String, Object> jdbcMapResult)
        {
            //获得
            Field[] fields = clazz.getDeclaredFields();
    
            //存放field和column对应关系,该关系来自于实体类的 @Column配置
            Map<String/*field name in modelBean*/, String/*column in db*/> fieldHasColumnAnnoMap = new LinkedHashMap<String, String>();
            Annotation[] annotations = null;
            for (Field field : fields)
            {
                annotations = field.getAnnotations();
                for (Annotation an : annotations)
                {
                    if (an instanceof Column)
                    {
                        Column column = (Column)an;
                        fieldHasColumnAnnoMap.put(field.getName(), column.name());
                    }
                }
            }
            //存放field name 和 对应的来自map的该field的属性值,用于后续reflect成ModelBean
            Map<String, Object> conCurrent = new LinkedHashMap<String, Object>();
            for (Map.Entry<String, String> en : fieldHasColumnAnnoMap.entrySet())
            {
                //将column大写。因为jdbcMapResult key is UpperCase
                String key = en.getValue().toUpperCase();
                
                //获得map的该field的属性值
                Object value = jdbcMapResult.get(key);
                
                //确保value有效性,防止JSON reflect时异常
                if (value != null)
                {
                    conCurrent.put(en.getKey(), jdbcMapResult.get(key));
                }
            }
            //fastjson reflect to modelbean
            return JSON.parseObject(JSON.toJSONString(conCurrent), clazz);
        }
    
        
        /**
         * test example
         * @param args
         * @throws Exception 
         * @see
         */
        public static void main(String[] args)
            throws Exception
        {            
            //call reflect testing
            Map<String, Object> jdbcMapResult = new HashMap<>();
            jdbcMapResult.put("LOGIN_NAME", "reflect");
            jdbcMapResult.put("PASSWORD", "reflect123456");
            
            System.out.println(ReflectUtil.reflect(SysUser.class, jdbcMapResult));
        }
    }

    工具类中,实现map的替换处理,然后利用fastjson将map反射成JavaBean即可,一如上述的场景条件3中提到,如果实体类字段和DBTable中的字段命名一样直接就可以用fastjson reflect成JavaBean,而就不需要这些轮子了。

    应用层调用:

    import static com.iss.util.ReflectUtil.reflect;
    
    List<Map<String, Object>> mapList = userDao.queryNaviByUser(loginName);
    
    List<SysMenu> meunList = new LinkedList<SysMenu>();
    for (Map<String, Object> jdbcMapResult : mapList)
    {
         //利用工具类反向生成bean
         meunList.add(reflect(SysMenu.class, jdbcMapResult));
    }
  • 相关阅读:
    Thrift全面介绍
    ZooKeeper全面介绍
    Redis全面介绍
    第三篇:彻底解决ssh.invoke_shell() 返回的中文问题
    第二篇:ssh.invoke_shell() 切换root出现的新问题
    第一篇:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc3 in position 0: invalid continuation byte
    pycharm安装 suds模块报错:AttributeError: module 'pip' has no attribute 'main'
    变量赋值理解--Pyton中让两个值互换的方法
    02 Django框架基础(APP的创建访问)
    01 Web框架介绍
  • 原文地址:https://www.cnblogs.com/huanghongbo/p/9003358.html
Copyright © 2011-2022 走看看