基于SpringBoot的GIS可视化系统的设计与构建

2024-06-16 12:30陈刚
电脑知识与技术 2024年12期

陈刚

关键词:SpringBoot;Java反射解耦;Python模型;Mars3D框架;Ajax异步通信

0 引言

现状:目前,全国各地水库系统的信息化程度参差不齐,尽管所有系统的安全级别均较高,且必须在获得授权的情况下离线完成系统部署,甚至不允许随意调试。一些水库的数据存储在基于XML格式的古老WebService中,而另一些则建立了数据中心平台,需要通过调用平台API来获取数据。还有的水库引入了Kafka技术,须建立Kafka消费端以获取数据。因此,不同的生产环境对开发的需求各异,这部分开发要求能独立于整个项目之外,同时又能与原有项目互相整合调用,这就要求设计出一个低耦合的系统调用架构,以实现在不同生产环境下的开发。

已有项目:现存的已有项目采用了SpringBoot+MySQL+JPA+Thymeleaf+Bootstrap的技术选型,这是一个前后端不分离的项目,要求在此基础上扩展功能以适配不同的水库生产环境。这个前提使得项目不能重新开始,需要在原有项目中进行拆解和分割,既要保证开发进度,又能将功能模块独立出来,这是一个关键点。需求:新的需求要求能够在任意生产环境下获取水库数据;新增GIS可视化系统;新增新水库的AI模型(Python程序)。

难点及关键技术:

1) Java调用独立jar包,以实现数据的抽取并持久化到数据库。

2) Java调用Python编写的模型算法,以获得结果并绘制可视化图形。

3) 将基于Vue 的Mars3D 开源GIS 框架整合到SpringBoot中。

1 开发框架简介

SpringBoot:SpringBoot 是一种后端框架,它采用特定的配置方式,并通过内嵌的Tomcat服务器,直接将项目打包成jar 包,从而简化项目的部署工作[1]。SpringBoot框架采用MVC三层结构,其中MVC包括3 个模块:模型层(Model) 、视图层(View) 、控制层(Con?troller) [2]。此外,通过配置Maven工具来管理大量的项目资源,可以有效解决项目资源管理的问题。

Thymeleaf:Thymeleaf 是一个面向Web 服务器端的现代化Java模板引擎。与传统的Java模板引擎不同,Thymeleaf可以直接被浏览器加载,以展示静态页面效果。当通过Web应用程序访问时,Thymeleaf会根据对应的标签属性进行动态渲染。SpringBoot推荐使用Thymeleaf作为模板引擎[3]。

Python:Python是一种面向对象的解释型语言,具有动态数据类型特性。它是一种高级通用编程语言,相比其他语言,Python更便于实现原型开发。

Vue3:Vue是一款由国内开发者尤雨溪研发的用于搭建用户界面的框架。Vue采用自底向上增量开发的设计方式,提供了丰富的组件库,支持独立开发。结合使用Vue生态系统支持的库和单文件组件,Vue 可以为复杂的单页应用程序提供支持[4]。此外,通过Vue,前端更便于调用第三方工具(如Web API) 。

此外,开发过程中还使用到了MySQL、SpringData JPA、Bootstrap、WebService、PostgreSQL等技术。

2 技术选型

本次项目开发采用前后端一体化开发,并配合使用Ajax 技术,其技术选型包括:SpringBoot、MySQL、Spring Data JPA、Thymeleaf、Bootstrap、Vue和Mars3D。

2.1 为什么不选择前后端分离

2.1.1 基于旧项目上新增功能

选择前后端分离的优势在于前后端可以相互独立开发,只需要在接口规范上做到统一就可以加速开发过程。然而,这种方式适合新项目的全新设计,不适合旧项目的改造。在现有的前后端不分离的项目中增加新功能时,既要保证开发进度,又要做到尽可能低耦合的设计。在代码重构的环节,应该采用敏捷开发的思路,逐渐向解耦的方向演化。

2.1.2 服务器资源限制

服务器的资源分配是按照单个项目进行的,如果改为前后端分离,就需要在原有MySQL服务和Spring?Boot服务的基础上开启NginX长期服务。

2.1.3 项目进度约束

项目进度是一个重要的限制因素。从前后端不分离的模式转变为分离模式,将涉及整个设计的变动和大量的代码修改,这可能导致项目完成的预期时间难以预测。

2.2 为什么不使用Python+Flask 选型

与上述2.1.2点类似,尽管Python+Flask能独立启动Web服务并长期占用Web资源,但实际上调用模型算法的频率较低,多数情况下是按需调用。因此,为了优化资源利用,选择按需调用而非常驻Web服务的方案。

2.3 为什么要调用独立Jar 实现数据抽取

鉴于不同水库的信息化程度各不相同,数据存储方式也有所差异,因此面对不同的水库需要进行单独开发。这种开发方式不会影响原有项目,相对较为独立。因此,可以采用独立的jar程序来获取数据,并将其存储在原有项目的数据库中。在实际开发中,会采用反射机制,并在原有项目中设计好接口,以实现主动调用独立jar(或class) 进行数据传递。

3 架构设计分析

3.1 反射解耦原理与实践

3.1.1 原理

在面对不同的数据获取环境时,编写独立的jar 程序进行数据抽取,这样可以实现独立开发,而不会影响到原有项目的代码。然而,在调用这些jar程序时,需要一个通用的解决方案来实现对不同jar程序的调用。这就要求每个数据抽取程序设计出相同的调用方法和参数。根据设计模式原则中的“依赖倒置原则”(面向接口而不是具体实现),虽然没有直接使用接口类型,但在反射机制的实践中,动态调用类方法可以被理解为面向接口。例如,定义如下类结构:package com.p1; class App{public void run(){}}。每个数据抽取程序被划分到不同的包中,它们具有相同的类名和方法,但内部实现逻辑完全不同。

为了能够在运行时加载每个独立的数据抽取程序(既可以是jar文件,也可以是class文件),这里以class为例,通过Class.forName“( 包名.类名”)的方式加载class。如果加载成功就执行,加载失败则通过异常捕获顺序加载下一个。由于加载class时输入的包名和类名属于字符串,更容易提炼为参数,甚至可以把包名和类名作为数据库中的配置项通过DAO层获取,从而实现彻底解耦。这样,新的数据抽取程序加入时,完全不需要修改任何主程序代码,而只需要在数据库中配置全限定名即可。

3.1.2 实践

已知的数据获取方式包括:从WebService 获取XML 格式数据、从数据中心平台API 获取数据、从PostgreSQL数据库获取数据、从Kafka消费端获取数据以及从Excel文件中获取数据等。

对于从WebService获取XML格式数据的情况,借助JDK自带的工具wsimport生成WebService客户端,将功能调用代码放入com.core.extract.webservice.Cli?ent类中。部分代码参考如下:

3.2 系统结构功能设计

在设计整个系统时,重点放在功能的独立性和耦合性上,旨在减少各功能模块之间的依赖程度,确保系统的易维护性和可扩展性。因此,系统被划分为以下几个关键模块:

1) 数据抽取模块:负责获得实时数据。

2) 数据导出模块:处理数据计算结果,生成数据报表,并负责数据的导出等功能。

3) 数据处理模块:作为系统的核心模块,它是主要的交互区域。

通过这种模块化的设计,系统的结构变得清晰,每个模块的职责明确,便于未来根据需求进行相应的功能扩展或调整。

首先,数据抽取模块构成了系统运行的基础部分,其主要职责是从生产环境中获取实时数据。该模块与各种数据库、平台接口、Kafka服务等数据源建立连接,定时或实时抽取所需数据,并将其传输到系统内部的MySQL数据库表中,为后续的数据处理和导出提供数据基础。数据抽取模块包括:WebService、平台API、Kafka、PostgreSQL、Excel及其他数据源。

其次,数据导出模块负责将数据处理结果以多种形式导出,包括数据报表、数据文件、报警平台消息推送等。该模块提供了丰富的导出选项,以满足不同用户的需求,并保证了数据的灵活性和可扩展性。目前,数据导出模块包括:推送平台API、报警平台、Ex?cel和报表。

最后,数据处理模块是整个系统的核心模块,也是用户使用频率最高的功能区域。该模块提供了实时预报、历史预报、洪水归档、模型调用、可视化呈现、Echarts、GIS等功能。

3.3 项目模块组织代码

原项目为单个Module实现,内部包含MVC三层结构。然而,新增的功能中包含相对独立的GIS可视化系统,主要用于地理信息呈现。因此,可以将GIS前端及其交互的控制器层剥离成为独立的Module。代码组织的逻辑是横向切分子系统,纵向切分代码调用层次。因此,原项目被重构为包含若干Module的大项目,分为核心功能模块群(由多个纵向切割的模块,例如控制器层、域对象层、数据访问层等)和独立模块(横向切割,模块内部包含MVC三层结构,形成若干相对独立的子系统模块)。

3.4 系统与Python 模型对接设计

使用Python语言,通过构建LSTM模型,形成适应某水库流域特点的智能洪水预报方案。该方案采用历史洪水数据进行模拟预报,以检验预报方案的效果。同时,利用气象水文耦合技术,对未来水库入库洪水过程进行实时滚动预报。为实现Java与Python 的混合编程,特别是将Java 作为主控语言,需要在Java程序中以某种方式访问Python脚本代码[5]。Java 程序通过其命令行函数执行Python命令,以高效获取数据,而Python执行的结果则通过Java对象直接获取并返回给控制器。

// 为了消除硬编码,下面采用了变量,cmd[]数组中的元素分别是命令行的命令和参数,元素之间是空格分隔符

此时,变量text保存了模型运算的结果,并在内存中直接由控制器返回给前端,用于绘制可视化图形。这种调用方式使得数据无须落地,可直接调用,并将运算结果直接返回。

3.5 系统与GIS 纯前端项目对接设计

前端采用Mars3D 开源框架实现快速开发。Mars3D基于Vue3+Vite构建,属于纯前端项目。在与SpringBoot项目对接时,需要使用异步通信(Mars3D框架内置Axios) ,这要求后端提供JSON 格式的、遵循REST风格的控制器接口。然而,原项目使用Thyme?leaf引擎渲染HTML文件,控制器采用@Controller 注解,方法返回视图名称。因此,在对接过程中,需要创建专门针对GIS的控制器,并使用SpringBoot的@Rest?Controller注解。

关键操作包括在后端部署以确保能正常运行。前端使用命令“npm run build”进行打包,随后将打包得到的dist目录下的文件复制到后端的static目录中。需要注意的是,static目录默认位于SpringBoot项目内部,在将SpringBoot项目打包成jar文件时,static目录会被一同打包。如果static 目录中的文件内容有变动,须重新打包。为便于部署,可以通过添加额外配置使static目录从SpringBoot项目中独立出来,这样就无须因静态资源的变化而重新打包。要使SpringBoot 引用外部资源,可在SpringBoot 的默认application.properties文件中添加关键代码:

# 实际路径根据实际情况修改

spring. web. resources. static-locations=file: D:/re?sources/static

4 结束语

随着信息技术的快速发展,集成多语言和多框架的开发已成为跨专业和跨领域合作的主要趋势。本项目建立在现有系统的基础上,分析了新的需求,明确了项目开发的难点和关键技术,提出了符合项目实际需求的架构设计,并在新架构中实现了各个模块的解耦和集成。特别是,使用反射机制极大地减少了项目功能间的依赖关系,实现了功能动态加载的灵活性设计。

项目开发的首要任务是确保按时交付。在系统运行资源充足、开发时间充裕及技术储备充分的情况下,可以实现更优的设计方案。前后端分离+反射机制的应用将更好地适应当前的需求。