您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關Java如何使用反射把對象轉換成MongoDb的結構的內容。小編覺得挺實用的,因此分享給大家做個參考。一起跟隨小編過來看看吧。
反射是 Java 的一個高級技巧,大量地用在各種開源項目上。比如,Spring、Tomcat、Jetty 等等項目中,都大量地用到了反射。
作為 Java 程序員,我們如果用好反射,不但能提高自己的技術水平,還能開發出更好的項目。
然而,雖然很多人聽說過反射,但卻不知道應該用在哪里。
那么,我們就從實際工作出發,使用反射,把對象轉換成 MongoDb 的數據結構。當你在搞懂這個例子后,就能明白反射是怎么個用法。
在電商系統中,一些數據要保存到 MongoDb 中,以此來提高查詢的性能。但在此之前,我們必須把數據先轉換成 MongoDb 的結構,也就是把 Java 對象轉換成 Document。
比如,訂單信息要存到 MongoDb 中,就得把訂單對象轉換成 Document。
可這樣一來,每個實體類都得開發一個 2Doc() 方法。這個方法毫無技術含量,就是把各種字段 put 到 Document 里面。而且一旦字段多了,一不留神就會寫錯代碼,你感受一下。
public class Order { private Long id; private Long userId; private String orderNo; private BigDecimal amount; private String createTime; private String updateTime; // 省略無數字段 // 轉換方法:訂單轉doc public Document order2Doc(Order order) { Document doc = new Document(); doc.put("id", order.getId()); doc.put("userId", order.getUserId()); doc.put("orderNo", order.getOrderNo()); doc.put("amount", order.getAmount()); doc.put("createTime", order.getCreateTime()); doc.put("updateTime", order.getUpdateTime()); // 省略無數put... return doc; } }
除此之外,我們還得從 MongoDb 中取數據,把 Document 轉換回 Java 對象,你再感受一下。
public class Order { private Long id; private Long userId; private String orderNo; private BigDecimal amount; private String createTime; private String updateTime; // 省略無數字段 // 轉換方法:doc轉訂單 public Order doc2Order(Document doc) { Order order = new Order(); order.setId((Long) doc.get("id")); order.setUserId((Long) doc.get("userId")); order.setOrderNo((String) doc.get("orderNo")); order.setAmount((BigDecimal) doc.get("amount")); order.setCreateTime((String) doc.get("createTime")); order.setUpdateTime((String) doc.get("updateTime")); // 省略無數set... return order; } }
光是一個訂單類都這么麻煩了,何況這樣的類不止一個,而且項目總有新需求,如果一個字段改了,那你麻煩大了,說不定要把整個項目翻一遍。
因此,為了少出錯,必須優化這兩個轉換方法,而這次優化用到了 Java 的兩個高級特性:反射、泛型。為了讓大家更直觀的了解,我將分成兩個版本迭代。
第一版,利用反射,簡化實體類的轉換方法;第二版,利用泛型、反射,提取 MongoDb 工具類;
接下來,我們就一步步迭代吧~
在第一版的迭代中,我們要簡化實體類的兩個轉換方法。
我們先從 Java 對象轉 Document 開始,還是以 Order 類為例。
首先,我們通過反射,獲取到訂單類的所有字段信息;然后,使用循環遍歷這些字段;最后,在循環中,我們放開字段的訪問權限,把字段 put 到 Document 里面。
public class Order { // ...省略無數字段 public Document order2Doc(Order order) throws Exception { Document doc = new Document(); // 獲取所有字段:通過 getClass() 方法獲取 Class 對象,然后獲取這個類所有字段 Field[] fields = order.getClass().getDeclaredFields(); for (Field field : fields) { // 開放字段操作權限 field.setAccessible(true); // 設置值 doc.put(field.getName(), field.get(order)); } return doc; } }
你可以看到,經過反射改造后,代碼簡單了很多。一個對象無論有多少個字段,要寫多少 put 操作,只要這幾行代碼就能搞定。Java 對象轉成 MongoDb 的結構,看起來也不那么麻煩了。
照著這個思路,我們再來改造第二個方法,Document 轉 Java 對象。
public class Order { // ...省略無數字段 public Order doc2Order(Document doc) throws Exception { Order order = new Order(); for (String key : doc.keySet()) { // 獲取字段 Field field = order.getClass().getDeclaredField(key); // 開放字段操作權限 field.setAccessible(true); // 設置值 field.set(order, doc.get(key)); } return order; } }
首先,我們使用循環遍歷 Document;在循環中,使用反射獲取相應的字段,再放開字段的訪問權限,把 Document 的值設置到對象的字段里。
到了這兒,我們利用反射,簡化了兩個實體類的轉換方法,第一版的迭代基本完成了。剩下的工作,就是復制粘貼,把各個類重新改造一遍。
然而,經過這一版迭代,雖然減少了很多工作,但依然有很多不合理的地方。
首先,重復代碼還是很多。每個實體類都有兩個轉換方法,但這兩個方法的核心邏輯是一樣的,完全沒必要到處復制。
然后,這不是實體類應該承擔的功能。實體類只負責短暫保留數據,不負責任何持久化功能。你把數據存到哪里,該轉換成什么數據結構,這和實體類沒什么關系。
換句話說,我們還得做第二次迭代。
簡單來說,泛型是一種風格或范式,你不用一開始就指明具體的參數類型,而是在使用的時候再確定參數類型。
如果把泛型、反射結合在一起,能幫我們減少很多重復代碼。
我們來看看,該怎么做第二次迭代?
先從 Java 對象轉 Document 開始。我們先聲明一個泛型方法;然后,通過反射,獲取泛型類的所有字段信息,再使用循環遍歷這些字段;最后,在循環中,把字段 put 到 Document 里面。
public class MongoDbUtils { // 定義泛型方法: // 1. 在返回值前,聲明泛型參數 <參數名>; // 2. 傳入參數時,指定一個泛型參數 public static <T> Document obj2Doc(T obj) throws Exception { Document doc = new Document(); // 獲取所有字段:通過 getClass() 方法獲取 Class 對象,然后獲取這個類所有字段 Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { // 開放字段操作權限 field.setAccessible(true); // 設置值 doc.put(field.getName(), field.get(obj)); } return doc; } }
在加入泛型后,重復代碼大量減少了,實體類不用再單獨寫 2Doc()
方法了。在使用的時候,只要調用 MongoDbUtils.obj2Doc()
就行。
按照同樣的思路,我們繼續來改造第二個方法,Document 轉 Java 對象。
public class MongoDbUtils { // 定義泛型方法: // 1. 在返回值前,聲明泛型參數 <參數名>; // 2. 傳入參數必須是 Class,但這個 Class 是泛型參數,不限制類型 public static <T> T doc2Obj(Document doc, Class<T> clazz) throws Exception { // 實例化泛型對象 T obj = clazz.newInstance(); for (String key : doc.keySet()) { // 獲取字段 Field field = clazz.getDeclaredField(key); // 開放字段操作權限 field.setAccessible(true); // 設置值 field.set(obj, doc.get(key)); } return obj; } }
首先,我們定義實例化一個泛型對象;然后,我們使用循環遍歷 Document;最后,在循環中,使用反射獲取相應的字段,把 Document 的值設置到泛型對象的字段里。
第二版的迭代就基本完成了。我們在第一版迭代的基礎上,加入了泛型,得到了一個工具類 MongoDbUtils
,這個工具類得到結果和以前完全一樣,你可以看下測試代碼。
public static void main(String[] args) throws Exception { Order order = new Order(); order.setId(0L); order.setUserId(0L); order.setOrderNo("1"); order.setAmount(new BigDecimal("0")); order.setCreateTime("2"); order.setUpdateTime("3"); System.out.println("原始數據:" + order); Document document = MongoDbUtils.obj2Doc(order); System.out.println("轉換doc數據:" + document); Order order1 = MongoDbUtils.doc2Obj(document, Order.class); System.out.println("轉換java數據:" + order1); } 運行結果: 原始數據:Order(id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3) 轉換doc數據:Document{{id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3}} 轉換java數據:Order(id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3)
這樣一來,我們就不用保留實體類上的轉換方法了,剩下的工作就是刪代碼。
MongoDb 和 Java 對象的互相轉換就完成了。我們做了兩次迭代,第一次迭代利用了反射,把大量手動 set/get 操作給去掉了;第二次迭代在原來的基礎上,加入了泛型的應用,又去掉了一堆重復代碼。
感謝各位的閱讀!關于Java如何使用反射把對象轉換成MongoDb的結構就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。