1. 程式人生 > >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));
}


綜上,輪子完畢。

相關推薦

Spring JdbcTemplate 查詢結果Map反向生成Java實體

以前寫過一篇文章吐槽過Spring JdbcTemplate的queryForList方法(參見:http://blog.csdn.net/will_awoke/article/details/12617383),因為這個方法只支援單資料型別泛型實體,而想返回自定義實體時

Spring JdbcTemplate 查詢出的Map,是如何產生大小寫忽略的Key的?

Java 是區分大小寫的,普通的Map例如HashMap如果其中的key="ABC" value="XXX"那麼map.get("Abc") 或 map.get("abc")是獲取不到值得。但Spring中產生了一個忽略大小寫的map使我產生了好奇例如 jdbcTempla

MyBatis反向生成Java實體類和Mapper對映檔案

首先在maven中新增 mybatis-generator-maven-plugin 外掛 <plugin> <groupId>org.mybatis.generator</groupId> <ar

hibernateTemplate 使用原生sql查詢,並將查詢結果直接封裝成map物件

private List<?> findBySQLForWhat(String sql,Object[] args,String what) { SQLQuery query = this.getSession().createSQLQuery(sql);

php中mysqli 處理查詢結果的幾個方法

數值 集中 style 索引 php bsp 枚舉 tab object 最近對php查詢mysql處理結果集的幾個方法不太明白的地方查閱了資料,在此整理記下 Php使用mysqli_result類處理結果集有以下幾種方法 fetch_all() 抓取所有的結果行並且

遍歷查詢結果,update數據

cas code view sed closed clas alt upd begin 1 set rowcount 0 2 select NULL mykey, * into #mytemp from dbo.DIM_DISTRIBUTOR 3 4 s

使用resultMap定義查詢結果,實現關聯查詢

操作 測試 nal spa void ltm 介紹 規則 print 接下來介紹resultMap定義查詢結果集,實現關聯查詢 1 首先在接口中定義操作的方法 public interface EmployeeMapperPlus { public Employee get

SELECT查詢結果INSERT到數據表

華盛頓 sel fff tro address 存在 插入 提取 語句 簡介 將查詢語句查詢的結果集作為數據插入到數據表中。 一、通過INSERT SELECT語句形式向表中添加數據 例如,創建一張新表AddressList來存儲班級學生的通訊錄信息,然後這些信息恰好存

spring jdbcTemplate查詢使用

ger emp template result 結果類型 指定 str rowset sele 1.查詢一行數據並返回int型結果 jdbcTemplate.queryForInt("select count(*) from test"); 2. 查詢一行數據並將該行數

Oracle 對查詢結果操作

轉自:https://www.cnblogs.com/lingyejun/p/7092206.html 在Oracle中提供了三種類型的集合操作: 並(UNION)、交(INTERSECT)、差(MINUS) Union:對兩個結果集進行並集操作,不包括重複行,同時進行預設規則的排序; Union Al

Oracle 對查詢結果操作

結果集 https min rac 指定 方式 union inter 查詢 轉自:https://www.cnblogs.com/lingyejun/p/7092206.html 在Oracle中提供了三種類型的集合操作: 並(UNION)、交(INTERSECT)、差(

mybatis查詢結果Map型別

1.mapper.xml <select id="findYwmsid" resultType="java.util.Map"> select DISTINCT(yid) AS "yid",sd.label AS "name" from qk

Oracle Union Union All Intersect Minus 4種對查詢結果操作

Oracle Union Union All 對查詢結果集操作 在Oracle中提供了三種類型的集合操作: 並(UNION)、交(INTERSECT)、差(MINUS) Union:對兩個結果集進行並集操作,不包括重複行,同時進行預設規則的排序; Union All:對兩個結果集進行並集

php中mysqli 處理查詢結果總結

在PHP開發中,我們經常會與資料庫打交道。我們都知道,一般的資料處理操作流程為 接收表單資料 資料入庫 //連線資料庫 $link = mysqli_connect("my_host", "my_user", "my_password", "my_db"

mysql儲存過程之迴圈遍歷查詢結果

-- 建立儲存過程之前需判斷該儲存過程是否已存在,若存在則刪除 DROP PROCEDURE IF EXISTS init_reportUrl; -- 建立儲存過程 CREATE PROCEDURE init_reportUrl() BEGIN -- 定義變數 DECLARE s int

Arcgis for Js QueryTask查詢結果的定位

通常我們在對服務查詢到結果集後,需要把視域定位到結果集上,這時可以使用到 graphicsUtils來實現    var queryTask = new esri.tasks.QueryTask(             "http://localhost:6080/arc

SQLSERVER 儲存過程實現分頁查詢 C#後臺獲取查詢結果

一、為什麼要用分頁查詢         在列表查詢時由於資料量非常多,一次性查出來非常慢,也不能一次顯示給客戶端,特別是在使用ExtJS的GridPanel時候,顯示資料量達到200條時對效能影響難以容忍,所以需要考慮將資料分批次查詢出來,每頁顯示一定量的資料,這就是資料要

向表1中插入查詢t2的查詢結果

向一個表中插入另一個表中的查詢結果集,可以通過 insert into 表1(欄位1,欄位2) select(欄位3,欄位4) from 表2 當然:欄位1,2分別與欄位3,4的資料型別對應。 1.建立表t1 create table t1( t1_id number,

mybatis查詢結果,返回List的物件集合

mapper介面中寫的方法的返回值為List的物件陣列首先需要在mapper.xml中對映一個resultmap,column為類中的屬性也就是表中所對應的欄位。程式碼如下:<resultMap id="seeShare" type="com.example.demo.

Mybatis關聯查詢結果物件巢狀

在查詢時經常出現一對多”的關係,所有會出現巢狀物件的情況,Mybatis在resultMap提供了collection標籤,本文適合有一定Mybatis基礎的讀者查閱 資料模型WeixinActivity2018User.java publ