在Java中使用ModelMapper簡化Shapefile屬性轉(zhuǎn)JavaBean實戰(zhàn)過程
前言
在現(xiàn)代軟件開發(fā)中,尤其是在多層架構(gòu)中,經(jīng)常需要將數(shù)據(jù)從一個域?qū)ο筠D(zhuǎn)換到另一個域?qū)ο螅蛘邚臄?shù)據(jù)庫結(jié)果集轉(zhuǎn)換到業(yè)務(wù)對象。手動編寫這些轉(zhuǎn)換代碼不僅耗時,而且容易出錯。我們需要一種自動化的方式來處理這些轉(zhuǎn)換,減少了開發(fā)工作量和潛在的錯誤。JavaBean是一種遵循特定編寫規(guī)范的Java類,通常具有g(shù)et和set方法來訪問私有屬性,以及一個無參構(gòu)造函數(shù)。JavaBean是我們平時的開發(fā)過程當中遇到最多的類,不管它是DO、DTO、VO或者POJO等等,這些類都是以JavaBean的形式存在的。
在之前的系列博客中,尤其是涉及空間數(shù)據(jù)管理和查詢的后臺設(shè)計中。大家如果認真注意的話,我們分別在空間數(shù)據(jù)庫中創(chuàng)建一張與屬性字段對應(yīng)的空間表。而在采用MVC的開發(fā)模式中,模型層通常會對應(yīng)一個與空間表對應(yīng)的空間表。與成熟的ORM映射不同的是,ORM框架自動的會將數(shù)據(jù)庫中的字段快速得與JavaBean的屬性進行對應(yīng),在執(zhí)行查詢語句的時候可以直接關(guān)聯(lián)。但是在處理空間數(shù)據(jù)時,比如使用GDAL或者GeoTools來進行數(shù)據(jù)讀取時,目前暫時沒有找到成熟的框架或者組件支持空間屬性表與JavaBean的快速映射需求。
本文以Java語言為例,主要講解如何使用Java語言進行空間數(shù)據(jù)的讀取,空間屬性信息的讀取使用GeoTools,文章首先介紹最原始的做法,即在對象中自定義轉(zhuǎn)換方法來實現(xiàn)轉(zhuǎn)換,然后詳細介紹一種基于ModelMapper的空間屬性映射實現(xiàn)方法。ModelMapper在Java的其它領(lǐng)域應(yīng)用很多,但是在GIS領(lǐng)域中使用的還不多。如果您是一名GISER,同時也面臨著屬性信息映射的問題,不妨來這里交流討論。
一、原始的處理辦法
在介紹本文的處理辦法之前,首先依然來看一下最原始的處理辦法是什么。由此,可以對比不同的處理辦法的不同點,也可以發(fā)現(xiàn)其有點。關(guān)于如何讀取空間屬性信息,不管是使用GDAL或者GeoTools,不管是Gdb數(shù)據(jù)或者Shapefile數(shù)據(jù),之前的系列博客都進行了簡單的說明。因此想了解具體的讀取過程的,可以翻閱之前的博客。因此這里只將轉(zhuǎn)換的過程進行說明。
1、使用Set方法來轉(zhuǎn)換
首先來介紹調(diào)用對象實例的Set方法來進行轉(zhuǎn)換。這種情況使用與空間屬性表的字段不是很多,我們在轉(zhuǎn)換時可以先從空間屬性表中分別讀取出具體的字段,然后再調(diào)用對應(yīng)的JavaBea的Set方法來進行字段的映射和轉(zhuǎn)換。比如在進行省份的空間屬性信息轉(zhuǎn)換的代碼如下所示:
List<Province> list = new ArrayList<Province>(); for (int i = 0; i < featureCount; i++) { Feature feature = layer.GetFeature(i); String code = feature.GetFieldAsString("province_c"); String name = feature.GetFieldAsString("province_n"); String type = feature.GetFieldAsString("type"); Geometry geom = feature.GetGeometryRef(); String wkt = geom.ExportToWkt(); Province p = new Province(); p.setCode(code); p.setName(name); p.setType(type); p.setGeom(wkt); }
上面是一個使用GDAL解析空間數(shù)據(jù)時的屬性映射的實例代碼。 這種方式相信大家很熟悉,通過創(chuàng)建Province對象后,再分別從feature中讀取省份信息,最后設(shè)置到實例對象中,最后再保存到數(shù)據(jù)庫中。
2、使用構(gòu)造方法轉(zhuǎn)換
除了使用set方法來進行設(shè)置,我們也可以使用構(gòu)造方法來進行屬性賦值。與set方法相比,構(gòu)造方法可以統(tǒng)一設(shè)置,不需逐行進行設(shè)置。這樣代碼顯得比較優(yōu)雅,可讀性也高。構(gòu)造方法是將屬性賦值的過程抽象都對象的構(gòu)造方法中,這樣實現(xiàn)代碼的整體復用。這里以城市對象構(gòu)造方法為例:
public City(String provinceCode, String provinceName, String cityCode, String cityName, String type, String geom) { super(); this.provinceCode = provinceCode; this.provinceName = provinceName; this.cityCode = cityCode; this.cityName = cityName; this.type = type; this.geom = geom; }
然后在解析的過程中就可以直接調(diào)用構(gòu)造方法的模式簡化設(shè)置的過程,代碼如下:
List<City> list = new ArrayList<City>(); for (int i = 0; i < featureCount; i++) { Feature feature = layer.GetFeature(i); String code = feature.GetFieldAsString("province_c"); String name = feature.GetFieldAsString("province_n"); String cityCode = feature.GetFieldAsString("city_code"); String cityName = feature.GetFieldAsString("city_name"); String type = feature.GetFieldAsString("type"); Geometry geom = feature.GetGeometryRef(); String wkt = geom.ExportToWkt(); list.add(new City(code,name,cityCode,cityName,type,wkt)); } cityService.saveBatch(list,100);
可以從代碼中看到,通過構(gòu)造方法的方式來進行賦值,能極大的減少set方法的調(diào)用,能減少許多的代碼調(diào)用??梢钥吹剑还苁褂媚姆N方式,我們都需要有一個從feature中根據(jù)屬性名解析字段,不得不說,這種方式于我們最開始學JDBC的模式非常相似,那么有什么辦法實現(xiàn)動態(tài)映射,不需要單獨讀取呢?下面我們就來分享一種方法來進行轉(zhuǎn)換。
二、基于ModelMapper的動態(tài)轉(zhuǎn)換
既然有了如上的需求場景,那么有什么方法可以實現(xiàn)快速的屬性映射嗎?在Java當中,很多人首選肯定是采用反射,對吧。確實如此,使用反射可以解決我們的問題,實現(xiàn)上述的需求。對于反射,相信很多的朋友可以自行進行編碼。本著不重復造輪子的思路,我們可以從現(xiàn)有的一些成熟工具中來選擇符合我們期望的組件。這里推薦一款轉(zhuǎn)換組件,ModelMapper。
1、ModelMapper簡介
ModelMapper是一個Java對象映射庫,它能夠?qū)⒁粋€對象的數(shù)據(jù)映射到另一個對象中,從而避免手動編寫數(shù)據(jù)轉(zhuǎn)換代碼。ModelMapper通過使用簡單的配置和API,能夠自動地將源對象的屬性復制到目標對象的屬性中,這在處理不同數(shù)據(jù)層之間的數(shù)據(jù)轉(zhuǎn)換時非常有用。ModelMapper簡化了開發(fā)流程,因為它減少了手動編寫數(shù)據(jù)轉(zhuǎn)換代碼的需要。這不僅提高了開發(fā)效率,還使得代碼更加簡潔和易于維護。通過使用ModelMapper,開發(fā)者可以將更多的精力投入到業(yè)務(wù)邏輯的實現(xiàn)上,而不是數(shù)據(jù)轉(zhuǎn)換的細節(jié)上。ModelMapper提供了高度的靈活性和可配置性。開發(fā)者可以根據(jù)需要自定義映射規(guī)則,例如跳過某些屬性的映射,或者在映射過程中進行條件判斷和自定義轉(zhuǎn)換。這種靈活性使得ModelMapper能夠適應(yīng)各種復雜的數(shù)據(jù)轉(zhuǎn)換場景。
首先,我們來看一下ModelMapper的官網(wǎng)介紹,modelmapper官網(wǎng)。大家可以先到官網(wǎng)看一下它的相關(guān)介紹可幫助文檔。
2、集成到項目中
對ModelMapper有了基本的了解之后,我們來看一下如何將ModelMapper集成到Java項目當中。首先我們需要使用Maven來進行資源的引入,在Pom.xml中引入依賴,關(guān)鍵代碼如下所示:
<!-- 增加模型映射 add by 夜郎king in 2024.11.11 begin --> <!-- https://mvnrepository.com/artifact/org.modelmapper/modelmapper --> <dependency> <groupId>org.modelmapper</groupId> <artifactId>modelmapper</artifactId> <version>3.1.1</version> </dependency> <!-- modelmapper add by 夜郎king in 2024.11.11 end -->
然后在Java中進行相應(yīng)的集成,雖然ModelMapper本身主要作用是用于JavaBean之間的轉(zhuǎn)換,但是也可以在Map和JavaBean之間進行屬性映射。
@Test public void convertMap2BeanWithUnderscoreNamingConvention() { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("scalerank", 6); map.put("LS_NAME", "test241111"); map.put("MAX_POP10", "23562"); ModelMapper modelMapper = new ModelMapper(); Ne10mPopulatedPlaces pp = modelMapper.map(map, Ne10mPopulatedPlaces.class); System.out.println(pp); System.out.println(pp.getLsName()); System.out.println(pp.getMaxPop10()); assertEquals("test241111", pp.getLsName()); assertEquals(23562L, pp.getMaxPop10()); }
代碼很簡單,首先定義一個HashMap,map的key是屬性的名字,value是實際的值。然后我們創(chuàng)建ModelMapper,使用默認的轉(zhuǎn)換策略和匹配模式,在這種策略下實現(xiàn)Map向Ne10mPopulatedPlaces對象的轉(zhuǎn)換。Ne10mPopulatedPlaces對象就是之前提到過的人口城市空間屬性數(shù)據(jù)。
這個類的屬性比較對,大概有137個屬性。針對這么多的屬性映射,不管是采用set方法還是構(gòu)造方法,實現(xiàn)代碼都會非常冗長。運行上面的測試方法后,可以看到如下結(jié)果:
3、Shapefile屬性讀取
有了以上的基礎(chǔ),結(jié)合之前的GeoTools的屬性讀取方法,我們來解析屬性表格。解析的思路很簡單,循環(huán)屬性表格,將屬性表列和值組成一個HashMap,表頭為key,值為value的hashMap,然后將這個HashMap轉(zhuǎn)換成對應(yīng)的JavaBean對象。
@Test public void convertDbf2BeanByDefault() throws Exception { File dbfFile = new File(SHP_FILE); ShpFiles shpFile = new ShpFiles(dbfFile); DbaseFileReader dbfReader = new DbaseFileReader(shpFile, true, Charset.defaultCharset()); // 讀取 DBF 文件的頭信息 DbaseFileHeader header = dbfReader.getHeader(); List<Ne10mPopulatedPlaces> dataList = new ArrayList<Ne10mPopulatedPlaces>(header.getNumRecords()); List<HashMap<String, Object>> mapList = new ArrayList<HashMap<String,Object>>(); ModelMapper modelMapper = new ModelMapper(); while (dbfReader.hasNext()) { Row row = dbfReader.readRow(); HashMap<String, Object> map = new HashMap<String, Object>(); for (int i = 0; i < header.getNumFields(); i++) { map.put(header.getFieldName(i), row.read(i)); } mapList.add(map); } int index = 0; for(HashMap<String, Object> map : mapList) { if(index > 10) { break; } Ne10mPopulatedPlaces places = modelMapper.map(map, Ne10mPopulatedPlaces.class); System.out.println(places); dataList.add(places); index ++; } System.out.println(dataList.size()); System.out.println("屬性字段數(shù):" + header.getNumFields()); System.out.println("數(shù)據(jù)記錄數(shù):" + header.getNumRecords()); dbfReader.close(); }
也是默認的映射策略和模式,通過上述的代碼可以看到以下輸出:
可以看到, 通過以上的代碼已經(jīng)成功的實現(xiàn)把HashMap轉(zhuǎn)換成JavaBean,同時可以看到JavaBean的屬性值都成功的進行了賦值。到此,大功告成。
三、總結(jié)
以上就是本文的主要內(nèi)容,本文以Java語言為例,主要講解如何使用Java語言進行空間數(shù)據(jù)的讀取,空間屬性信息的讀取使用GeoTools,文章首先介紹最原始的做法,即在對象中自定義轉(zhuǎn)換方法來實現(xiàn)轉(zhuǎn)換,然后詳細介紹一種基于ModelMapper的空間屬性映射實現(xiàn)方法。ModelMapper在Java的其它領(lǐng)域應(yīng)用很多,但是在GIS領(lǐng)域中使用的還不多。本文基于ModelMapper解決了在Shapefile文件讀取過程中,如何實現(xiàn)動態(tài)的將屬性表格映射到指定對象的方法進行了詳細介紹。如果您是一名GISER,同時也面臨著屬性信息映射的問題,不妨來這里交流討論。行文倉促,難免有許多不足之處,如有不足,還請各位專家朋友在評論區(qū)留言批評指正,不甚感激。
到此這篇關(guān)于在Java中使用ModelMapper簡化Shapefile屬性轉(zhuǎn)JavaBean實戰(zhàn)的文章就介紹到這了,更多相關(guān)Java轉(zhuǎn)JavaBean內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring data elasticsearch使用方法詳解
這篇文章主要介紹了Spring data elasticsearch使用方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-01-01Spring MVC結(jié)合Spring Data JPA實現(xiàn)按條件查詢和分頁
這篇文章主要為大家詳細介紹了Spring MVC結(jié)合Spring Data JPA實現(xiàn)按條件查詢,以及分頁效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10Assert.assertEquals的使用方法及注意事項說明
這篇文章主要介紹了Assert.assertEquals的使用方法及注意事項說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05如何使用spring?boot的程序主線程中異步訪問外部接口
CompletableFuture.supplyAsync提供了一種強大的工具,使您能夠以異步方式執(zhí)行操作,充分利用多核處理器和提高程序性能,同時保持代碼的清晰性和可維護性,本文給大家介紹使用spring?boot的程序主線程中異步訪問外部接口,感興趣的朋友一起看看吧2023-10-10java之CSV大批量數(shù)據(jù)入庫的實現(xiàn)
本文主要介紹了java之CSV大批量數(shù)據(jù)入庫的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-02-02