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

news2024/11/14 9:04:41

目录

前言

一、原始的处理办法

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.coloradmin.cn/o/2240063.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024版本IDEA创建Sprintboot项目下载依赖缓慢

目录 步骤一&#xff1a;在IDEA中搜索Maven(双击shift) 步骤二&#xff1a;找到Maven下的settings.xml文件修改镜像 ​编辑 ​编辑​编辑 步骤三&#xff1a;用VScode打开settings.xml文件修改镜像 ​编辑 步骤一&#xff1a;在IDEA中搜索Maven(双击shift) 步骤二&#xff…

【初阶数据结构与算法】链表刷题之移除链表元素、反转链表、找中间节点、合并有序链表、链表的回文结构

文章目录 一、移除链表元素思路一思路二 二、合并两个有序链表思路&#xff1a;优化&#xff1a; 三、反转链表思路一思路二 四、链表的中间节点思路一思路二 五、综合应用之链表的回文结构思路一&#xff1a;思路二&#xff1a; 一、移除链表元素 题目链接&#xff1a;https:…

三维测量与建模笔记 - 特征提取与匹配 - 4.1 梯度信息提取

上面说的“可关联性”&#xff0c;举一个例子&#xff0c;比如我们拍摄一个凹凸不平的金属表面&#xff0c;在某个角度拍的时候&#xff0c;从图像中可以看到这些凹凸不平的地方&#xff0c;但是换个角度&#xff08;或者光照发生变化&#xff09;拍就看不到了。这样的特征点就…

显示微服务间feign调用的日志

第一步 package com.niuniu.common.config;import com.niuniu.common.CommonConstant; import com.niuniu.common.utils.UserContext; import feign.Logger; import feign.RequestInterceptor; import feign.RequestTemplate; import org.springframework.context.annotation.…

读取文件内容、修改文件内容、识别文件夹目录(Web操作系统文件/文件夹详解)

前言 因 Unicode IDE 编辑器导入文件、文件夹需要&#xff0c;研究了下导入文件/文件夹的功能实现&#xff0c;发现目前相关文章有点少&#xff0c;故而记录下过程&#xff0c;如果有误&#xff0c;还望指正。(API的兼容性及相关属性、接口定义&#xff0c;请自行查看文件系统 …

「Mac玩转仓颉内测版2」入门篇2 - 编写第一个Cangjie程序

本篇详细介绍在Mac系统上创建首个Cangjie项目并编写、运行第一个Cangjie程序的全过程。内容涵盖项目创建、代码编写、程序运行与调试&#xff0c;以及代码修改后的重新运行。通过本篇&#xff0c;掌握Cangjie项目的基本操作&#xff0c;进一步巩固开发环境的配置&#xff0c;迈…

微信小程序_小程序视图与逻辑_day3

一、目标 A. 能够知道如何实现页面之间的导航跳转 B. 能够知道如何实现下拉刷新效果 C. 能够知道如何实现上拉加载更多效果 D. 能够知道小程序中常用的生命周期 二、目录 A. 页面导航 B. 页面事件 C. 生命周期 D. WXS脚本 E. 案例-本地生活&#xff08;列表页面&#xff09;…

Threejs 材质贴图、光照和投影详解

1. 材质和贴图 材质&#xff08;Material&#xff09;定义了物体表面的外观&#xff0c;包括颜色、光泽度、透明度等。贴图&#xff08;Textures&#xff09;是应用于材质的图像&#xff0c;它们可以增加物体表面的细节和真实感。 1.1材质类型 MeshBasicMaterial&#xff1a…

论文概览 |《Sustainable Cities and Society》2024.11 Vol.115(下)

本次给大家整理的是《Sustainable Cities and Society》杂志2024年11月第115期的论文的题目和摘要&#xff0c;一共包括76篇SCI论文&#xff01;由于论文过多&#xff0c;我们将通过两篇文章进行介绍&#xff0c;本篇文章介绍第31--第76篇论文! 论文31 The effect of urban fo…

【问卷调研】HarmonyOS SDK开发者社区用户需求有奖调研

问卷请点击&#xff1a;HarmonyOS SDK开发者社区用户需求有奖调研

【3D Slicer】的小白入门使用指南五

心脏CT多组织半自动分割(解说版) 模块勾选的是converters下的crop volume 右侧移动滑块+移动边框,移动位置找到自己关注的区域即可,然后点击apply(其他参数也要设置的和图片一致) 模块勾选segment editor,并创建心脏多个不同分割位置(默认下不同位置自动分配了不同的颜…

丹摩征文活动|FLUX.1 和 ComfyUI:从部署到上手,轻松驾驭!

FLUX.1 和 ComfyUI&#xff1a;从部署到上手&#xff0c;轻松驾驭&#xff01; FLUX.1历史曲线 黑森林实验室推出了一款名为FLUX.1的先进图像生成模型&#xff0c;根据不同用户需求&#xff0c;提供了三种独特的版本。 FLUX.1-pro&#xff1a;作为专为企业打造的强大闭源版本…

自动驾驶合集(更新中)

文章目录 车辆模型控制路径规划 车辆模型 车辆模型基础合集 控制 控制合集 路径规划 规划合集

string------1

文章目录 一. STL1.概念2.版本 二. string类2.1 为什么学习string类2. 标准库中的string类2.2.1 构造&#xff08;7个&#xff09;2.2.2 对string类对象进行“访问和修改”&#xff08;1&#xff09;operator[]&#xff08;2&#xff09;迭代器1.迭代器的使用2.迭代器的价值&am…

开源 2 + 1 链动模式、AI 智能名片、S2B2C 商城小程序在用户留存与品牌发展中的应用研究

摘要&#xff1a;本文以企业和个人品牌发展中至关重要的用户留存问题为切入点&#xff0c;结合管理大师彼得德鲁克对于企业兴旺发达的观点&#xff0c;阐述了用户留存对品牌营收的关键意义。在此基础上&#xff0c;深入分析开源 2 1 链动模式、AI 智能名片、S2B2C 商城小程序在…

蓝桥杯每日真题 - 第8天

题目&#xff1a;&#xff08;子2023&#xff09; 题目描述&#xff08;14届 C&C B组A题&#xff09; 解题思路&#xff1a; 该代码通过动态计算包含数字 "2023" 的子序列出现次数。主要思路是&#xff1a; 拼接序列&#xff1a;将1到2023的所有数字按顺序拆分…

Mac Nginx 前端打包部署

安装homebrew /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 安装Nginx brew install nginx nginx相关命令 nginx启动命令&#xff1a;nginx nginx -s reload #重新加载配置 nginx -s reopen #重启 nginx -s stop #…

小试银河麒麟系统OCR软件

0 前言 今天在国产电脑上办公&#xff0c;需要从一些PDF文件中复制文字内容&#xff0c;但是这些PDF文件是图片转换生成的&#xff0c;不支持文字选择和复制&#xff0c;除了手工输入&#xff0c;我们还可以使用OCR。 1 什么是OCR OCR &#xff08;Optical Character Recogni…

选择主动孤独,亦可以成长和放松

有的人热衷于喧嚣&#xff0c;享受来自社交场合的灯火辉煌&#xff0c;将欢声笑语作为心灵的慰藉。有的人则偏爱那份宁静&#xff0c;更愿意在青灯古巷间徘徊&#xff0c;在山川湖海间独行&#xff0c;以一杯茶、一卷书、一段旅程与自我对话。每个人以不同的方式诠释活着的意义…

Django 外键引用另一个表中的多个字段

在 Django 中&#xff0c;外键&#xff08;ForeignKey&#xff09;通常只引用另一张表的一个字段&#xff0c;比如一个主键或一个唯一标识字段。然而&#xff0c;如果我们需要让一个外键引用另一张表中的多个字段&#xff0c;通常有以下几种方法来实现这种关系。 1、问题背景 …