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

Spring JdbcTemplate 查询结果集Map反向生成Java实体

2015-01-04 01:40 288 查看
以前写过一篇文章吐槽过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:

[java] view
plaincopy





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:

[html] view
plaincopy





<dependency>

<groupId>org.hibernate</groupId>

<artifactId>ejb3-persistence</artifactId>

<version>1.0.2.GA</version>

</dependency>

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

[java] view
plaincopy





/**

* 注解映射

*

* @author will_awoke

* @version

* @see Column

* @since

*/

@Target(java.lang.annotation.ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Column {

String name() default "";

}

核心反射工具类如下:

[java] view
plaincopy





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,而就不需要这些轮子了。

应用层调用:

[java] view
plaincopy





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

}

综上,轮子完毕。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐