2041 lines
64 KiB
Markdown
2041 lines
64 KiB
Markdown
|
|
# 黑石咀水库系统详细设计文档
|
|||
|
|
|
|||
|
|
# 第4章 项目总体设计
|
|||
|
|
|
|||
|
|
## 4.1 总体架构
|
|||
|
|
|
|||
|
|
### 4.1.1 四层分布式体系架构
|
|||
|
|
|
|||
|
|
黑石咀水库系统作为湖北省山洪灾害监测预报预警"四预"系统的重要组成部分,采用面向服务的架构模型,建立了完整的"基础支撑层-数据支撑层-业务支撑层-业务应用层"分布式体系架构。
|
|||
|
|
|
|||
|
|
#### 架构层次设计
|
|||
|
|
|
|||
|
|
**基础支撑层**:
|
|||
|
|
- **感知设备体系**:集成雨量站、水位站、图像站、末端预警站等监测设备
|
|||
|
|
- **传输网络架构**:水利专网和互联网双通道数据传输
|
|||
|
|
- **基础资源平台**:基于省政务云水利专区的计算资源、存储资源、安全资源和资源调度服务
|
|||
|
|
- **设备接入管理**:通过`StPptnR`、`StRsvrR`、`StRiverR`等实体模型实现设备数据的标准化接入
|
|||
|
|
|
|||
|
|
**数据支撑层**:
|
|||
|
|
- **多源数据整合**:建设汇聚库、主题库、基础库、共享库、专题库五级数据体系
|
|||
|
|
- **数据治理平台**:对各类基础数据、地理空间数据、监测预报数据进行集成、存储、处理、共享
|
|||
|
|
- **数据同步机制**:通过`DataTaskHsz`定时任务实现5分钟间隔的多源数据同步
|
|||
|
|
- **数据质量控制**:实现数据清洗、验证、标准化处理
|
|||
|
|
|
|||
|
|
**业务支撑层**:
|
|||
|
|
- **算法模型体系**:
|
|||
|
|
- 小流域分布式水文模型集成(`flood_algorithm`库)
|
|||
|
|
- 简化淹没范围与水深分析模型
|
|||
|
|
- GRIB2气象数据处理模型(`ForecastService`)
|
|||
|
|
- 空间数据分析模型(JTS集成)
|
|||
|
|
- **应用支撑平台**:
|
|||
|
|
- GIS引擎:基于JTS的空间数据处理能力
|
|||
|
|
- 微服务管理:Spring Boot 3.x原生微服务支持
|
|||
|
|
- 数据支撑平台:MyBatis-Plus 3.5.7 ORM框架
|
|||
|
|
- 消息中心:`MessageCenterService`预警消息管理
|
|||
|
|
- 文件管理:MinIO/S3兼容对象存储
|
|||
|
|
|
|||
|
|
**业务应用层**:
|
|||
|
|
- **预报系统**:气象预报和洪水预测功能
|
|||
|
|
- **预警系统**:多级别、多类型的预警信息管理
|
|||
|
|
- **预演系统**:考核评估和演练管理
|
|||
|
|
- **预案系统**:应急响应和决策支持
|
|||
|
|
|
|||
|
|
### 4.1.2 技术架构实现
|
|||
|
|
|
|||
|
|
#### 微服务架构设计
|
|||
|
|
|
|||
|
|
系统采用Spring Boot 3.x微服务架构,实现服务的模块化部署和独立扩展:
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
@GunShiApplication
|
|||
|
|
@MapperScan(basePackages = {"com.gunshi.**.mapper", "com.gunshi.**.model"})
|
|||
|
|
@EnableMPP
|
|||
|
|
@EnableCaching
|
|||
|
|
public class Main {
|
|||
|
|
public static void main(String[] args) {
|
|||
|
|
SpringApplication.run(Main.class, args);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 分层架构模式
|
|||
|
|
|
|||
|
|
**控制器层**:132个REST API控制器,提供统一的HTTP接口服务
|
|||
|
|
- 统一异常处理:`MyE500UnknownExceptionResolver`
|
|||
|
|
- 参数验证:JSR-303验证注解
|
|||
|
|
- API文档:Swagger 3.0自动生成
|
|||
|
|
|
|||
|
|
**服务层**:业务逻辑处理核心
|
|||
|
|
- 事务管理:`@Transactional(rollbackFor = Exception.class)`
|
|||
|
|
- 缓存策略:`@Cacheable`和`@CacheEvict`注解
|
|||
|
|
- 异步处理:`@Async`和`@Scheduled`注解
|
|||
|
|
|
|||
|
|
**数据访问层**:基于MyBatis-Plus的数据持久化
|
|||
|
|
- Lambda查询:类型安全的查询构建
|
|||
|
|
- 动态SQL:灵活的查询条件组合
|
|||
|
|
- 分页插件:高效的数据分页处理
|
|||
|
|
|
|||
|
|
#### 数据流转架构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
外部数据源 → HTTP API → 数据同步任务 → 数据清洗 → PostgreSQL
|
|||
|
|
↓
|
|||
|
|
实时数据表 → 历史数据表 → 整编数据表(小时/天)
|
|||
|
|
↓
|
|||
|
|
Redis缓存 → 业务服务调用 → 前端展示
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 4.2 网络架构
|
|||
|
|
|
|||
|
|
### 4.2.1 多网络区域架构设计
|
|||
|
|
|
|||
|
|
根据云平台整体架构规划,系统网络接入采用多区域隔离设计,包括互联网接入区、政务外网接入区,每个接入区的业务处理网络彼此隔离。
|
|||
|
|
|
|||
|
|
#### 政务外网及专网区实现
|
|||
|
|
|
|||
|
|
**网络分区设计**:
|
|||
|
|
- **接入区**:提供专线接入湖北省水利厅专网
|
|||
|
|
- 荆楚水库API:`jcskPath: http://64.97.142.113:8002/shareddata/api/v1/monitdata`
|
|||
|
|
- Token认证:`jcskToken` API访问令牌管理
|
|||
|
|
- IP白名单:`reloadCache`动态缓存清理机制
|
|||
|
|
|
|||
|
|
- **核心交换区**:完成各功能分区之间数据流量的高速交换
|
|||
|
|
- 数据库主从同步:PostgreSQL主备架构
|
|||
|
|
- Redis缓存集群:多实例缓存服务
|
|||
|
|
- 负载均衡:基于docker-compose的服务编排
|
|||
|
|
|
|||
|
|
- **运维区**:提供远程运维接入服务
|
|||
|
|
- SSH远程访问:`deploy_rsa`密钥认证
|
|||
|
|
- 日志监控:应用日志和系统日志统一管理
|
|||
|
|
- 性能监控:数据库和应用性能指标监控
|
|||
|
|
|
|||
|
|
- **管理区域**:提供数据中心整体的管理功能
|
|||
|
|
- 用户管理:基于RuoYi框架的权限管理
|
|||
|
|
- 配置管理:多环境配置文件管理
|
|||
|
|
- 审计日志:操作日志和安全审计
|
|||
|
|
|
|||
|
|
#### 安全隔离区实现
|
|||
|
|
|
|||
|
|
**容器化安全隔离**:
|
|||
|
|
```yaml
|
|||
|
|
services:
|
|||
|
|
hsz:
|
|||
|
|
image: openjdk:21
|
|||
|
|
container_name: hsz
|
|||
|
|
network_mode: host
|
|||
|
|
restart: no
|
|||
|
|
volumes:
|
|||
|
|
- /root/gunshiApp/hsz:/app
|
|||
|
|
environment:
|
|||
|
|
- SPRING_PROFILES_ACTIVE=dev
|
|||
|
|
- TZ=Asia/Shanghai
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**网络安全配置**:
|
|||
|
|
- 网络模式:`network_mode: host`实现负载分担
|
|||
|
|
- 端口管理:统一的服务端口管理(24205)
|
|||
|
|
- 访问控制:基于Token的API访问控制
|
|||
|
|
|
|||
|
|
### 4.2.2 外部网络集成
|
|||
|
|
|
|||
|
|
#### 三网接入支持
|
|||
|
|
|
|||
|
|
**多网络接入架构**:
|
|||
|
|
- **电信接入**:通过外部API配置支持电信网络接入
|
|||
|
|
- **联通接入**:多网络负载均衡和冗余设计
|
|||
|
|
- **移动接入**:移动网络接入支持
|
|||
|
|
|
|||
|
|
**外部API集成体系**:
|
|||
|
|
```yaml
|
|||
|
|
# 气象数据API
|
|||
|
|
shqxjsCloudowrCnPath: http://shqxjs.cloudowr.cn/service/
|
|||
|
|
|
|||
|
|
# 水库数据API
|
|||
|
|
owrsvrPath: http://owrsvr.cloudowr.cn/
|
|||
|
|
|
|||
|
|
# IP白名单管理
|
|||
|
|
reloadCache: http://223.75.53.124:8002/shareddata/sys/whitelists/reloadCache
|
|||
|
|
|
|||
|
|
# 数据同步API
|
|||
|
|
apiPath: http://223.75.53.141:8000/shzh/monitdata/datasync/getData
|
|||
|
|
|
|||
|
|
# 预警信息API
|
|||
|
|
shqxjsWarnPath: http://223.75.53.141:8000/shzh/met/zyqxfw/api/warning/getGroupWarning
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 4.3 部署架构
|
|||
|
|
|
|||
|
|
### 4.3.1 容器化部署架构
|
|||
|
|
|
|||
|
|
#### 前端服务器配置
|
|||
|
|
|
|||
|
|
**VPC部署设计**:
|
|||
|
|
- 独立VPC环境,分配弹性IP
|
|||
|
|
- 集群技术实现负载分担和高可用
|
|||
|
|
- 等保三级安全要求:WAF、防DDOS、IPS等安全服务
|
|||
|
|
|
|||
|
|
**网络优化配置**:
|
|||
|
|
```yaml
|
|||
|
|
server:
|
|||
|
|
port: 24205
|
|||
|
|
servlet:
|
|||
|
|
context-path: /gunshiApp/hsz
|
|||
|
|
compression:
|
|||
|
|
enabled: true
|
|||
|
|
mime-types: application/javascript,text/css,application/json,application/xml,text/html,text/xml
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 后端服务器配置
|
|||
|
|
|
|||
|
|
**独立VPC部署**:
|
|||
|
|
- 后端服务器在单独的VPC,不分配弹性IP
|
|||
|
|
- 内部IP地址交互,提高安全性
|
|||
|
|
- 云防火墙安全隔离
|
|||
|
|
|
|||
|
|
**容器编排配置**:
|
|||
|
|
- 基础镜像:`openjdk:21`
|
|||
|
|
- 数据存储:`/root/gunshiApp/hsz:/app`
|
|||
|
|
- 时区配置:`TZ=Asia/Shanghai`
|
|||
|
|
- 环境配置:`SPRING_PROFILES_ACTIVE=dev`
|
|||
|
|
|
|||
|
|
### 4.3.2 数据引擎部署
|
|||
|
|
|
|||
|
|
#### PostgreSQL主备架构
|
|||
|
|
|
|||
|
|
**主数据库配置**:
|
|||
|
|
```yaml
|
|||
|
|
spring:
|
|||
|
|
datasource:
|
|||
|
|
dynamic:
|
|||
|
|
datasource:
|
|||
|
|
master:
|
|||
|
|
url: jdbc:postgresql://postgres:5432/hsz?stringtype=unspecified
|
|||
|
|
username: gunshiiot
|
|||
|
|
password: 1234567a
|
|||
|
|
driver-class-name: org.postgresql.Driver
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**备用数据库配置**:
|
|||
|
|
- 主从同步:基于PostgreSQL流复制
|
|||
|
|
- 故障转移:自动主备切换机制
|
|||
|
|
- 连接池:HikariCP高性能连接管理
|
|||
|
|
|
|||
|
|
#### 缓存系统部署
|
|||
|
|
|
|||
|
|
**Redis集群配置**:
|
|||
|
|
```yaml
|
|||
|
|
data:
|
|||
|
|
redis:
|
|||
|
|
host: redis
|
|||
|
|
port: 6379
|
|||
|
|
database: 4
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**缓存策略**:
|
|||
|
|
- 会话管理:用户登录状态缓存
|
|||
|
|
- 查询缓存:热点数据查询优化
|
|||
|
|
- 分布式缓存:多实例数据一致性
|
|||
|
|
|
|||
|
|
## 4.4 数据架构
|
|||
|
|
|
|||
|
|
### 4.4.1 数据源体系
|
|||
|
|
|
|||
|
|
#### 行业外数据源
|
|||
|
|
|
|||
|
|
**气象数据源**:
|
|||
|
|
- 数据来源:省气象局气象监测雨量和预报雨量
|
|||
|
|
- 接入方式:`shqxjsCloudowrCnPath` API接口
|
|||
|
|
- 数据类型:GRIB2气象文件、实时监测数据
|
|||
|
|
- 处理服务:`ForecastService`气象预报处理
|
|||
|
|
|
|||
|
|
**水文数据源**:
|
|||
|
|
- 数据来源:省水文处水文监测雨量
|
|||
|
|
- 接入方式:荆楚水库API专线接入
|
|||
|
|
- 数据类型:降雨量、水位、流量
|
|||
|
|
- 同步频率:5分钟定时同步
|
|||
|
|
|
|||
|
|
**水库数据源**:
|
|||
|
|
- 数据来源:省水库处水库监测数据
|
|||
|
|
- 接入方式:`owrsvrPath` API接口
|
|||
|
|
- 数据类型:水库水位、蓄水量
|
|||
|
|
- 处理机制:实时数据和历史数据分离
|
|||
|
|
|
|||
|
|
#### 行业内数据源
|
|||
|
|
|
|||
|
|
**基础地理数据**:
|
|||
|
|
- 数据来源:中国水科院提供的107条小流域风险隐患调查数据
|
|||
|
|
- 数据类型:空间地理数据、流域边界、风险隐患要素
|
|||
|
|
- 处理方式:GIS空间分析和可视化
|
|||
|
|
|
|||
|
|
**行政区划数据**:
|
|||
|
|
- 数据来源:各区县水利局提供的行政区划信息
|
|||
|
|
- 数据类型:行政区划边界、责任人信息
|
|||
|
|
- 管理服务:`StAddvcdDService`行政区划管理
|
|||
|
|
|
|||
|
|
### 4.4.2 数据支撑平台
|
|||
|
|
|
|||
|
|
#### 数据处理能力
|
|||
|
|
|
|||
|
|
**气象文件处理**:
|
|||
|
|
- GRIB2文件解析:`grb.RainGrib2Layer`网格数据模型
|
|||
|
|
- 雷达数据处理:短临预报数据处理
|
|||
|
|
- 网格计算:基于JTS的空间插值算法
|
|||
|
|
|
|||
|
|
**数据计算分析**:
|
|||
|
|
- 面雨量计算:泰森多边形权重计算
|
|||
|
|
- 时间序列分析:历史数据趋势分析
|
|||
|
|
- 多维分析:基于MyBatis-Plus的数据统计
|
|||
|
|
|
|||
|
|
**算法模型对接**:
|
|||
|
|
- 洪水算法库:`flood_algorithm`库集成
|
|||
|
|
- 空间分析:JTS几何计算引擎
|
|||
|
|
- 预测模型:气象预报和水文预测模型
|
|||
|
|
|
|||
|
|
#### 数据交换共享平台
|
|||
|
|
|
|||
|
|
**数据同步机制**:
|
|||
|
|
```java
|
|||
|
|
@Async
|
|||
|
|
@Scheduled(fixedRate = 5, timeUnit = TimeUnit.MINUTES)
|
|||
|
|
public void getPptnData() // 5分钟雨量数据同步
|
|||
|
|
@Async
|
|||
|
|
@Scheduled(fixedRate = 5, timeUnit = TimeUnit.MINUTES)
|
|||
|
|
public void getRiverData() // 5分钟水情数据同步
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**数据汇聚中心**:
|
|||
|
|
- 25个县区山洪监测数据汇聚
|
|||
|
|
- 一站双发数据采集机制
|
|||
|
|
- 数据质量控制和异常处理
|
|||
|
|
|
|||
|
|
### 4.4.3 数据库体系
|
|||
|
|
|
|||
|
|
#### 基础数据库设计
|
|||
|
|
|
|||
|
|
**实体模型体系**:
|
|||
|
|
- 监测数据模型:`StPptnR`、`StRsvrR`、`StRiverR`
|
|||
|
|
- 预警数据模型:`MessageCenter`、`OsmoticWarnR`
|
|||
|
|
- 业务数据模型:`AssessTask`、`PrePlace`、`ByPlan`
|
|||
|
|
|
|||
|
|
**数据关系设计**:
|
|||
|
|
- 一对多关系:防治对象与监测设备关系
|
|||
|
|
- 多对多关系:考核任务与考核对象关系
|
|||
|
|
- 层级关系:行政区划层级结构
|
|||
|
|
|
|||
|
|
#### 专题数据库设计
|
|||
|
|
|
|||
|
|
**预报专题库**:
|
|||
|
|
- 气象预报数据:24小时预报和逐小时预报
|
|||
|
|
- 网格降雨数据:基于GIS的空间网格数据
|
|||
|
|
- 历史比对数据:历史同期数据对比分析
|
|||
|
|
|
|||
|
|
**预警专题库**:
|
|||
|
|
- 预警规则配置:`OsmoticWarnRule`预警规则管理
|
|||
|
|
- 预警消息记录:分级预警消息存储
|
|||
|
|
- 预警统计分析:预警频次和类型统计
|
|||
|
|
|
|||
|
|
### 4.4.4 数据应用体系
|
|||
|
|
|
|||
|
|
#### 水雨情监测应用
|
|||
|
|
|
|||
|
|
**实时监测功能**:
|
|||
|
|
- 实时数据展示:`StPptnRRealService`实时降雨监测
|
|||
|
|
- 历史数据查询:`StPptnRService`历史数据检索
|
|||
|
|
- 数据统计报表:多维度数据统计分析
|
|||
|
|
|
|||
|
|
**监测站点管理**:
|
|||
|
|
- 站点信息管理:监测站点基本信息维护
|
|||
|
|
- 站点状态监控:设备运行状态实时监控
|
|||
|
|
- 数据质量评估:监测数据质量评估和报警
|
|||
|
|
|
|||
|
|
#### 预报应用专题
|
|||
|
|
|
|||
|
|
**天气预报功能**:
|
|||
|
|
- GRIB2数据处理:专业气象文件解析
|
|||
|
|
- 网格降雨量计算:空间插值算法
|
|||
|
|
- 预报结果展示:多时间尺度预报展示
|
|||
|
|
|
|||
|
|
**洪水预报功能**:
|
|||
|
|
- 水位预测:基于历史数据的水位预测
|
|||
|
|
- 流量预测:基于水文模型的流量预测
|
|||
|
|
- 风险评估:洪水风险评估和预警
|
|||
|
|
|
|||
|
|
#### 预警应用专题
|
|||
|
|
|
|||
|
|
**多级预警机制**:
|
|||
|
|
- 水位预警:超校核水位、超设计水位、超汛限水位
|
|||
|
|
- 渗压预警:渗流压力监测和预警
|
|||
|
|
- 降雨预警:强降雨监测和预警
|
|||
|
|
|
|||
|
|
**预警消息管理**:
|
|||
|
|
- 消息推送:基于角色的预警消息推送
|
|||
|
|
- 状态管理:预警消息的确认和处理状态
|
|||
|
|
- 统计分析:预警数据统计和分析
|
|||
|
|
|
|||
|
|
## 4.5 安全架构
|
|||
|
|
|
|||
|
|
### 4.5.1 总体安全策略
|
|||
|
|
|
|||
|
|
#### 数据安全策略
|
|||
|
|
|
|||
|
|
**敏感数据保护**:
|
|||
|
|
- 数据库连接加密:PostgreSQL SSL连接
|
|||
|
|
- API访问认证:基于Token的身份认证
|
|||
|
|
- 密码安全:数据库密码加密存储
|
|||
|
|
|
|||
|
|
**输入数据安全**:
|
|||
|
|
- XSS防护:自定义Jackson反序列化器
|
|||
|
|
- SQL注入防护:MyBatis-Plus参数化查询
|
|||
|
|
- 输入验证:JSR-303验证注解
|
|||
|
|
|
|||
|
|
#### 系统安全策略
|
|||
|
|
|
|||
|
|
**访问控制**:
|
|||
|
|
- 基于角色的权限控制:RuoYi框架集成
|
|||
|
|
- API访问控制:Token认证机制
|
|||
|
|
- 数据访问控制:基于用户权限的数据访问
|
|||
|
|
|
|||
|
|
**审计安全**:
|
|||
|
|
- 操作日志记录:用户操作行为审计
|
|||
|
|
- 系统日志监控:系统运行状态监控
|
|||
|
|
- 安全事件审计:安全事件记录和分析
|
|||
|
|
|
|||
|
|
### 4.5.2 网络安全等级保护
|
|||
|
|
|
|||
|
|
#### 等保三级要求
|
|||
|
|
|
|||
|
|
**网络安全防护**:
|
|||
|
|
- 网络隔离:政务外网和互联网区域隔离
|
|||
|
|
- 访问控制:基于IP和端口的访问控制
|
|||
|
|
- 入侵检测:网络入侵检测和防护
|
|||
|
|
|
|||
|
|
**数据安全防护**:
|
|||
|
|
- 数据加密:敏感数据传输和存储加密
|
|||
|
|
- 数据备份:定期数据备份和恢复
|
|||
|
|
- 数据完整性:数据完整性校验和验证
|
|||
|
|
|
|||
|
|
**应用安全防护**:
|
|||
|
|
- 应用防火墙:Web应用防火墙防护
|
|||
|
|
- 漏洞管理:定期漏洞扫描和修复
|
|||
|
|
- 安全编码:安全编码规范和检查
|
|||
|
|
|
|||
|
|
### 4.5.3 安全技术体系
|
|||
|
|
|
|||
|
|
#### 计算环境安全
|
|||
|
|
|
|||
|
|
**容器安全**:
|
|||
|
|
- Docker容器隔离:进程和网络隔离
|
|||
|
|
- 镜像安全:基础镜像安全扫描
|
|||
|
|
- 运行时安全:容器运行时监控
|
|||
|
|
|
|||
|
|
**应用安全**:
|
|||
|
|
- Spring Security:安全框架集成
|
|||
|
|
- 会话管理:安全的会话管理机制
|
|||
|
|
- 异常处理:统一的异常处理机制
|
|||
|
|
|
|||
|
|
**数据安全**:
|
|||
|
|
- 数据库安全:PostgreSQL安全配置
|
|||
|
|
- 文件安全:MinIO对象存储安全
|
|||
|
|
- 缓存安全:Redis缓存安全配置
|
|||
|
|
|
|||
|
|
#### 安全区域边界
|
|||
|
|
|
|||
|
|
**网络边界安全**:
|
|||
|
|
- 防火墙:网络边界防火墙防护
|
|||
|
|
- 负载均衡:安全的负载均衡配置
|
|||
|
|
- DDoS防护:分布式拒绝服务攻击防护
|
|||
|
|
|
|||
|
|
**应用边界安全**:
|
|||
|
|
- API网关:统一的API访问控制
|
|||
|
|
- 请求限流:API访问频率限制
|
|||
|
|
- 参数验证:输入参数严格验证
|
|||
|
|
|
|||
|
|
### 4.5.4 安全管理体系
|
|||
|
|
|
|||
|
|
#### 安全策略管理
|
|||
|
|
|
|||
|
|
**安全策略制定**:
|
|||
|
|
- 数据安全策略:敏感数据保护策略
|
|||
|
|
- 网络安全策略:网络安全防护策略
|
|||
|
|
- 应用安全策略:应用系统安全策略
|
|||
|
|
|
|||
|
|
**安全管理制度**:
|
|||
|
|
- 访问控制制度:基于角色的访问控制
|
|||
|
|
- 数据管理制度:数据分类和管理制度
|
|||
|
|
- 应急响应制度:安全事件应急响应流程
|
|||
|
|
|
|||
|
|
#### 安全运维管理
|
|||
|
|
|
|||
|
|
**安全监控**:
|
|||
|
|
- 实时监控:系统安全状态实时监控
|
|||
|
|
- 日志审计:安全日志审计和分析
|
|||
|
|
- 异常检测:安全异常行为检测
|
|||
|
|
|
|||
|
|
**安全维护**:
|
|||
|
|
- 漏洞修复:定期漏洞扫描和修复
|
|||
|
|
- 安全更新:系统和应用安全更新
|
|||
|
|
- 备份恢复:数据备份和恢复演练
|
|||
|
|
|
|||
|
|
## 4.6 数据流向
|
|||
|
|
|
|||
|
|
### 4.6.1 数据采集流程
|
|||
|
|
|
|||
|
|
#### 多源数据采集
|
|||
|
|
|
|||
|
|
**山洪5分钟雨量监测数据**:
|
|||
|
|
- 数据源:全省74个县的山洪5分钟雨量监测数据
|
|||
|
|
- 采集方式:一站双发形式,确保数据可靠性
|
|||
|
|
- 处理机制:`DataTaskHsz.getPptnData()`定时同步
|
|||
|
|
- 数据存储:`StPptnR`实时数据表和`StPptnRH`历史数据表
|
|||
|
|
|
|||
|
|
**气象1小时雨量监测数据**:
|
|||
|
|
- 数据源:省气象局Oracle数据库
|
|||
|
|
- 采集方式:先上报到省气象局,再通过数据汇集与共享平台同步
|
|||
|
|
- 处理机制:GRIB2文件解析和网格化处理
|
|||
|
|
- 数据存储:`ForecastService`处理后的网格数据
|
|||
|
|
|
|||
|
|
**水库1小时雨量监测数据**:
|
|||
|
|
- 数据源:省水库处SqlServer数据库
|
|||
|
|
- 采集方式:通过数据汇集与共享平台同步
|
|||
|
|
- 处理机制:`DataTaskHsz.getRiverData()`定时同步
|
|||
|
|
- 数据存储:`StRsvrR`水库水位数据表
|
|||
|
|
|
|||
|
|
#### 数据质量控制
|
|||
|
|
|
|||
|
|
**数据验证机制**:
|
|||
|
|
- 完整性检查:数据字段完整性验证
|
|||
|
|
- 格式检查:数据格式和类型验证
|
|||
|
|
- 范围检查:数据值范围合理性验证
|
|||
|
|
|
|||
|
|
**数据清洗流程**:
|
|||
|
|
- 异常数据处理:识别和处理异常数据
|
|||
|
|
- 重复数据去重:基于时间戳和设备ID去重
|
|||
|
|
- 数据标准化:统一数据格式和单位
|
|||
|
|
|
|||
|
|
### 4.6.2 数据处理流程
|
|||
|
|
|
|||
|
|
#### 实时数据处理
|
|||
|
|
|
|||
|
|
**实时数据流入**:
|
|||
|
|
```
|
|||
|
|
外部API → HTTP请求 → 数据解析 → 数据验证 → PostgreSQL存储
|
|||
|
|
↓
|
|||
|
|
Redis缓存更新 → 业务服务消费 → 前端实时展示
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**数据同步机制**:
|
|||
|
|
```java
|
|||
|
|
@Async
|
|||
|
|
@Scheduled(fixedRate = 5, timeUnit = TimeUnit.MINUTES)
|
|||
|
|
public void getPptnData() {
|
|||
|
|
// HTTP请求获取数据
|
|||
|
|
// 数据解析和验证
|
|||
|
|
// 批量保存到数据库
|
|||
|
|
// 更新Redis缓存
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 历史数据处理
|
|||
|
|
|
|||
|
|
**数据整编处理**:
|
|||
|
|
- 小时数据整编:基于5分钟数据生成小时统计数据
|
|||
|
|
- 天数据整编:基于小时数据生成天统计数据
|
|||
|
|
- 月数据整编:基于天数据生成月统计数据
|
|||
|
|
|
|||
|
|
**数据归档策略**:
|
|||
|
|
- 实时数据:保留最近30天实时数据
|
|||
|
|
- 历史数据:长期保存历史整编数据
|
|||
|
|
- 统计数据:保存各类统计数据
|
|||
|
|
|
|||
|
|
### 4.6.3 数据应用流程
|
|||
|
|
|
|||
|
|
#### 业务数据应用
|
|||
|
|
|
|||
|
|
**预报数据应用**:
|
|||
|
|
- 气象预报数据:GRIB2文件处理和网格化展示
|
|||
|
|
- 洪水预报数据:基于水文模型的洪水预测
|
|||
|
|
- 预警数据应用:基于阈值的预警信息发布
|
|||
|
|
|
|||
|
|
**管理数据应用**:
|
|||
|
|
- 考核数据管理:`AssessTaskService`考核任务管理
|
|||
|
|
- 防治对象管理:`PrePlaceService`防治点管理
|
|||
|
|
- 维护管理:`MentencePlanService`维护计划管理
|
|||
|
|
|
|||
|
|
#### 对外数据共享
|
|||
|
|
|
|||
|
|
**数据接口服务**:
|
|||
|
|
- REST API:标准化的数据访问接口
|
|||
|
|
- 文件导出:Excel、PDF等格式数据导出
|
|||
|
|
- 实时推送:WebSocket实时数据推送
|
|||
|
|
|
|||
|
|
**数据安全保障**:
|
|||
|
|
- 访问控制:基于权限的数据访问
|
|||
|
|
- 数据脱敏:敏感信息脱敏处理
|
|||
|
|
- 审计日志:数据访问日志记录
|
|||
|
|
|
|||
|
|
## 4.7 技术路线
|
|||
|
|
|
|||
|
|
### 4.7.1 微服务架构
|
|||
|
|
|
|||
|
|
#### 服务拆分策略
|
|||
|
|
|
|||
|
|
**业务模块化**:
|
|||
|
|
- 按业务领域划分:预报、预警、预演、预案
|
|||
|
|
- 按数据类型划分:监测数据、管理数据、统计数据
|
|||
|
|
- 按用户角色划分:管理员、县级用户、普通用户
|
|||
|
|
|
|||
|
|
**技术组件化**:
|
|||
|
|
- 数据同步组件:`DataTaskHsz`定时任务组件
|
|||
|
|
- 预警处理组件:`MessageCenterService`预警消息组件
|
|||
|
|
- 预报计算组件:`ForecastService`气象预报组件
|
|||
|
|
|
|||
|
|
#### 服务治理机制
|
|||
|
|
|
|||
|
|
**服务注册发现**:
|
|||
|
|
- Spring Boot原生服务注册
|
|||
|
|
- 配置中心:多环境配置管理
|
|||
|
|
- 健康检查:服务健康状态监控
|
|||
|
|
|
|||
|
|
**服务间通信**:
|
|||
|
|
- HTTP REST:同步服务调用
|
|||
|
|
- 异步消息:基于消息队列的异步处理
|
|||
|
|
- 事件驱动:基于事件的松耦合架构
|
|||
|
|
|
|||
|
|
### 4.7.2 云计算技术
|
|||
|
|
|
|||
|
|
#### 云平台部署
|
|||
|
|
|
|||
|
|
**政务云集成**:
|
|||
|
|
- 省政务云水利专区部署
|
|||
|
|
- 专属云平台和云产品
|
|||
|
|
- 独立物理机房安全保障
|
|||
|
|
|
|||
|
|
**容器化部署**:
|
|||
|
|
- Docker容器化部署
|
|||
|
|
- docker-compose服务编排
|
|||
|
|
- 持续集成和持续部署
|
|||
|
|
|
|||
|
|
#### 云原生技术
|
|||
|
|
|
|||
|
|
**微服务支持**:
|
|||
|
|
- Spring Boot 3.x微服务框架
|
|||
|
|
- 云原生配置管理
|
|||
|
|
- 弹性伸缩和负载均衡
|
|||
|
|
|
|||
|
|
**DevOps实践**:
|
|||
|
|
- 自动化构建:Maven构建工具
|
|||
|
|
- 自动化测试:JUnit单元测试
|
|||
|
|
- 自动化部署:容器化部署脚本
|
|||
|
|
|
|||
|
|
## 4.8 接口设计
|
|||
|
|
|
|||
|
|
### 4.8.1 用户接口设计
|
|||
|
|
|
|||
|
|
#### REST API接口
|
|||
|
|
|
|||
|
|
**接口标准化**:
|
|||
|
|
- RESTful设计:符合REST架构风格
|
|||
|
|
- 统一响应格式:JSON格式标准化响应
|
|||
|
|
- 错误处理:统一的异常处理机制
|
|||
|
|
|
|||
|
|
**API文档管理**:
|
|||
|
|
```java
|
|||
|
|
@OpenAPIDefinition(
|
|||
|
|
servers = {
|
|||
|
|
@Server(url = "http://localhost:24105/gunshiApp/hsz", description = "本地测试环境"),
|
|||
|
|
@Server(url = "http://local.gunshiiot.com:18083/gunshiApp/hsz", description = "线上测试环境")
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**接口分组管理**:
|
|||
|
|
- 按业务模块分组:预报、预警、管理、系统
|
|||
|
|
- 按用户角色分组:管理员、县级用户、普通用户
|
|||
|
|
- 按功能类型分组:查询接口、管理接口、统计接口
|
|||
|
|
|
|||
|
|
#### 前端集成接口
|
|||
|
|
|
|||
|
|
**数据查询接口**:
|
|||
|
|
- 实时数据查询:`/api/realtime/data`
|
|||
|
|
- 历史数据查询:`/api/history/data`
|
|||
|
|
- 统计数据查询:`/api/statistics/data`
|
|||
|
|
|
|||
|
|
**业务操作接口**:
|
|||
|
|
- 预警发布接口:`/api/warning/publish`
|
|||
|
|
- 考核管理接口:`api/assessment/manage`
|
|||
|
|
- 系统管理接口:`/api/system/manage`
|
|||
|
|
|
|||
|
|
### 4.8.2 外部接口设计
|
|||
|
|
|
|||
|
|
#### 气象数据接口
|
|||
|
|
|
|||
|
|
**GRIB2数据获取**:
|
|||
|
|
```java
|
|||
|
|
@Value("${shqxjsCloudowrCnPath}")
|
|||
|
|
private String shqxjsCloudowrCnPath;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**数据处理流程**:
|
|||
|
|
- 文件获取:从气象服务器获取GRIB2文件
|
|||
|
|
- 数据解析:解析气象网格数据
|
|||
|
|
- 结果计算:计算面雨量和预报结果
|
|||
|
|
|
|||
|
|
#### 水文数据接口
|
|||
|
|
|
|||
|
|
**荆楚水库API**:
|
|||
|
|
```java
|
|||
|
|
@Value("${jcskPath}")
|
|||
|
|
private String jcskPath; // 荆楚水库API路径
|
|||
|
|
|
|||
|
|
@Value("${jcskToken}")
|
|||
|
|
private String jcskToken; // API访问令牌
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**数据同步机制**:
|
|||
|
|
- Token认证:API访问安全认证
|
|||
|
|
- IP白名单:访问IP地址控制
|
|||
|
|
- 重试机制:网络异常重试处理
|
|||
|
|
|
|||
|
|
### 4.8.3 内部接口设计
|
|||
|
|
|
|||
|
|
#### 服务层接口
|
|||
|
|
|
|||
|
|
**业务服务接口**:
|
|||
|
|
- 预报服务:`ForecastService`气象预报服务
|
|||
|
|
- 预警服务:`MessageCenterService`预警消息服务
|
|||
|
|
- 考核服务:`AssessTaskService`考核任务服务
|
|||
|
|
|
|||
|
|
**数据服务接口**:
|
|||
|
|
- 实时数据服务:`StPptnRRealService`实时数据服务
|
|||
|
|
- 历史数据服务:`StPptnRService`历史数据服务
|
|||
|
|
- 统计数据服务:各种统计数据服务
|
|||
|
|
|
|||
|
|
#### 数据访问接口
|
|||
|
|
|
|||
|
|
**Mapper接口设计**:
|
|||
|
|
- 基础CRUD:继承`BaseMapper`基础操作
|
|||
|
|
- 自定义查询:复杂业务查询方法
|
|||
|
|
- 动态SQL:基于条件的动态查询构建
|
|||
|
|
|
|||
|
|
**缓存接口设计**:
|
|||
|
|
- 查询缓存:`@Cacheable`查询结果缓存
|
|||
|
|
- 更新缓存:`@CacheEvict`缓存更新和清除
|
|||
|
|
- 分布式缓存:Redis分布式缓存支持
|
|||
|
|
|
|||
|
|
# 第5章 功能设计
|
|||
|
|
|
|||
|
|
## 5.1 梳理集成基础数据
|
|||
|
|
|
|||
|
|
### 5.1.1 设计思路
|
|||
|
|
|
|||
|
|
为梳理集成完整的、准确的、权威的湖北山洪灾害基础数据,需对基础数据进行全量调研和评估,分析其质量、完整性、准确性,识别可能存在的数据缺失、错误或不一致等问题。
|
|||
|
|
|
|||
|
|
#### 数据质量评估体系
|
|||
|
|
|
|||
|
|
**数据完整性评估**:
|
|||
|
|
- 必填字段检查:确保关键字段不为空
|
|||
|
|
- 数据范围验证:验证数据在合理范围内
|
|||
|
|
- 时间连续性检查:确保时间序列数据的连续性
|
|||
|
|
|
|||
|
|
**数据准确性评估**:
|
|||
|
|
- 数据一致性检查:跨表数据一致性验证
|
|||
|
|
- 业务逻辑验证:基于业务规则的逻辑验证
|
|||
|
|
- 异常值检测:识别和处理异常数据
|
|||
|
|
|
|||
|
|
**数据权威性评估**:
|
|||
|
|
- 数据来源确认:确认数据来源的权威性
|
|||
|
|
- 数据更新机制:确保数据的及时更新
|
|||
|
|
- 数据版本管理:维护数据的历史版本
|
|||
|
|
|
|||
|
|
### 5.1.2 防治对象调查评价成果集成
|
|||
|
|
|
|||
|
|
#### 调查评价成果数据管理
|
|||
|
|
|
|||
|
|
**防治对象数据模型**:
|
|||
|
|
```java
|
|||
|
|
// 防治点实体模型
|
|||
|
|
public class PrePlace {
|
|||
|
|
private Long id;
|
|||
|
|
private String placeName; // 防治点名称
|
|||
|
|
private String placeCode; // 防治点编码
|
|||
|
|
private String placeType; // 防治点类型
|
|||
|
|
private String location; // 地理位置
|
|||
|
|
private String riskLevel; // 风险等级
|
|||
|
|
// ... 其他字段
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**防治部位详细管理**:
|
|||
|
|
```java
|
|||
|
|
// 防治部位实体模型
|
|||
|
|
public class PrePlaceDetail {
|
|||
|
|
private Long id;
|
|||
|
|
private Long placeId; // 关联防治点ID
|
|||
|
|
private String detailName; // 部位名称
|
|||
|
|
private String detailType; // 部位类型
|
|||
|
|
private String status; // 状态
|
|||
|
|
// ... 其他字段
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 成果数据集成实现
|
|||
|
|
|
|||
|
|
**调查评价成果报告管理**:
|
|||
|
|
- 文档存储:基于MinIO的对象存储
|
|||
|
|
- 元数据管理:文档的基本信息和分类
|
|||
|
|
- 版本控制:文档版本管理和历史追踪
|
|||
|
|
|
|||
|
|
**图集管理系统**:
|
|||
|
|
- 图像存储:防治对象相关图像存储
|
|||
|
|
- 空间关联:图像与防治对象的空间关联
|
|||
|
|
- 展示管理:图集的在线展示和查询
|
|||
|
|
|
|||
|
|
**成果数据管理**:
|
|||
|
|
- 电子数据:结构化数据存储和管理
|
|||
|
|
- 纸质数据:纸质文档的数字化管理
|
|||
|
|
- 照片数据:相关照片的存储和管理
|
|||
|
|
|
|||
|
|
### 5.1.3 风险隐患调查与影响分析成果集成
|
|||
|
|
|
|||
|
|
#### 风险隐患数据模型设计
|
|||
|
|
|
|||
|
|
**风险隐患要素数据**:
|
|||
|
|
```java
|
|||
|
|
// 风险隐患要素实体
|
|||
|
|
public class RiskHazard {
|
|||
|
|
private Long id;
|
|||
|
|
private String hazardCode; // 隐患编码
|
|||
|
|
private String hazardType; // 隐患类型
|
|||
|
|
private String hazardName; // 隐患名称
|
|||
|
|
private String location; // 位置信息
|
|||
|
|
private String riskLevel; // 风险等级
|
|||
|
|
private Geometry geometry; // 空间几何信息
|
|||
|
|
// ... 其他字段
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**断面数据管理**:
|
|||
|
|
```java
|
|||
|
|
// 断面数据实体
|
|||
|
|
public class SectionData {
|
|||
|
|
private Long id;
|
|||
|
|
private String sectionCode; // 断面编码
|
|||
|
|
private String sectionName; // 断面名称
|
|||
|
|
private String riverCode; // 河流编码
|
|||
|
|
private BigDecimal elevation; // 高程
|
|||
|
|
private Geometry sectionLine; // 断面线几何
|
|||
|
|
// ... 其他字段
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 成果报表管理实现
|
|||
|
|
|
|||
|
|
**重点关注对象详查名录表**:
|
|||
|
|
- 对象管理:重点防治对象的详细信息管理
|
|||
|
|
- 风险评估:对象风险评估和等级划分
|
|||
|
|
- 监测关联:与监测设备的关联管理
|
|||
|
|
|
|||
|
|
**防治对象-监测设备关系表**:
|
|||
|
|
- 关系映射:防治对象与监测设备的对应关系
|
|||
|
|
- 设备信息:监测设备的基本信息和状态
|
|||
|
|
- 数据关联:监测数据与防治对象的关联
|
|||
|
|
|
|||
|
|
**山洪灾害防治对象名录**:
|
|||
|
|
- 名录管理:防治对象的统一名录管理
|
|||
|
|
- 分类管理:按类型、区域等分类管理
|
|||
|
|
- 状态管理:防治对象的状态跟踪
|
|||
|
|
|
|||
|
|
**跨沟道路、桥涵、塘(堰)坝调查成果表**:
|
|||
|
|
- 设施管理:跨沟设施的管理和维护
|
|||
|
|
- 安全评估:设施安全状况评估
|
|||
|
|
- 风险分析:设施对山洪的影响分析
|
|||
|
|
|
|||
|
|
### 5.1.4 数据治理入库和应用集成
|
|||
|
|
|
|||
|
|
#### 数据治理流程设计
|
|||
|
|
|
|||
|
|
**数据提取阶段**:
|
|||
|
|
- 多源数据采集:从不同数据源提取原始数据
|
|||
|
|
- 数据格式转换:统一数据格式和编码
|
|||
|
|
- 数据质量检查:初步的数据质量评估
|
|||
|
|
|
|||
|
|
**数据清洗阶段**:
|
|||
|
|
- 异常数据处理:识别和处理异常数据
|
|||
|
|
- 重复数据去重:基于业务规则的去重处理
|
|||
|
|
- 数据标准化:统一数据标准和规范
|
|||
|
|
|
|||
|
|
**数据整合阶段**:
|
|||
|
|
- 数据关联:建立数据间的关联关系
|
|||
|
|
- 数据融合:多源数据的融合处理
|
|||
|
|
- 数据验证:业务逻辑验证和一致性检查
|
|||
|
|
|
|||
|
|
**数据转换阶段**:
|
|||
|
|
- 数据映射:源数据到目标数据的映射
|
|||
|
|
- 数据计算:派生数据的计算和生成
|
|||
|
|
- 数据聚合:数据的汇总和聚合处理
|
|||
|
|
|
|||
|
|
**数据解耦和重组阶段**:
|
|||
|
|
- 数据分层:按业务需求进行数据分层
|
|||
|
|
- 数据分区:按时间和区域进行数据分区
|
|||
|
|
- 数据索引:建立高效的数据索引
|
|||
|
|
|
|||
|
|
**数据入库阶段**:
|
|||
|
|
- 批量导入:高效的数据批量导入
|
|||
|
|
- 事务管理:确保数据导入的事务一致性
|
|||
|
|
- 完整性检查:数据完整性和一致性验证
|
|||
|
|
|
|||
|
|
#### 数据治理服务实现
|
|||
|
|
|
|||
|
|
**数据质量监控服务**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class DataQualityService {
|
|||
|
|
|
|||
|
|
public DataQualityReport checkDataQuality(String dataType) {
|
|||
|
|
// 数据质量检查逻辑
|
|||
|
|
return qualityReport;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public List<DataAnomaly> detectAnomalies(String dataset) {
|
|||
|
|
// 异常数据检测逻辑
|
|||
|
|
return anomalyList;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**数据标准化服务**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class DataStandardizationService {
|
|||
|
|
|
|||
|
|
public StandardizedData standardizeData(RawData rawData) {
|
|||
|
|
// 数据标准化处理逻辑
|
|||
|
|
return standardizedData;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public ValidationResult validateStandards(StandardizedData data) {
|
|||
|
|
// 标准验证逻辑
|
|||
|
|
return validationResult;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.1.5 小流域治理单元建档立卡
|
|||
|
|
|
|||
|
|
#### 小流域基础信息管理
|
|||
|
|
|
|||
|
|
**小流域治理单元数据模型**:
|
|||
|
|
```java
|
|||
|
|
// 小流域治理单元实体
|
|||
|
|
public class WatershedUnit {
|
|||
|
|
private Long id;
|
|||
|
|
private String unitCode; // 单元编码
|
|||
|
|
private String unitName; // 单元名称
|
|||
|
|
private String area; // 流域面积
|
|||
|
|
private String riverLength; // 河流长度
|
|||
|
|
private String avgElevation; // 平均高程
|
|||
|
|
private Geometry boundary; // 流域边界
|
|||
|
|
// ... 其他字段
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**基础信息梳理功能**:
|
|||
|
|
- 全省1309个小流域治理单元基础信息管理
|
|||
|
|
- 流域特征参数计算和管理
|
|||
|
|
- 空间拓扑关系建立和维护
|
|||
|
|
|
|||
|
|
#### 监测站点信息集成
|
|||
|
|
|
|||
|
|
**雨量(水位)站点信息管理**:
|
|||
|
|
```java
|
|||
|
|
// 监测站点实体
|
|||
|
|
public class MonitoringStation {
|
|||
|
|
private Long id;
|
|||
|
|
private String stationCode; // 站点编码
|
|||
|
|
private String stationName; // 站点名称
|
|||
|
|
private String stationType; // 站点类型
|
|||
|
|
private BigDecimal longitude; // 经度
|
|||
|
|
private BigDecimal latitude; // 纬度
|
|||
|
|
private Geometry location; // 空间位置
|
|||
|
|
// ... 其他字段
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**站点关联管理**:
|
|||
|
|
- 空间关联:监测站点与小流域的空间关联
|
|||
|
|
- 数据关联:监测数据与小流域的数据关联
|
|||
|
|
- 状态监控:监测站点运行状态监控
|
|||
|
|
|
|||
|
|
#### 降雨预报成果数据集成
|
|||
|
|
|
|||
|
|
**网格化降雨预报数据**:
|
|||
|
|
```java
|
|||
|
|
// 降雨预报网格数据实体
|
|||
|
|
public class RainfallGrid {
|
|||
|
|
private Long id;
|
|||
|
|
private String gridCode; // 网格编码
|
|||
|
|
private BigDecimal rainfall; // 降雨量
|
|||
|
|
private String forecastTime; // 预报时间
|
|||
|
|
private Integer forecastHour; // 预报小时数
|
|||
|
|
private Geometry gridGeometry; // 网格几何
|
|||
|
|
// ... 其他字段
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**预报成果管理功能**:
|
|||
|
|
- 网格数据存储和管理
|
|||
|
|
- 时间序列预报数据管理
|
|||
|
|
- 空间插值和计算功能
|
|||
|
|
|
|||
|
|
#### 流域关系管理
|
|||
|
|
|
|||
|
|
**流域拓扑关系建立**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class WatershedRelationService {
|
|||
|
|
|
|||
|
|
public WatershedTopology buildTopology(List<WatershedUnit> units) {
|
|||
|
|
// 构建流域拓扑关系
|
|||
|
|
return topology;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public List<WatershedUnit> getUpstreamUnits(Long unitId) {
|
|||
|
|
// 获取上游流域单元
|
|||
|
|
return upstreamUnits;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public List<WatershedUnit> getDownstreamUnits(Long unitId) {
|
|||
|
|
// 获取下游流域单元
|
|||
|
|
return downstreamUnits;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**空间分析算法**:
|
|||
|
|
- 河流网络提取:基于DEM数据的河流网络提取
|
|||
|
|
- 流域边界识别:小流域边界的自动识别
|
|||
|
|
- 拓扑关系生成:上下游关系的自动生成
|
|||
|
|
|
|||
|
|
## 5.2 算法模型建设方案
|
|||
|
|
|
|||
|
|
### 5.2.1 模型建模范围确定
|
|||
|
|
|
|||
|
|
#### 小流域设计暴雨计算
|
|||
|
|
|
|||
|
|
**暴雨参数计算模型**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class DesignStormService {
|
|||
|
|
|
|||
|
|
public DesignStormResult calculateDesignStorm(String watershedCode,
|
|||
|
|
int returnPeriod) {
|
|||
|
|
// 基于《湖北省暴雨统计参数等值线图集》计算设计暴雨
|
|||
|
|
DesignStormResult result = new DesignStormResult();
|
|||
|
|
|
|||
|
|
// 计算标准历时点雨量均值
|
|||
|
|
BigDecimal tenMinMean = calculate10MinMean(watershedCode);
|
|||
|
|
BigDecimal oneHourMean = calculate1HourMean(watershedCode);
|
|||
|
|
BigDecimal sixHourMean = calculate6HourMean(watershedCode);
|
|||
|
|
BigDecimal twentyFourHourMean = calculate24HourMean(watershedCode);
|
|||
|
|
|
|||
|
|
// 计算设计暴雨
|
|||
|
|
result.setTenMinDesign(calculateDesignRainfall(tenMinMean, returnPeriod));
|
|||
|
|
result.setOneHourDesign(calculateDesignRainfall(oneHourMean, returnPeriod));
|
|||
|
|
result.setSixHourDesign(calculateDesignRainfall(sixHourMean, returnPeriod));
|
|||
|
|
result.setTwentyFourHourDesign(calculateDesignRainfall(twentyFourHourMean, returnPeriod));
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private BigDecimal calculateDesignRainfall(BigDecimal mean, int returnPeriod) {
|
|||
|
|
// 设计暴雨计算逻辑
|
|||
|
|
return mean.multiply(getFrequencyFactor(returnPeriod));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**暴雨时程分配模型**:
|
|||
|
|
- 时程分配模式:基于典型暴雨过程的时程分配
|
|||
|
|
- 时间步长处理:按小时或更小时间步长分配
|
|||
|
|
- 空间分布:考虑暴雨空间分布的不均匀性
|
|||
|
|
|
|||
|
|
#### 小流域设计洪水计算
|
|||
|
|
|
|||
|
|
**净雨计算模型**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class NetRainfallService {
|
|||
|
|
|
|||
|
|
public List<NetRainfall> calculateNetRainfall(DesignStormResult designStorm,
|
|||
|
|
WatershedUnit watershed) {
|
|||
|
|
// 净雨计算逻辑
|
|||
|
|
List<NetRainfall> netRainfallList = new ArrayList<>();
|
|||
|
|
|
|||
|
|
// 初损计算
|
|||
|
|
BigDecimal initialLoss = calculateInitialLoss(watershed);
|
|||
|
|
|
|||
|
|
// 下渗计算
|
|||
|
|
BigDecimal infiltrationRate = calculateInfiltrationRate(watershed);
|
|||
|
|
|
|||
|
|
// 净雨过程计算
|
|||
|
|
for (StormData stormData : designStorm.getStormData()) {
|
|||
|
|
NetRainfall netRainfall = new NetRainfall();
|
|||
|
|
netRainfall.setTime(stormData.getTime());
|
|||
|
|
netRainfall.setGrossRainfall(stormData.getRainfall());
|
|||
|
|
netRainfall.setNetRainfall(calculateNetAmount(
|
|||
|
|
stormData.getRainfall(), initialLoss, infiltrationRate));
|
|||
|
|
netRainfallList.add(netRainfall);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return netRainfallList;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**单位线法洪水计算**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class UnitHydrographService {
|
|||
|
|
|
|||
|
|
public FloodHydrograph calculateFloodHydrograph(List<NetRainfall> netRainfall,
|
|||
|
|
WatershedUnit watershed) {
|
|||
|
|
// 单位线法洪水计算
|
|||
|
|
FloodHydrograph hydrograph = new FloodHydrograph();
|
|||
|
|
|
|||
|
|
// 获取单位线
|
|||
|
|
UnitHydrograph unitHydrograph = getUnitHydrograph(watershed.getUnitCode());
|
|||
|
|
|
|||
|
|
// 卷积计算
|
|||
|
|
List<BigDecimal> discharge = new ArrayList<>();
|
|||
|
|
for (int i = 0; i < netRainfall.size(); i++) {
|
|||
|
|
BigDecimal q = BigDecimal.ZERO;
|
|||
|
|
for (int j = 0; j <= i; j++) {
|
|||
|
|
q = q.add(netRainfall.get(j).getNetRainfall()
|
|||
|
|
.multiply(unitHydrograph.getOrdinate(i - j)));
|
|||
|
|
}
|
|||
|
|
discharge.add(q);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
hydrograph.setDischarge(discharge);
|
|||
|
|
return hydrograph;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**经验公式法洪水计算**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class EmpiricalFormulaService {
|
|||
|
|
|
|||
|
|
public BigDecimal calculatePeakDischarge(WatershedUnit watershed,
|
|||
|
|
int returnPeriod) {
|
|||
|
|
// 经验公式法计算洪峰流量
|
|||
|
|
BigDecimal area = new BigDecimal(watershed.getArea());
|
|||
|
|
BigDecimal coefficient = getCoefficient(watershed, returnPeriod);
|
|||
|
|
BigDecimal exponent = getExponent(watershed);
|
|||
|
|
|
|||
|
|
// Q = C * A^n
|
|||
|
|
return coefficient.multiply(area.pow(exponent));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private BigDecimal getCoefficient(WatershedUnit watershed, int returnPeriod) {
|
|||
|
|
// 根据水文分区和重现期获取系数
|
|||
|
|
return coefficientRepository.findByWatershedAndReturnPeriod(
|
|||
|
|
watershed.getHydrologicalZone(), returnPeriod);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### HEC-RAS二维水动力学模型
|
|||
|
|
|
|||
|
|
**淹没范围分析模型**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class InundationAnalysisService {
|
|||
|
|
|
|||
|
|
public InundationResult analyzeInundation(WatershedUnit watershed,
|
|||
|
|
FloodHydrograph hydrograph, int returnPeriod) {
|
|||
|
|
// HEC-RAS二维水动力学模型调用
|
|||
|
|
InundationResult result = new InundationResult();
|
|||
|
|
|
|||
|
|
// 模型输入准备
|
|||
|
|
ModelInput input = prepareModelInput(watershed, hydrograph);
|
|||
|
|
|
|||
|
|
// 调用HEC-RAS模型
|
|||
|
|
ModelOutput output = callHECRASModel(input);
|
|||
|
|
|
|||
|
|
// 结果处理
|
|||
|
|
result.setInundationArea(output.getInundationArea());
|
|||
|
|
result.setMaxDepth(output.getMaxDepth());
|
|||
|
|
result.setInundationMap(output.getInundationMap());
|
|||
|
|
result.setVelocityMap(output.getVelocityMap());
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private ModelOutput callHECRASModel(ModelInput input) {
|
|||
|
|
// 调用HEC-RAS模型的实现
|
|||
|
|
// 这里可以集成外部HEC-RAS计算引擎
|
|||
|
|
return hcrasEngine.run(input);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**不同重现期洪水分析**:
|
|||
|
|
- 50年一遇洪水:中等风险洪水淹没分析
|
|||
|
|
- 100年一遇洪水:高风险洪水淹没分析
|
|||
|
|
- 300年一遇洪水:极高风险洪水淹没分析
|
|||
|
|
|
|||
|
|
### 5.2.2 小流域分布式水文模型精细建模
|
|||
|
|
|
|||
|
|
#### 小流域计算单元划分
|
|||
|
|
|
|||
|
|
**计算单元属性提取**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class CalculationUnitService {
|
|||
|
|
|
|||
|
|
public List<CalculationUnit> divideCalculationUnits(WatershedUnit watershed) {
|
|||
|
|
// 小流域计算单元划分
|
|||
|
|
List<CalculationUnit> units = new ArrayList<>();
|
|||
|
|
|
|||
|
|
// 基于DEM数据进行单元划分
|
|||
|
|
List<Subcatchment> subcatchments = extractSubcatchments(watershed);
|
|||
|
|
|
|||
|
|
for (Subcatchment subcatchment : subcatchments) {
|
|||
|
|
CalculationUnit unit = new CalculationUnit();
|
|||
|
|
unit.setUnitCode(generateUnitCode(subcatchment));
|
|||
|
|
unit.setArea(subcatchment.getArea());
|
|||
|
|
unit.setAvgSlope(calculateAvgSlope(subcatchment));
|
|||
|
|
unit.setFlowLength(calculateFlowLength(subcatchment));
|
|||
|
|
unit.setCentroid(subcatchment.getCentroid());
|
|||
|
|
unit.setBoundary(subcatchment.getBoundary());
|
|||
|
|
|
|||
|
|
// 提取其他属性
|
|||
|
|
unit.setLandUseType(extractLandUseType(subcatchment));
|
|||
|
|
unit.setSoilType(extractSoilType(subcatchment));
|
|||
|
|
unit.setVegetationCover(extractVegetationCover(subcatchment));
|
|||
|
|
|
|||
|
|
units.add(unit);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return units;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private BigDecimal calculateAvgSlope(Subcatchment subcatchment) {
|
|||
|
|
// 基于DEM计算平均坡度
|
|||
|
|
return demAnalyzer.calculateAvgSlope(subcatchment);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private BigDecimal calculateFlowLength(Subcatchment subcatchment) {
|
|||
|
|
// 计算流径长度
|
|||
|
|
return flowAnalyzer.calculateFlowLength(subcatchment);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**小流域统一编码**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class WatershedCodingService {
|
|||
|
|
|
|||
|
|
public String generateWatershedCode(WatershedUnit watershed) {
|
|||
|
|
// 小流域统一编码生成
|
|||
|
|
StringBuilder code = new StringBuilder();
|
|||
|
|
|
|||
|
|
// 省级编码
|
|||
|
|
code.append("42"); // 湖北省编码
|
|||
|
|
|
|||
|
|
// 市级编码
|
|||
|
|
code.append(String.format("%02d", watershed.getCityCode()));
|
|||
|
|
|
|||
|
|
// 县级编码
|
|||
|
|
code.append(String.format("%02d", watershed.getCountyCode()));
|
|||
|
|
|
|||
|
|
// 流域编码
|
|||
|
|
code.append(String.format("%03d", watershed.getRiverBasinCode()));
|
|||
|
|
|
|||
|
|
// 小流域编码
|
|||
|
|
code.append(String.format("%04d", watershed.getUnitNumber()));
|
|||
|
|
|
|||
|
|
return code.toString();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 面雨量权重值计算
|
|||
|
|
|
|||
|
|
**泰森多边形权重计算**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class ThiessenPolygonService {
|
|||
|
|
|
|||
|
|
public Map<String, BigDecimal> calculateThiessenWeights(
|
|||
|
|
List<MonitoringStation> stations, WatershedUnit watershed) {
|
|||
|
|
// 泰森多边形权重计算
|
|||
|
|
Map<String, BigDecimal> weights = new HashMap<>();
|
|||
|
|
|
|||
|
|
// 创建泰森多边形
|
|||
|
|
List<Polygon> thiessenPolygons = createThiessenPolygons(stations);
|
|||
|
|
|
|||
|
|
// 计算每个站点在流域内的权重
|
|||
|
|
Geometry watershedBoundary = watershed.getBoundary();
|
|||
|
|
for (int i = 0; i < stations.size(); i++) {
|
|||
|
|
Polygon stationPolygon = thiessenPolygons.get(i);
|
|||
|
|
|
|||
|
|
// 计算站点多边形与流域的交集
|
|||
|
|
Geometry intersection = stationPolygon.intersection(watershedBoundary);
|
|||
|
|
|
|||
|
|
// 计算权重
|
|||
|
|
BigDecimal stationArea = new BigDecimal(intersection.getArea());
|
|||
|
|
BigDecimal watershedArea = new BigDecimal(watershedBoundary.getArea());
|
|||
|
|
BigDecimal weight = stationArea.divide(watershedArea, 8, RoundingMode.HALF_UP);
|
|||
|
|
|
|||
|
|
weights.put(stations.get(i).getStationCode(), weight);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return weights;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private List<Polygon> createThiessenPolygons(List<MonitoringStation> stations) {
|
|||
|
|
// 创建泰森多边形
|
|||
|
|
// 使用JTS的Voronoi图算法
|
|||
|
|
GeometryFactory geometryFactory = new GeometryFactory();
|
|||
|
|
|
|||
|
|
// 创建站点点集
|
|||
|
|
Coordinate[] coordinates = stations.stream()
|
|||
|
|
.map(station -> station.getLocation().getCoordinate())
|
|||
|
|
.toArray(Coordinate[]::new);
|
|||
|
|
|
|||
|
|
// 生成Voronoi图
|
|||
|
|
VoronoiDiagramBuilder voronoiBuilder = new VoronoiDiagramBuilder();
|
|||
|
|
voronoiBuilder.setSites(coordinates);
|
|||
|
|
Geometry voronoiDiagram = voronoiBuilder.getDiagram(geometryFactory);
|
|||
|
|
|
|||
|
|
// 提取多边形
|
|||
|
|
return extractPolygons(voronoiDiagram);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**反距离权重插值**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class IDWInterpolationService {
|
|||
|
|
|
|||
|
|
public Map<String, BigDecimal> calculateIDWWeights(
|
|||
|
|
List<MonitoringStation> stations, WatershedUnit watershed) {
|
|||
|
|
// 反距离权重插值
|
|||
|
|
Map<String, BigDecimal> weights = new HashMap<>();
|
|||
|
|
|
|||
|
|
// 生成流域内网格点
|
|||
|
|
List<Coordinate> gridPoints = generateGridPoints(watershed);
|
|||
|
|
|
|||
|
|
for (Coordinate gridPoint : gridPoints) {
|
|||
|
|
BigDecimal totalWeight = BigDecimal.ZERO;
|
|||
|
|
BigDecimal weightedRainfall = BigDecimal.ZERO;
|
|||
|
|
|
|||
|
|
// 计算每个站点对网格点的权重
|
|||
|
|
for (MonitoringStation station : stations) {
|
|||
|
|
BigDecimal distance = calculateDistance(gridPoint,
|
|||
|
|
station.getLocation().getCoordinate());
|
|||
|
|
|
|||
|
|
// 避免除零错误
|
|||
|
|
if (distance.compareTo(BigDecimal.ZERO) == 0) {
|
|||
|
|
distance = new BigDecimal("0.0001");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 权重 = 1 / distance^2
|
|||
|
|
BigDecimal weight = BigDecimal.ONE.divide(
|
|||
|
|
distance.pow(2), 8, RoundingMode.HALF_UP);
|
|||
|
|
|
|||
|
|
totalWeight = totalWeight.add(weight);
|
|||
|
|
weightedRainfall = weightedRainfall.add(
|
|||
|
|
weight.multiply(station.getCurrentRainfall()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 计算网格点降雨量
|
|||
|
|
BigDecimal gridRainfall = weightedRainfall.divide(totalWeight,
|
|||
|
|
2, RoundingMode.HALF_UP);
|
|||
|
|
|
|||
|
|
weights.put(getGridPointCode(gridPoint), gridRainfall);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return weights;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 蒸散发量计算
|
|||
|
|
|
|||
|
|
**潜在蒸散发计算**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class EvapotranspirationService {
|
|||
|
|
|
|||
|
|
public BigDecimal calculatePET(EtData data) {
|
|||
|
|
// 潜在蒸散发计算(Penman-Monteith方程)
|
|||
|
|
BigDecimal delta = calculateSlopeVaporPressure(data.getTemperature());
|
|||
|
|
BigDecimal gamma = calculatePsychrometricConstant(data.getPressure());
|
|||
|
|
BigDecimal u2 = data.getWindSpeed();
|
|||
|
|
BigDecimal es = calculateSaturationVaporPressure(data.getTemperature());
|
|||
|
|
BigDecimal ea = calculateActualVaporPressure(data.getTemperature(),
|
|||
|
|
data.getRelativeHumidity());
|
|||
|
|
|
|||
|
|
BigDecimal rn = data.getNetRadiation();
|
|||
|
|
BigDecimal g = data.getSoilHeatFlux();
|
|||
|
|
|
|||
|
|
// Penman-Monteith方程
|
|||
|
|
BigDecimal numerator = delta.multiply(rn.subtract(g))
|
|||
|
|
.add(K_CONSTANT.multiply(rho_AIR.multiply(CP_AIR).multiply(u2)
|
|||
|
|
.multiply(es.subtract(ea))));
|
|||
|
|
|
|||
|
|
BigDecimal denominator = delta.add(gamma.multiply(
|
|||
|
|
BigDecimal.ONE.add(C_D_CONSTANT.multiply(u2))));
|
|||
|
|
|
|||
|
|
return numerator.divide(denominator, 2, RoundingMode.HALF_UP);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private BigDecimal calculateSlopeVaporPressure(BigDecimal temperature) {
|
|||
|
|
// 饱和水汽压斜率计算
|
|||
|
|
BigDecimal temp = temperature.add(BigDecimal.valueOf(237.3));
|
|||
|
|
BigDecimal numerator = BigDecimal.valueOf(4098).multiply(
|
|||
|
|
BigDecimal.valueOf(0.6108).multiply(
|
|||
|
|
BigDecimal.valueOf(17.27).multiply(temperature).divide(temp,
|
|||
|
|
8, RoundingMode.HALF_UP).exp()));
|
|||
|
|
BigDecimal denominator = temp.pow(2);
|
|||
|
|
return numerator.divide(denominator, 8, RoundingMode.HALF_UP);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**实际蒸散发计算**:
|
|||
|
|
```java
|
|||
|
|
public BigDecimal calculateAET(BigDecimal pet, BigDecimal soilMoisture,
|
|||
|
|
BigDecimal fieldCapacity) {
|
|||
|
|
// 实际蒸散发计算
|
|||
|
|
BigDecimal moistureRatio = soilMoisture.divide(fieldCapacity,
|
|||
|
|
8, RoundingMode.HALF_UP);
|
|||
|
|
|
|||
|
|
if (moistureRatio.compareTo(BigDecimal.ONE) >= 0) {
|
|||
|
|
return pet; // 土壤水分充足,实际蒸散发等于潜在蒸散发
|
|||
|
|
} else {
|
|||
|
|
// 土壤水分不足,按比例减少
|
|||
|
|
return pet.multiply(moistureRatio);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 产流模型参数确定
|
|||
|
|
|
|||
|
|
**SCS-CN产流模型**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class SCSModelService {
|
|||
|
|
|
|||
|
|
public BigDecimal calculateSCSRunoff(BigDecimal rainfall,
|
|||
|
|
BigDecimal cn, BigDecimal initialAbstraction) {
|
|||
|
|
// SCS-CN产流模型
|
|||
|
|
BigDecimal s = BigDecimal.valueOf(25400).divide(cn,
|
|||
|
|
8, RoundingMode.HALF_UP).subtract(BigDecimal.valueOf(254));
|
|||
|
|
|
|||
|
|
BigDecimal ia = initialAbstraction.multiply(s);
|
|||
|
|
|
|||
|
|
if (rainfall.compareTo(ia) <= 0) {
|
|||
|
|
return BigDecimal.ZERO; // 降雨小于初损,无产流
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
BigDecimal numerator = rainfall.subtract(ia).pow(2);
|
|||
|
|
BigDecimal denominator = rainfall.subtract(ia).add(s);
|
|||
|
|
|
|||
|
|
return numerator.divide(denominator, 2, RoundingMode.HALF_UP);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public BigDecimal calculateCNValue(LandUseType landUse, SoilType soil,
|
|||
|
|
BigDecimal antecedentMoisture) {
|
|||
|
|
// CN值计算
|
|||
|
|
// 基于土地利用类型、土壤类型和前期湿度条件
|
|||
|
|
return cnTableRepository.findByLandUseAndSoil(landUse, soil, antecedentMoisture);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Green-Ampt渗透模型**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class GreenAmptService {
|
|||
|
|
|
|||
|
|
public BigDecimal calculateInfiltration(BigDecimal time, BigDecimal initialMoisture,
|
|||
|
|
BigDecimal saturatedMoisture, BigDecimal hydraulicConductivity,
|
|||
|
|
BigDecimal suctionHead, BigDecimal cumulativeInfiltration) {
|
|||
|
|
// Green-Ampt渗透模型
|
|||
|
|
BigDecimal thetaS = saturatedMoisture;
|
|||
|
|
BigDecimal thetaI = initialMoisture;
|
|||
|
|
BigDecimal deltaTheta = thetaS.subtract(thetaI);
|
|||
|
|
|
|||
|
|
BigDecimal Ks = hydraulicConductivity;
|
|||
|
|
BigDecimal psi = suctionHead;
|
|||
|
|
BigDecimal F = cumulativeInfiltration;
|
|||
|
|
|
|||
|
|
// Green-Ampt方程
|
|||
|
|
BigDecimal numerator = Ks.multiply(time).multiply(deltaTheta).multiply(psi).add(F);
|
|||
|
|
BigDecimal denominator = F.add(Ks.multiply(time).multiply(deltaTheta));
|
|||
|
|
|
|||
|
|
BigDecimal newF = numerator.divide(denominator, 8, RoundingMode.HALF_UP);
|
|||
|
|
|
|||
|
|
return newF.subtract(F); // 当前时段渗透量
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 单位线提取
|
|||
|
|
|
|||
|
|
**瞬时单位线计算**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class InstantaneousUnitHydrographService {
|
|||
|
|
|
|||
|
|
public List<BigDecimal> calculateIUH(WatershedUnit watershed,
|
|||
|
|
List<CalculationUnit> units) {
|
|||
|
|
// 瞬时单位线计算
|
|||
|
|
List<BigDecimal> iuh = new ArrayList<>();
|
|||
|
|
|
|||
|
|
// 计算流域特征参数
|
|||
|
|
BigDecimal avgSlope = calculateAvgSlope(units);
|
|||
|
|
BigDecimal avgFlowLength = calculateAvgFlowLength(units);
|
|||
|
|
BigDecimal avgVelocity = calculateAvgVelocity(avgSlope);
|
|||
|
|
|
|||
|
|
// 计算汇流时间
|
|||
|
|
BigDecimal tc = avgFlowLength.divide(avgVelocity,
|
|||
|
|
8, RoundingMode.HALF_UP);
|
|||
|
|
|
|||
|
|
// Nash瞬时单位线模型
|
|||
|
|
int n = 2; // 线性水库数
|
|||
|
|
BigDecimal k = tc.divide(BigDecimal.valueOf(n),
|
|||
|
|
8, RoundingMode.HALF_UP); // 水库蓄量常数
|
|||
|
|
|
|||
|
|
// 生成单位线纵坐标
|
|||
|
|
for (int t = 0; t < 100; t++) {
|
|||
|
|
BigDecimal ordinate = calculateNashIUHOrdinate(t, n, k);
|
|||
|
|
iuh.add(ordinate);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return iuh;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private BigDecimal calculateNashIUHOrdinate(int t, int n, BigDecimal k) {
|
|||
|
|
// Nash瞬时单位线纵坐标计算
|
|||
|
|
if (t == 0) return BigDecimal.ZERO;
|
|||
|
|
|
|||
|
|
BigDecimal numerator = BigDecimal.ONE.pow(n - 1);
|
|||
|
|
BigDecimal denominator = BigDecimal.valueOf(factorial(n - 1))
|
|||
|
|
.multiply(k.pow(n));
|
|||
|
|
|
|||
|
|
BigDecimal timeTerm = BigDecimal.valueOf(t).pow(n - 1);
|
|||
|
|
BigDecimal expTerm = BigDecimal.valueOf(-t).divide(k,
|
|||
|
|
8, RoundingMode.HALF_UP).exp();
|
|||
|
|
|
|||
|
|
return numerator.multiply(timeTerm).multiply(expTerm).divide(denominator,
|
|||
|
|
8, RoundingMode.HALF_UP);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 河道演进模型参数确定
|
|||
|
|
|
|||
|
|
**马斯京根法河道演进**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class MuskingumRoutingService {
|
|||
|
|
|
|||
|
|
public List<BigDecimal> routeFloodWave(List<BigDecimal> inflow,
|
|||
|
|
BigDecimal k, BigDecimal x, BigDecimal dt) {
|
|||
|
|
// 马斯京根法河道演进
|
|||
|
|
List<BigDecimal> outflow = new ArrayList<>();
|
|||
|
|
|
|||
|
|
// 计算演进系数
|
|||
|
|
BigDecimal c0 = calculateC0(k, x, dt);
|
|||
|
|
BigDecimal c1 = calculateC1(k, x, dt);
|
|||
|
|
BigDecimal c2 = calculateC2(k, x, dt);
|
|||
|
|
|
|||
|
|
// 初始条件
|
|||
|
|
outflow.add(inflow.get(0)); // 假设初始出流等于入流
|
|||
|
|
|
|||
|
|
// 演进计算
|
|||
|
|
for (int i = 1; i < inflow.size(); i++) {
|
|||
|
|
BigDecimal qOut = c0.multiply(inflow.get(i))
|
|||
|
|
.add(c1.multiply(inflow.get(i - 1)))
|
|||
|
|
.add(c2.multiply(outflow.get(i - 1)));
|
|||
|
|
|
|||
|
|
outflow.add(qOut);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return outflow;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private BigDecimal calculateC0(BigDecimal k, BigDecimal x, BigDecimal dt) {
|
|||
|
|
BigDecimal denominator = k.multiply(BigDecimal.valueOf(2).multiply(x).subtract(BigDecimal.ONE))
|
|||
|
|
.add(dt);
|
|||
|
|
return dt.subtract(k.multiply(x)).divide(denominator,
|
|||
|
|
8, RoundingMode.HALF_UP);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private BigDecimal calculateC1(BigDecimal k, BigDecimal x, BigDecimal dt) {
|
|||
|
|
BigDecimal denominator = k.multiply(BigDecimal.valueOf(2).multiply(x).subtract(BigDecimal.ONE))
|
|||
|
|
.add(dt);
|
|||
|
|
return dt.add(k.multiply(x)).divide(denominator,
|
|||
|
|
8, RoundingMode.HALF_UP);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private BigDecimal calculateC2(BigDecimal k, BigDecimal x, BigDecimal dt) {
|
|||
|
|
BigDecimal denominator = k.multiply(BigDecimal.valueOf(2).multiply(x).subtract(BigDecimal.ONE))
|
|||
|
|
.add(dt);
|
|||
|
|
return BigDecimal.ONE.subtract(denominator).divide(denominator,
|
|||
|
|
8, RoundingMode.HALF_UP);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.3 预警功能设计
|
|||
|
|
|
|||
|
|
### 5.3.1 动态预警指标设计
|
|||
|
|
|
|||
|
|
**预警规则配置模型**:
|
|||
|
|
```java
|
|||
|
|
// 预警规则实体
|
|||
|
|
public class OsmoticWarnRule {
|
|||
|
|
private Long id;
|
|||
|
|
private String ruleName; // 规则名称
|
|||
|
|
private String ruleType; // 规则类型:1-渗压,2-渗流,3-位移
|
|||
|
|
private String deviceCode; // 设备编码
|
|||
|
|
private BigDecimal threshold1; // 一级阈值
|
|||
|
|
private BigDecimal threshold2; // 二级阈值
|
|||
|
|
private BigDecimal threshold3; // 三级阈值
|
|||
|
|
private String logicRelation; // 逻辑关系:AND/OR
|
|||
|
|
private Integer status; // 状态:0-禁用,1-启用
|
|||
|
|
// ... 其他字段
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**预警条件判断算法**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class WarningRuleService {
|
|||
|
|
|
|||
|
|
public WarningResult evaluateWarningRules(List<OsmoticWarnRule> rules,
|
|||
|
|
Map<String, BigDecimal> sensorData) {
|
|||
|
|
WarningResult result = new WarningResult();
|
|||
|
|
List<WarningEvent> events = new ArrayList<>();
|
|||
|
|
|
|||
|
|
for (OsmoticWarnRule rule : rules) {
|
|||
|
|
if (rule.getStatus() == 0) continue; // 跳过禁用规则
|
|||
|
|
|
|||
|
|
BigDecimal currentValue = sensorData.get(rule.getDeviceCode());
|
|||
|
|
if (currentValue == null) continue;
|
|||
|
|
|
|||
|
|
// 评估预警级别
|
|||
|
|
int level = evaluateWarningLevel(rule, currentValue);
|
|||
|
|
if (level > 0) {
|
|||
|
|
WarningEvent event = new WarningEvent();
|
|||
|
|
event.setRuleId(rule.getId());
|
|||
|
|
event.setRuleName(rule.getRuleName());
|
|||
|
|
event.setLevel(level);
|
|||
|
|
event.setCurrentValue(currentValue);
|
|||
|
|
event.setThreshold(getThresholdForLevel(rule, level));
|
|||
|
|
event.setTimestamp(LocalDateTime.now());
|
|||
|
|
|
|||
|
|
events.add(event);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result.setEvents(events);
|
|||
|
|
result.setHasWarning(!events.isEmpty());
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private int evaluateWarningLevel(OsmoticWarnRule rule, BigDecimal value) {
|
|||
|
|
if (rule.getThreshold3() != null && value.compareTo(rule.getThreshold3()) > 0) {
|
|||
|
|
return 3; // 三级预警
|
|||
|
|
} else if (rule.getThreshold2() != null && value.compareTo(rule.getThreshold2()) > 0) {
|
|||
|
|
return 2; // 二级预警
|
|||
|
|
} else if (rule.getThreshold1() != null && value.compareTo(rule.getThreshold1()) > 0) {
|
|||
|
|
return 1; // 一级预警
|
|||
|
|
}
|
|||
|
|
return 0; // 无预警
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.3.2 预警发布系统设计
|
|||
|
|
|
|||
|
|
**预警消息管理**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class MessageCenterService {
|
|||
|
|
|
|||
|
|
public void publishWaterLevelWarning(List<StRsvrR> waterLevelData) {
|
|||
|
|
// 水位预警发布
|
|||
|
|
for (StRsvrR data : waterLevelData) {
|
|||
|
|
// 检查水位预警条件
|
|||
|
|
if (checkWaterLevelWarning(data)) {
|
|||
|
|
MessageCenter message = new MessageCenter();
|
|||
|
|
message.setTitle("水位预警");
|
|||
|
|
message.setContent(String.format("%s水库水位预警:当前水位%.2fm,超过警戒水位",
|
|||
|
|
data.getStnm(), data.getRz()));
|
|||
|
|
message.setWarningLevel(calculateWarningLevel(data));
|
|||
|
|
message.setStationCode(data.getStcd());
|
|||
|
|
message.setCreateTime(LocalDateTime.now());
|
|||
|
|
message.setStatus(0); // 未读状态
|
|||
|
|
|
|||
|
|
// 保存预警消息
|
|||
|
|
save(message);
|
|||
|
|
|
|||
|
|
// 推送给相关用户
|
|||
|
|
pushToUsers(message);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void publishOsmoticWarning(OsmoticWarnR warnData, String description) {
|
|||
|
|
// 渗压预警发布
|
|||
|
|
MessageCenter message = new MessageCenter();
|
|||
|
|
message.setTitle("渗压预警");
|
|||
|
|
message.setContent(String.format("%s渗压预警:%s",
|
|||
|
|
warnData.getDeviceName(), description));
|
|||
|
|
message.setWarningLevel(warnData.getWarningLevel());
|
|||
|
|
message.setDeviceCode(warnData.getDeviceCode());
|
|||
|
|
message.setCreateTime(LocalDateTime.now());
|
|||
|
|
message.setStatus(0);
|
|||
|
|
|
|||
|
|
save(message);
|
|||
|
|
pushToUsers(message);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**用户推送机制**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class UserPushService {
|
|||
|
|
|
|||
|
|
public void pushToUsers(MessageCenter message) {
|
|||
|
|
// 根据预警级别和用户角色推送消息
|
|||
|
|
List<User> targetUsers = getTargetUsers(message);
|
|||
|
|
|
|||
|
|
for (User user : targetUsers) {
|
|||
|
|
// 创建用户消息记录
|
|||
|
|
UserMessage userMessage = new UserMessage();
|
|||
|
|
userMessage.setUserId(user.getId());
|
|||
|
|
userMessage.setMessageId(message.getId());
|
|||
|
|
userMessage.setReadStatus(0); // 未读状态
|
|||
|
|
userMessage.setPushTime(LocalDateTime.now());
|
|||
|
|
|
|||
|
|
userMessageRepository.save(userMessage);
|
|||
|
|
|
|||
|
|
// 实时推送(WebSocket或其他推送机制)
|
|||
|
|
if (user.isOnline()) {
|
|||
|
|
pushRealTimeNotification(user, message);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private List<User> getTargetUsers(MessageCenter message) {
|
|||
|
|
// 根据预警级别确定目标用户
|
|||
|
|
switch (message.getWarningLevel()) {
|
|||
|
|
case 3: // 三级预警(最高级别)
|
|||
|
|
return userRepository.findByRoleIn(Arrays.asList("ADMIN", "COUNTY_MANAGER"));
|
|||
|
|
case 2: // 二级预警
|
|||
|
|
return userRepository.findByRole("COUNTY_MANAGER");
|
|||
|
|
case 1: // 一级预警
|
|||
|
|
return userRepository.findByRoleIn(Arrays.asList("COUNTY_MANAGER", "FIELD_STAFF"));
|
|||
|
|
default:
|
|||
|
|
return Collections.emptyList();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.3.3 预警统计分析
|
|||
|
|
|
|||
|
|
**预警统计服务**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class WarningStatisticsService {
|
|||
|
|
|
|||
|
|
public WarningStatistics getMonthlyStatistics(int year, int month) {
|
|||
|
|
// 月度预警统计
|
|||
|
|
WarningStatistics stats = new WarningStatistics();
|
|||
|
|
|
|||
|
|
// 查询当月预警数据
|
|||
|
|
List<MessageCenter> warnings = messageCenterRepository
|
|||
|
|
.findByYearAndMonth(year, month);
|
|||
|
|
|
|||
|
|
// 按类型统计
|
|||
|
|
stats.setWaterLevelCount(warnings.stream()
|
|||
|
|
.filter(w -> "水位预警".equals(w.getTitle()))
|
|||
|
|
.count());
|
|||
|
|
|
|||
|
|
stats.setOsmoticCount(warnings.stream()
|
|||
|
|
.filter(w -> "渗压预警".equals(w.getTitle()))
|
|||
|
|
.count());
|
|||
|
|
|
|||
|
|
// 按级别统计
|
|||
|
|
stats.setLevel1Count(warnings.stream()
|
|||
|
|
.filter(w -> w.getWarningLevel() == 1)
|
|||
|
|
.count());
|
|||
|
|
|
|||
|
|
stats.setLevel2Count(warnings.stream()
|
|||
|
|
.filter(w -> w.getWarningLevel() == 2)
|
|||
|
|
.count());
|
|||
|
|
|
|||
|
|
stats.setLevel3Count(warnings.stream()
|
|||
|
|
.filter(w -> w.getWarningLevel() == 3)
|
|||
|
|
.count());
|
|||
|
|
|
|||
|
|
return stats;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public List<WarningTrend> getWarningTrend(int days) {
|
|||
|
|
// 预警趋势分析
|
|||
|
|
List<WarningTrend> trends = new ArrayList<>();
|
|||
|
|
|
|||
|
|
LocalDate endDate = LocalDate.now();
|
|||
|
|
LocalDate startDate = endDate.minusDays(days);
|
|||
|
|
|
|||
|
|
for (LocalDate date = startDate; date.isBefore(endDate); date = date.plusDays(1)) {
|
|||
|
|
WarningTrend trend = new WarningTrend();
|
|||
|
|
trend.setDate(date);
|
|||
|
|
trend.setCount(messageCenterRepository.countByDate(date));
|
|||
|
|
trends.add(trend);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return trends;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 5.4 县级用户功能设计
|
|||
|
|
|
|||
|
|
### 5.4.1 考核管理系统
|
|||
|
|
|
|||
|
|
**考核任务工作流程**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class AssessTaskService {
|
|||
|
|
|
|||
|
|
public AssessTask createTask(AssessTaskDTO dto) {
|
|||
|
|
// 创建考核任务
|
|||
|
|
AssessTask task = new AssessTask();
|
|||
|
|
BeanUtils.copyProperties(dto, task);
|
|||
|
|
task.setStatus(0); // 未启动状态
|
|||
|
|
task.setCreateTime(LocalDateTime.now());
|
|||
|
|
|
|||
|
|
// 分配考核对象
|
|||
|
|
List<AssessObject> objects = assessObjectRepository.findByRegion(dto.getRegion());
|
|||
|
|
task.setAssessObjects(objects);
|
|||
|
|
|
|||
|
|
// 设置考核指标
|
|||
|
|
List<AssessIndicator> indicators = assessIndicatorRepository.findByTaskType(dto.getTaskType());
|
|||
|
|
task.setIndicators(indicators);
|
|||
|
|
|
|||
|
|
return assessTaskRepository.save(task);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Transactional
|
|||
|
|
public String startTask(Long taskId) {
|
|||
|
|
// 启动考核任务
|
|||
|
|
AssessTask task = assessTaskRepository.findById(taskId)
|
|||
|
|
.orElseThrow(() -> new RuntimeException("任务不存在"));
|
|||
|
|
|
|||
|
|
if (task.getStatus() != 0) {
|
|||
|
|
throw new RuntimeException("任务状态不允许启动");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
task.setStatus(1); // 进行中状态
|
|||
|
|
task.setStartTime(LocalDateTime.now());
|
|||
|
|
|
|||
|
|
// 通知考核对象
|
|||
|
|
notifyAssessObjects(task);
|
|||
|
|
|
|||
|
|
assessTaskRepository.save(task);
|
|||
|
|
return "任务启动成功";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public List<AssessTask> getPendingTasks(Long userId) {
|
|||
|
|
// 获取用户待办任务
|
|||
|
|
User user = userRepository.findById(userId)
|
|||
|
|
.orElseThrow(() -> new RuntimeException("用户不存在"));
|
|||
|
|
|
|||
|
|
return assessTaskRepository.findByAssessorAndStatus(user, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public List<AssessResultVo> getResult(Long taskId) {
|
|||
|
|
// 获取考核结果
|
|||
|
|
AssessTask task = assessTaskRepository.findById(taskId)
|
|||
|
|
.orElseThrow(() -> new RuntimeException("任务不存在"));
|
|||
|
|
|
|||
|
|
List<AssessResult> results = assessResultRepository.findByTaskId(taskId);
|
|||
|
|
|
|||
|
|
return results.stream().map(result -> {
|
|||
|
|
AssessResultVo vo = new AssessResultVo();
|
|||
|
|
vo.setObjectName(result.getObjectName());
|
|||
|
|
vo.setIndicatorName(result.getIndicatorName());
|
|||
|
|
vo.setScore(result.getScore());
|
|||
|
|
vo.setComment(result.getComment());
|
|||
|
|
return vo;
|
|||
|
|
}).collect(Collectors.toList());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**考核对象管理**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class AssessObjectService {
|
|||
|
|
|
|||
|
|
public List<AssessObject> getObjectsByRegion(String region) {
|
|||
|
|
// 按区域获取考核对象
|
|||
|
|
return assessObjectRepository.findByRegion(region);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public List<AssessObject> getObjectsByType(String objectType) {
|
|||
|
|
// 按类型获取考核对象
|
|||
|
|
return assessObjectRepository.findByObjectType(objectType);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void assignToTask(Long taskId, List<Long> objectIds) {
|
|||
|
|
// 分配考核对象到任务
|
|||
|
|
AssessTask task = assessTaskRepository.findById(taskId)
|
|||
|
|
.orElseThrow(() -> new RuntimeException("任务不存在"));
|
|||
|
|
|
|||
|
|
List<AssessObject> objects = assessObjectRepository.findByIdIn(objectIds);
|
|||
|
|
task.setAssessObjects(objects);
|
|||
|
|
|
|||
|
|
assessTaskRepository.save(task);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.4.2 权限管理系统
|
|||
|
|
|
|||
|
|
**基于角色的权限控制**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class PermissionService {
|
|||
|
|
|
|||
|
|
public boolean hasPermission(Long userId, String permission) {
|
|||
|
|
// 检查用户权限
|
|||
|
|
User user = userRepository.findById(userId)
|
|||
|
|
.orElseThrow(() -> new RuntimeException("用户不存在"));
|
|||
|
|
|
|||
|
|
return user.getRoles().stream()
|
|||
|
|
.flatMap(role -> role.getPermissions().stream())
|
|||
|
|
.anyMatch(p -> p.getCode().equals(permission));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public List<String> getUserPermissions(Long userId) {
|
|||
|
|
// 获取用户权限列表
|
|||
|
|
User user = userRepository.findById(userId)
|
|||
|
|
.orElseThrow(() -> new RuntimeException("用户不存在"));
|
|||
|
|
|
|||
|
|
return user.getRoles().stream()
|
|||
|
|
.flatMap(role -> role.getPermissions().stream())
|
|||
|
|
.map(Permission::getCode)
|
|||
|
|
.distinct()
|
|||
|
|
.collect(Collectors.toList());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.5 系统改进功能
|
|||
|
|
|
|||
|
|
### 5.5.1 防治点管理
|
|||
|
|
|
|||
|
|
**防治点树形结构管理**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class PrePlaceService {
|
|||
|
|
|
|||
|
|
public List<PrePlaceTreeVo> getPlaceTree() {
|
|||
|
|
// 获取防治点树形结构
|
|||
|
|
List<PrePlace> places = prePlaceRepository.findAllByOrderByParentIdAsc();
|
|||
|
|
|
|||
|
|
return buildTree(places, null);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private List<PrePlaceTreeVo> buildTree(List<PrePlace> places, Long parentId) {
|
|||
|
|
List<PrePlaceTreeVo> tree = new ArrayList<>();
|
|||
|
|
|
|||
|
|
for (PrePlace place : places) {
|
|||
|
|
if ((parentId == null && place.getParentId() == null) ||
|
|||
|
|
(parentId != null && parentId.equals(place.getParentId()))) {
|
|||
|
|
|
|||
|
|
PrePlaceTreeVo vo = new PrePlaceTreeVo();
|
|||
|
|
vo.setId(place.getId());
|
|||
|
|
vo.setName(place.getPlaceName());
|
|||
|
|
vo.setCode(place.getPlaceCode());
|
|||
|
|
vo.setType(place.getPlaceType());
|
|||
|
|
vo.setChildren(buildTree(places, place.getId()));
|
|||
|
|
|
|||
|
|
tree.add(vo);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return tree;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public List<PrePlaceDetail> getPlaceDetails(Long placeId) {
|
|||
|
|
// 获取防治点详细信息
|
|||
|
|
return prePlaceDetailRepository.findByPlaceId(placeId);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.5.2 维护管理功能
|
|||
|
|
|
|||
|
|
**维护计划管理**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class MentenancePlanService {
|
|||
|
|
|
|||
|
|
public MentenancePlan createAnnualPlan(MentenancePlanDTO dto) {
|
|||
|
|
// 创建年度维护计划
|
|||
|
|
MentenancePlan plan = new MentenancePlan();
|
|||
|
|
BeanUtils.copyProperties(dto, plan);
|
|||
|
|
plan.setStatus(0); // 未启动状态
|
|||
|
|
plan.setCreateTime(LocalDateTime.now());
|
|||
|
|
|
|||
|
|
// 创建维护详情
|
|||
|
|
List<MentencePlanDetail> details = dto.getDetails().stream()
|
|||
|
|
.map(detailDto -> {
|
|||
|
|
MentenancePlanDetail detail = new MentenancePlanDetail();
|
|||
|
|
BeanUtils.copyProperties(detailDto, detail);
|
|||
|
|
detail.setPlan(plan);
|
|||
|
|
return detail;
|
|||
|
|
})
|
|||
|
|
.collect(Collectors.toList());
|
|||
|
|
|
|||
|
|
plan.setDetails(details);
|
|||
|
|
|
|||
|
|
return mentenancePlanRepository.save(plan);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void updatePlanStatus(Long planId, Integer status) {
|
|||
|
|
// 更新计划状态
|
|||
|
|
MentenancePlan plan = mentenancePlanRepository.findById(planId)
|
|||
|
|
.orElseThrow(() -> new RuntimeException("计划不存在"));
|
|||
|
|
|
|||
|
|
plan.setStatus(status);
|
|||
|
|
if (status == 1) {
|
|||
|
|
plan.setStartTime(LocalDateTime.now());
|
|||
|
|
} else if (status == 2) {
|
|||
|
|
plan.setEndTime(LocalDateTime.now());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mentenancePlanRepository.save(plan);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这些功能设计完整地覆盖了黑石咀水库系统的核心业务需求,包括基础数据管理、算法模型建设、预警功能、县级用户管理和系统改进功能,为系统的开发和实施提供了详细的技术指导。
|