這篇文章給大家分享的是有關(guān)Java如何使用反射把對(duì)象轉(zhuǎn)換成MongoDb的結(jié)構(gòu)的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考。一起跟隨小編過來看看吧。
專注于為中小企業(yè)提供成都做網(wǎng)站、成都網(wǎng)站建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)麻城免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了1000多家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。反射是 Java 的一個(gè)高級(jí)技巧,大量地用在各種開源項(xiàng)目上。比如,Spring、Tomcat、Jetty 等等項(xiàng)目中,都大量地用到了反射。
作為 Java 程序員,我們?nèi)绻煤梅瓷?,不但能提高自己的技術(shù)水平,還能開發(fā)出更好的項(xiàng)目。
然而,雖然很多人聽說過反射,但卻不知道應(yīng)該用在哪里。
那么,我們就從實(shí)際工作出發(fā),使用反射,把對(duì)象轉(zhuǎn)換成 MongoDb 的數(shù)據(jù)結(jié)構(gòu)。當(dāng)你在搞懂這個(gè)例子后,就能明白反射是怎么個(gè)用法。
在電商系統(tǒng)中,一些數(shù)據(jù)要保存到 MongoDb 中,以此來提高查詢的性能。但在此之前,我們必須把數(shù)據(jù)先轉(zhuǎn)換成 MongoDb 的結(jié)構(gòu),也就是把 Java 對(duì)象轉(zhuǎn)換成 Document。
比如,訂單信息要存到 MongoDb 中,就得把訂單對(duì)象轉(zhuǎn)換成 Document。
可這樣一來,每個(gè)實(shí)體類都得開發(fā)一個(gè) 2Doc() 方法。這個(gè)方法毫無技術(shù)含量,就是把各種字段 put 到 Document 里面。而且一旦字段多了,一不留神就會(huì)寫錯(cuò)代碼,你感受一下。
public class Order { private Long id; private Long userId; private String orderNo; private BigDecimal amount; private String createTime; private String updateTime; // 省略無數(shù)字段 // 轉(zhuǎn)換方法:訂單轉(zhuǎn)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()); // 省略無數(shù)put... return doc; } }
除此之外,我們還得從 MongoDb 中取數(shù)據(jù),把 Document 轉(zhuǎn)換回 Java 對(duì)象,你再感受一下。
public class Order { private Long id; private Long userId; private String orderNo; private BigDecimal amount; private String createTime; private String updateTime; // 省略無數(shù)字段 // 轉(zhuǎn)換方法:doc轉(zhuǎn)訂單 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")); // 省略無數(shù)set... return order; } }
光是一個(gè)訂單類都這么麻煩了,何況這樣的類不止一個(gè),而且項(xiàng)目總有新需求,如果一個(gè)字段改了,那你麻煩大了,說不定要把整個(gè)項(xiàng)目翻一遍。
因此,為了少出錯(cuò),必須優(yōu)化這兩個(gè)轉(zhuǎn)換方法,而這次優(yōu)化用到了 Java 的兩個(gè)高級(jí)特性:反射、泛型。為了讓大家更直觀的了解,我將分成兩個(gè)版本迭代。
第一版,利用反射,簡(jiǎn)化實(shí)體類的轉(zhuǎn)換方法;第二版,利用泛型、反射,提取 MongoDb 工具類;
接下來,我們就一步步迭代吧~
在第一版的迭代中,我們要簡(jiǎn)化實(shí)體類的兩個(gè)轉(zhuǎn)換方法。
我們先從 Java 對(duì)象轉(zhuǎn) Document 開始,還是以 Order 類為例。
首先,我們通過反射,獲取到訂單類的所有字段信息;然后,使用循環(huán)遍歷這些字段;最后,在循環(huán)中,我們放開字段的訪問權(quán)限,把字段 put 到 Document 里面。
public class Order { // ...省略無數(shù)字段 public Document order2Doc(Order order) throws Exception { Document doc = new Document(); // 獲取所有字段:通過 getClass() 方法獲取 Class 對(duì)象,然后獲取這個(gè)類所有字段 Field[] fields = order.getClass().getDeclaredFields(); for (Field field : fields) { // 開放字段操作權(quán)限 field.setAccessible(true); // 設(shè)置值 doc.put(field.getName(), field.get(order)); } return doc; } }
你可以看到,經(jīng)過反射改造后,代碼簡(jiǎn)單了很多。一個(gè)對(duì)象無論有多少個(gè)字段,要寫多少 put 操作,只要這幾行代碼就能搞定。Java 對(duì)象轉(zhuǎn)成 MongoDb 的結(jié)構(gòu),看起來也不那么麻煩了。
照著這個(gè)思路,我們?cè)賮砀脑斓诙€(gè)方法,Document 轉(zhuǎn) Java 對(duì)象。
public class Order { // ...省略無數(shù)字段 public Order doc2Order(Document doc) throws Exception { Order order = new Order(); for (String key : doc.keySet()) { // 獲取字段 Field field = order.getClass().getDeclaredField(key); // 開放字段操作權(quán)限 field.setAccessible(true); // 設(shè)置值 field.set(order, doc.get(key)); } return order; } }
首先,我們使用循環(huán)遍歷 Document;在循環(huán)中,使用反射獲取相應(yīng)的字段,再放開字段的訪問權(quán)限,把 Document 的值設(shè)置到對(duì)象的字段里。
到了這兒,我們利用反射,簡(jiǎn)化了兩個(gè)實(shí)體類的轉(zhuǎn)換方法,第一版的迭代基本完成了。剩下的工作,就是復(fù)制粘貼,把各個(gè)類重新改造一遍。
然而,經(jīng)過這一版迭代,雖然減少了很多工作,但依然有很多不合理的地方。
首先,重復(fù)代碼還是很多。每個(gè)實(shí)體類都有兩個(gè)轉(zhuǎn)換方法,但這兩個(gè)方法的核心邏輯是一樣的,完全沒必要到處復(fù)制。
然后,這不是實(shí)體類應(yīng)該承擔(dān)的功能。實(shí)體類只負(fù)責(zé)短暫保留數(shù)據(jù),不負(fù)責(zé)任何持久化功能。你把數(shù)據(jù)存到哪里,該轉(zhuǎn)換成什么數(shù)據(jù)結(jié)構(gòu),這和實(shí)體類沒什么關(guān)系。
換句話說,我們還得做第二次迭代。
簡(jiǎn)單來說,泛型是一種風(fēng)格或范式,你不用一開始就指明具體的參數(shù)類型,而是在使用的時(shí)候再確定參數(shù)類型。
如果把泛型、反射結(jié)合在一起,能幫我們減少很多重復(fù)代碼。
我們來看看,該怎么做第二次迭代?
先從 Java 對(duì)象轉(zhuǎn) Document 開始。我們先聲明一個(gè)泛型方法;然后,通過反射,獲取泛型類的所有字段信息,再使用循環(huán)遍歷這些字段;最后,在循環(huán)中,把字段 put 到 Document 里面。
public class MongoDbUtils { // 定義泛型方法: // 1. 在返回值前,聲明泛型參數(shù) <參數(shù)名>; // 2. 傳入?yún)?shù)時(shí),指定一個(gè)泛型參數(shù) public staticDocument obj2Doc(T obj) throws Exception { Document doc = new Document(); // 獲取所有字段:通過 getClass() 方法獲取 Class 對(duì)象,然后獲取這個(gè)類所有字段 Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { // 開放字段操作權(quán)限 field.setAccessible(true); // 設(shè)置值 doc.put(field.getName(), field.get(obj)); } return doc; } }
在加入泛型后,重復(fù)代碼大量減少了,實(shí)體類不用再單獨(dú)寫2Doc()
方法了。在使用的時(shí)候,只要調(diào)用MongoDbUtils.obj2Doc()
就行。
按照同樣的思路,我們繼續(xù)來改造第二個(gè)方法,Document 轉(zhuǎn) Java 對(duì)象。
public class MongoDbUtils { // 定義泛型方法: // 1. 在返回值前,聲明泛型參數(shù) <參數(shù)名>; // 2. 傳入?yún)?shù)必須是 Class,但這個(gè) Class 是泛型參數(shù),不限制類型 public staticT doc2Obj(Document doc, Class clazz) throws Exception { // 實(shí)例化泛型對(duì)象 T obj = clazz.newInstance(); for (String key : doc.keySet()) { // 獲取字段 Field field = clazz.getDeclaredField(key); // 開放字段操作權(quán)限 field.setAccessible(true); // 設(shè)置值 field.set(obj, doc.get(key)); } return obj; } }
首先,我們定義實(shí)例化一個(gè)泛型對(duì)象;然后,我們使用循環(huán)遍歷 Document;最后,在循環(huán)中,使用反射獲取相應(yīng)的字段,把 Document 的值設(shè)置到泛型對(duì)象的字段里。
第二版的迭代就基本完成了。我們?cè)诘谝话娴幕A(chǔ)上,加入了泛型,得到了一個(gè)工具類MongoDbUtils
,這個(gè)工具類得到結(jié)果和以前完全一樣,你可以看下測(cè)試代碼。
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("原始數(shù)據(jù):" + order); Document document = MongoDbUtils.obj2Doc(order); System.out.println("轉(zhuǎn)換doc數(shù)據(jù):" + document); Order order1 = MongoDbUtils.doc2Obj(document, Order.class); System.out.println("轉(zhuǎn)換java數(shù)據(jù):" + order1); } 運(yùn)行結(jié)果: 原始數(shù)據(jù):Order(id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3) 轉(zhuǎn)換doc數(shù)據(jù):Document{{id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3}} 轉(zhuǎn)換java數(shù)據(jù):Order(id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3)
這樣一來,我們就不用保留實(shí)體類上的轉(zhuǎn)換方法了,剩下的工作就是刪代碼。
MongoDb 和 Java 對(duì)象的互相轉(zhuǎn)換就完成了。我們做了兩次迭代,第一次迭代利用了反射,把大量手動(dòng) set/get 操作給去掉了;第二次迭代在原來的基礎(chǔ)上,加入了泛型的應(yīng)用,又去掉了一堆重復(fù)代碼。
感謝各位的閱讀!關(guān)于Java如何使用反射把對(duì)象轉(zhuǎn)換成MongoDb的結(jié)構(gòu)就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!