在Java中使用ModelMapper简化Shapefile属性转JavaBean实战

目录

前言

一、原始的处理办法

1、使用Set方法来转换

2、使用构造方法转换

二、基于ModelMapper的动态转换

1、ModelMapper简介

2、集成到项目中

3、Shapefile属性读取 

三、总结


前言

        在现代软件开发中,尤其是在多层架构中,经常需要将数据从一个域对象转换到另一个域对象,或者从数据库结果集转换到业务对象。手动编写这些转换代码不仅耗时,而且容易出错。我们需要一种自动化的方式来处理这些转换,减少了开发工作量和潜在的错误。JavaBean是一种遵循特定编写规范的Java类,通常具有get和set方法来访问私有属性,以及一个无参构造函数。JavaBean是我们平时的开发过程当中遇到最多的类,不管它是DO、DTO、VO或者POJO等等,这些类都是以JavaBean的形式存在的。

        在之前的系列博客中,尤其是涉及空间数据管理和查询的后台设计中。大家如果认真注意的话,我们分别在空间数据库中创建一张与属性字段对应的空间表。而在采用MVC的开发模式中,模型层通常会对应一个与空间表对应的空间表。与成熟的ORM映射不同的是,ORM框架自动的会将数据库中的字段快速得与JavaBean的属性进行对应,在执行查询语句的时候可以直接关联。但是在处理空间数据时,比如使用GDAL或者GeoTools来进行数据读取时,目前暂时没有找到成熟的框架或者组件支持空间属性表与JavaBean的快速映射需求。

        本文以Java语言为例,主要讲解如何使用Java语言进行空间数据的读取,空间属性信息的读取使用GeoTools,文章首先介绍最原始的做法,即在对象中自定义转换方法来实现转换,然后详细介绍一种基于ModelMapper的空间属性映射实现方法。ModelMapper在Java的其它领域应用很多,但是在GIS领域中使用的还不多。如果您是一名GISER,同时也面临着属性信息映射的问题,不妨来这里交流讨论。

一、原始的处理办法

        在介绍本文的处理办法之前,首先依然来看一下最原始的处理办法是什么。由此,可以对比不同的处理办法的不同点,也可以发现其有点。关于如何读取空间属性信息,不管是使用GDAL或者GeoTools,不管是Gdb数据或者Shapefile数据,之前的系列博客都进行了简单的说明。因此想了解具体的读取过程的,可以翻阅之前的博客。因此这里只将转换的过程进行说明。

1、使用Set方法来转换

        首先来介绍调用对象实例的Set方法来进行转换。这种情况使用与空间属性表的字段不是很多,我们在转换时可以先从空间属性表中分别读取出具体的字段,然后再调用对应的JavaBea的Set方法来进行字段的映射和转换。比如在进行省份的空间属性信息转换的代码如下所示:

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解析空间数据时的属性映射的实例代码。 这种方式相信大家很熟悉,通过创建Province对象后,再分别从feature中读取省份信息,最后设置到实例对象中,最后再保存到数据库中。

2、使用构造方法转换

        除了使用set方法来进行设置,我们也可以使用构造方法来进行属性赋值。与set方法相比,构造方法可以统一设置,不需逐行进行设置。这样代码显得比较优雅,可读性也高。构造方法是将属性赋值的过程抽象都对象的构造方法中,这样实现代码的整体复用。这里以城市对象构造方法为例:

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

        然后在解析的过程中就可以直接调用构造方法的模式简化设置的过程,代码如下:

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

        可以从代码中看到,通过构造方法的方式来进行赋值,能极大的减少set方法的调用,能减少许多的代码调用。可以看到,不管使用哪种方式,我们都需要有一个从feature中根据属性名解析字段,不得不说,这种方式于我们最开始学JDBC的模式非常相似,那么有什么办法实现动态映射,不需要单独读取呢?下面我们就来分享一种方法来进行转换。

二、基于ModelMapper的动态转换

        既然有了如上的需求场景,那么有什么方法可以实现快速的属性映射吗?在Java当中,很多人首选肯定是采用反射,对吧。确实如此,使用反射可以解决我们的问题,实现上述的需求。对于反射,相信很多的朋友可以自行进行编码。本着不重复造轮子的思路,我们可以从现有的一些成熟工具中来选择符合我们期望的组件。这里推荐一款转换组件,ModelMapper。

1、ModelMapper简介

        ModelMapper是一个Java对象映射库,它能够将一个对象的数据映射到另一个对象中,从而避免手动编写数据转换代码。ModelMapper通过使用简单的配置和API,能够自动地将源对象的属性复制到目标对象的属性中,这在处理不同数据层之间的数据转换时非常有用。ModelMapper简化了开发流程,因为它减少了手动编写数据转换代码的需要。这不仅提高了开发效率,还使得代码更加简洁和易于维护。通过使用ModelMapper,开发者可以将更多的精力投入到业务逻辑的实现上,而不是数据转换的细节上。ModelMapper提供了高度的灵活性和可配置性。开发者可以根据需要自定义映射规则,例如跳过某些属性的映射,或者在映射过程中进行条件判断和自定义转换。这种灵活性使得ModelMapper能够适应各种复杂的数据转换场景。

        首先,我们来看一下ModelMapper的官网介绍,modelmapper官网。大家可以先到官网看一下它的相关介绍可帮助文档。

2、集成到项目中

        对ModelMapper有了基本的了解之后,我们来看一下如何将ModelMapper集成到Java项目当中。首先我们需要使用Maven来进行资源的引入,在Pom.xml中引入依赖,关键代码如下所示:

<!--  增加模型映射 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中进行相应的集成,虽然ModelMapper本身主要作用是用于JavaBean之间的转换,但是也可以在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是实际的值。然后我们创建ModelMapper,使用默认的转换策略和匹配模式,在这种策略下实现Map向Ne10mPopulatedPlaces对象的转换。Ne10mPopulatedPlaces对象就是之前提到过的人口城市空间属性数据。

        这个类的属性比较对,大概有137个属性。针对这么多的属性映射,不管是采用set方法还是构造方法,实现代码都会非常冗长。运行上面的测试方法后,可以看到如下结果:

3、Shapefile属性读取 

        有了以上的基础,结合之前的GeoTools的属性读取方法,我们来解析属性表格。解析的思路很简单,循环属性表格,将属性表列和值组成一个HashMap,表头为key,值为value的hashMap,然后将这个HashMap转换成对应的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("属性字段数:" + header.getNumFields());System.out.println("数据记录数:" + header.getNumRecords());dbfReader.close();
}

        也是默认的映射策略和模式,通过上述的代码可以看到以下输出:

        可以看到, 通过以上的代码已经成功的实现把HashMap转换成JavaBean,同时可以看到JavaBean的属性值都成功的进行了赋值。到此,大功告成。

三、总结

        以上就是本文的主要内容,本文以Java语言为例,主要讲解如何使用Java语言进行空间数据的读取,空间属性信息的读取使用GeoTools,文章首先介绍最原始的做法,即在对象中自定义转换方法来实现转换,然后详细介绍一种基于ModelMapper的空间属性映射实现方法。ModelMapper在Java的其它领域应用很多,但是在GIS领域中使用的还不多。本文基于ModelMapper解决了在Shapefile文件读取过程中,如何实现动态的将属性表格映射到指定对象的方法进行了详细介绍。如果您是一名GISER,同时也面临着属性信息映射的问题,不妨来这里交流讨论。行文仓促,难免有许多不足之处,如有不足,还请各位专家朋友在评论区留言批评指正,不甚感激。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/470780.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

时间管理的三个痛点

时间管理方面&#xff0c;有三个痛点&#xff1a;不知道、不平衡、不安全。 很多人&#xff0c;忙了一天&#xff0c;感觉很累&#xff0c;但是不知道做了什么。他不知道&#xff0c;这一天工作了几个小时&#xff0c;做了哪些事&#xff0c;分别用了多少时间&#xff0c;只是…

封装el-menu

案例图 数据格式 commonMenu.vue <template><div class"commonMenuStyle"><el-sub-menu v-if"hasChildren" :index"item.MenuId"><template #title><el-icon><location /></el-icon><!-- isColl…

微服务day07

Elasticsearch 需要安装elasticsearch和Kibana&#xff0c;应为Kibana中有一套控制台可以方便的进行操作。 安装elasticsearch 使用docker命令安装&#xff1a; docker run -d \ --name es \-e "ES_JAVA_OPTS-Xms512m -Xmx512m" \ //设置他的运行内存空间&#x…

假期增设:福祉与负担并存,寻求生活经济平衡之道

近年来&#xff0c;关于春节与五一假期各自增设一日的议题持续引发广泛热议。这一额外假期的增设&#xff0c;究竟是民众福祉的增益&#xff0c;还是社会运行的额外负担&#xff0c;值得我们深入探讨。 从宏观经济视角审视&#xff0c;假期的延长产生了复杂而深远的影响。一方面…

结构体(c语言)

一.结构体 1.结构的基础知识 结构是一些值得集合&#xff0c;这些值称为成员变量&#xff0c;结构得每个成员可以是不同类型的变量 2.结构体的声明 struct tag//结构体名称{member-list;//成员变量}variable-list;//全局变量 例&#xff1a;描述一个学生 struct Stu {int a…

GIS空间分析案例---城市公共设施配置与服务评价

今天给大家带来新的GIS案例分析——“城市公共设施配置与服务评价” 数据准备 本案例提供的数据资料如下&#xff1a; 武汉城区.shp&#xff1a;武汉市三环城区范围面要素&#xff1b; 武汉城区&#xff08;去除水系&#xff09;.shp&#xff1a;去除水系后的研究区范围面要…

如何在算家云搭建Peach-9B-8k-Roleplay(文本生成)

一、Peach-9B-8k-Roleplay简介 Peach-9B-8k-Roleplay 是一种聊天大型语言模型&#xff0c;它是通过我们的数据合成方法创建的超过 100K 的对话中微调 01-ai/Yi-1.5-9B 模型而获得的。 也许是 34B 以下参数最好的 LLM。 二、模型搭建流程 1. 创建容器镜像 进入算家云平台的“…

软件工程概论项目(二),node.js的配置,npm的使用与vue的安装

上一章我们配置了git仓库&#xff0c;这一章我们来配置项目需要用的一些其他的环境。 放一个思维导图在这里&#xff0c;可以参考一下&#xff0c;很不全面&#xff0c;没有参考价值,反正我先这样写吧。 参考了这个nodejs的配置&#xff0c;写的很好&#xff1a;https://blog.c…

Android中桌面小部件的开发流程及常见问题和解决方案

在Android中&#xff0c;桌面小部件&#xff08;App Widget&#xff09;是应用程序可以在主屏幕或其他地方显示的一个可视化组件&#xff0c;提供简化信息和交互功能。Android桌面小部件的framework为开发者提供了接口&#xff0c;使得可以创建和更新小部件的内容。以下是Andro…

JAVA题目笔记(十五)经典算法题

一、按要求排序 要求&#xff1a;定义数组并存储一些女朋友对象&#xff0c;利用Arrays中的sort方法进行排序 属性包括&#xff1a;姓名&#xff0c;年龄&#xff0c;身高 按照年龄大小进行排序&#xff0c;年龄一样按照身高排序&#xff0c;身高一样按照姓名字母进行排序。…

【JVM】关于JVM的内部原理你到底了解多少(八股文面经知识点)

前言 &#x1f31f;&#x1f31f;本期讲解关于HTTPS的重要的加密原理~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不…

【Pikachu】目录遍历实战

既然已经决定做一件事&#xff0c;那么除了当初决定做这件事的我之外&#xff0c;没人可以叫我傻瓜。 1.目录遍历漏洞概述 目录遍历漏洞概述 在Web功能的设计过程中&#xff0c;开发者经常会将需要访问的文件作为变量进行定义&#xff0c;以实现前端功能的灵活性。当用户发起…

如何用C#和Aspose.PDF实现PDF转Word工具

在本篇博文中&#xff0c;我将详细讲解如何用C#实现一个PDF转Word工具。这款工具基于Aspose.PDF库&#xff0c;实现PDF文件转为Word&#xff08;DOC/DOCX&#xff09;格式的功能&#xff0c;并通过用户友好的界面和状态提示提升用户体验。希望通过这篇文章帮助大家理解软件的实…

【图像压缩感知】论文阅读:Self-supervised Scalable Deep Compressed Sensing

tips&#xff1a;本文为个人阅读论文的笔记&#xff0c;仅作为学习记录所用。 Title&#xff1a;Self-supervised Scalable Deep Compressed Sensing Journal&#xff1a;IJCV 2024 代码链接&#xff1a;GitHub - Guaishou74851/SCNet: Self-Supervised Scalable Deep Comp…

使用elementUI实现表格行拖拽改变顺序,无需引入外部库

前言&#xff1a; 使用vue2element UI&#xff0c;且完全使用原生的拖拽事件,无需引入外部库。 如果表格数据量较大&#xff0c;或需要更多复杂功能&#xff0c;可以考虑使用 vuedraggable库&#xff0c;提供更多配置选项和拖拽功能。 思路&#xff1a; 1. 通过el-table的ro…

深入理解接口测试:实用指南与最佳实践5.0(三)

✨博客主页&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客内容》&#xff1a;.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 &#x1f4e2;博客专栏&#xff1a; https://blog.csdn.net/m0_63815035/cat…

32位、64位、x86与x64:深入解析计算机架构

目录 一、32位架构(x86) 1.1 定义与历史 1.2 技术特点 1.3 优缺点 二、64位架构(x64) 2.1 定义与历史 2.2 技术特点 2.3 优缺点 三、x86与x64的关系 四、应用场景 4.1 32位架构的应用场景 4.2 64位架构的应用场景 五、总结 在计算机领域中,处理器架构的选择对…

【stable diffusion部署】超强AI绘画Stable Diffusion,本地部署使用教程,完全免费使用

前言 01 软件介绍 Stable Diffusion和Midjourney类似&#xff0c;都是当下AI绘画最流行的AI工具之一&#xff0c;都支持用文字生成AI图片或者图片生成图片的软件。 二者的区别是&#xff1a;Midjourney只能在网上使用&#xff0c;国内需要魔法才能使用&#xff0c;而且存在使…

【计算机网络】【网络层】【习题】

计算机网络-传输层-习题 文章目录 13. 图 4-69 给出了距离-向量协议工作过程&#xff0c;表&#xff08;a&#xff09;是路由表 R1 初始的路由表&#xff0c;表&#xff08;b&#xff09;是相邻路由器 R2 传送来的路由表。请写出 R1 更新后的路由表&#xff08;c&#xff09;。…

【嵌入式开发】单片机CAN配置详解

0 前言 CAN外设作为一种传输速率较高&#xff0c;且连线较为简洁的通信协议&#xff0c;如今很多单片机内部都集成了CAN控制模块&#xff0c;这样只需要再外接一个CAN收发芯片&#xff0c;将TTL/CMOS电平转换成CAN协议的差分电平&#xff0c;就是一个完整的CAN收发节点。   最…