例行早会7 月 27 日完整整理
一、新人介绍
二、内网本地 GLM 大模型资源说明
三、各实习生上周五工作汇报 + 今日工作计划
- 上周五:完成本地开发环境搭建,Redis、ES 数据库配置完成,导入测试数据,项目可正常运行;
- 今日计划:分两阶段研读项目源码 ① 上午:熟悉整体架构,阅读启动类 Application、各项目配置、前端路由,梳理系统页面结构; ② 下午:深耕告警核心业务模块,学习告警模型 / 规则管理 Controller、Service,重点研究计算引擎、规则引擎,梳理定时任务调度与接口; ③ 配套动作:梳理代码调用链路,遇无法解决问题及时请教老师,同步记录架构、业务笔记便于复盘。
- 上周五:参与需求会议,设计通用 JSON 格式、开发个人信息模块,现存问题已同步金哥;
- 今日计划:开会讨论现存模块问题。
- 上周五:同步参与需求会议,完成 MD 转 JSON 标准化模板开发,以数据驱动转换;
- 今日计划:随小组开会沟通模块问题。
- 上周五:参会确定开发方向 —— 对外提供第三方 API;需求背景:胜利油田仅有原始数据,研发人员成果数据分散杂乱,计划依托当前项目搭建统一成果数据库,先以舒华总项目作为示范接口展示,后续全油田推广;梳理接口开发所需字段、数据格式等基础信息;
- 今日计划:完善需求方案设计。
- 上周五:修复清单页面按钮失效问题;收到王老需求:设计请假单类业务流程图流转逻辑;
- 今日计划:思考流程图业务设计方案。
- 上周五:完成环境配置、数据导入,初步熟悉功能模块划分;
- 今日计划:研读前后端代码、排查代码问题,绘制系统架构图。
- 上周五:完成手动、AI 生成两种模式的 RPA 脚本录制,熟悉整体业务流程;
- 今日计划:排查 RPA 脚本执行失败问题,区分是环境配置问题还是项目原生 Bug。
四、后续早会制度调整安排
五、其他事务通知
六、本周工作重点要求
- 若仅完成单一小功能(如单接口开发)虽上手快,但容易只懂单点、不懂整体;
- 建议开发前主动和导师沟通业务设计逻辑,理解功能开发的目的与业务价值;
- 技术编码难度较低,实习核心学习价值在于系统整体设计思路,切勿只追求完成代码。
工作内容
看代码文件
第一阶段【架构路由部分】
启动类 : BusinessRunApplication.java – 了解组件扫描和配置
BusinessRunApplication.java
package cn.com.xxx.bussiness;
import cn.com.xxx.boot.core.web.JsonMessage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
/**
* 项目启动类 – 集成计算引擎和定时任务
*
* @author nick
* @date 2025/10/27 10:26
* @since 4.4.3
*/
@SpringBootApplication(exclude = {
MybatisAutoConfiguration.class,
MybatisPlusAutoConfiguration.class
})
@EnableScheduling // 启用定时任务支持
@ComponentScan(basePackages = { "cn.com.xxx.bussiness", "cn.com.xxx.calculation",
"cn.com.xxx.bussiness.znyw.engine", "cn.com.xxx.bussiness.znyw.Log" }) // 扫描calculation包
@RequestMapping
//@CrossOrigin(origins = { "*","http://localhost:8090", "http://localhost:63342", "http://127.0.0.1:63342",
// "http://localhost:3000", "http://localhost:8080" })
@CrossOrigin(origins = { "*" })
public class BusinessRunApplication {
public static void main(String[] args) {
// 禁用JMX以避免检索问题
System.setProperty("spring.jmx.enabled", "false");
System.setProperty("management.endpoints.jmx.exposure.include", "");
SpringApplication.run(BusinessRunApplication.class, args);
}
/*
* @GetMapping("/")
*
* @ResponseBody
* public JsonMessage main(){
* return new JsonMessage().success("main");
* }
*/
}
代码完整逐段讲解
这是一套SpringBoot 微服务启动类,整合定时任务、跨域配置、自定义包扫描、排除 MyBatis 自动装配、关闭 JMX 监控等企业级配置,下面分包【package】、导入【import】、注解【@】、类【class】、main 方法、测试接口六部分拆解。
一、包定义
package cn.com.xxx.business;
-
规范:cn.com.xxx 代表xxx企业项目;
-
bussiness 业务模块包,当前启动类属于业务服务;
二、import 导入类说明
1. 框架核心
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
SpringBoot 启动器核心类,所有 Boot 项目必备。
2. 数据库自动配置
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
Spring 原生数据源、事务、JPA 自动装配类,本项目没有排除这几个,说明项目没有完全屏蔽原生 JDBC。
3. Web 统一返回体
import cn.com.xxx.boot.core.web.JsonMessage;
企业内部通用返回工具类,接口统一返回 JsonMessage(包含 code、msg、data,标准前后端交互格式)。
4. 定时任务
import org.springframework.scheduling.annotation.EnableScheduling;
开启 Spring 定时任务能力,配合@Scheduled注解实现定时调度。
5. Controller Web 注解
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
Web 控制器注解,用于写接口、跨域、路径映射。
6. MyBatis / MyBatisPlus 自动装配类
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
MyBatis、MyBatis-Plus 官方自动配置类,代码中主动排除了这两个自动装配。
三、类上注解(核心重点)
1. @SpringBootApplication(exclude = {})
@SpringBootApplication(exclude = {
MybatisAutoConfiguration.class,
MybatisPlusAutoConfiguration.class
})
@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan
-
作用:SpringBoot 启动核心注解,自动加载框架自动配置;
-
exclude 排除配置:禁用 MyBatis、MyBatis-Plus 的自动装配 场景解释:
-
项目可能手动自定义 MyBatis 配置(自己写 MapperScan、SqlSessionFactory),防止框架自动配置冲突;
-
多数据源场景,屏蔽自动装配避免数据源创建冲突;
-
部分模块临时不需要数据库操作,直接屏蔽 ORM 框架。
2. @EnableScheduling
@EnableScheduling // 启用定时任务支持
开启 Spring 内置定时任务,开启后项目中任意@Component类可以使用:
@Scheduled(cron = "0 0 1 * * ?")
public void task(){}
实现定时执行业务(数据计算、报表生成、巡检等,匹配项目calculation计算引擎包)。
3. @ComponentScan(basePackages = {})
@ComponentScan(basePackages = {
"cn.com.xxx.bussiness",
"cn.com.xxx.calculation",
"cn.com.xxx.bussiness.znyw.engine",
"cn.com.xxx.bussiness.znyw.Log"
})
自定义 Spring Bean 扫描范围,覆盖 4 个业务包:
cn.com.xxx.bussiness:当前业务主模块;
cn.com.xxx.calculation:独立计算引擎模块(项目核心,做数据运算、模型计算);
znyw.engine:智能业务引擎;
znyw.Log:智能业务日志处理;
为什么手动写 @ComponentScan?
默认@SpringBootApplication只会扫描当前启动类所在包及其子包; 而 calculation 是独立平级包,默认扫描不到,必须手动指定扫描路径,否则计算引擎中的 Service、Controller 不会被 Spring 实例化,报找不到 Bean 异常。
4. @RequestMapping
@RequestMapping
加在启动类上,代表全局接口统一前缀(无参数则无前缀); 如果写成 @RequestMapping("/api"),所有 Controller 接口都会拼接 /api。
5. @CrossOrigin(origins = { "*" })
@CrossOrigin(origins = { "*" })
全局跨域注解,允许所有前端域名访问本服务接口;
-
* 通配符:本地前端、线上前端、任意 IP 都可跨域;
-
注释掉的旧代码:曾经配置了localhost、3000、8080、8090、63342 等前端常用端口,后来简化为全部放行;
-
企业开发规范:生产环境不建议写*,需要指定真实前端域名,防止恶意网站跨域调用接口。
四、main 主启动方法
public static void main(String[] args) {
// 禁用JMX以避免检索问题
System.setProperty("spring.jmx.enabled", "false");
System.setProperty("management.endpoints.jmx.exposure.include", "");
SpringApplication.run(BusinessRunApplication.class, args);
}
1. System.setProperty 系统参数配置
JMX 是 SpringBoot Actuator 监控组件,用于远程监控、管理服务:
spring.jmx.enabled=false:关闭 JMX 功能;
management.endpoints.jmx.exposure.include="":清空 JMX 暴露的监控端点;
业务目的:
-
规避 JMX 端口冲突、远程连接检索报错;
-
企业内网安全管控,关闭远程服务监控入口;
-
减少服务占用端口,简化部署运维。
2. SpringApplication.run()
标准 SpringBoot 启动入口,加载当前类所有配置、初始化 Spring 容器、内嵌 Tomcat 启动 Web 服务。
五、注释掉的测试接口
/*
* @GetMapping("/")
* @ResponseBody
* public JsonMessage main(){
* return new JsonMessage().success("main");
* }
*/
曾经写的根路径健康测试接口:
-
访问 http://ip:端口/ 返回统一 JSON 成功报文;
-
作用:部署后快速验证服务是否正常启动、接口能否访问;
-
现在注释禁用,如需健康检测可重新打开,或使用 Actuator 健康端点 /actuator/health。
六、整体项目架构总结
项目归属:xxx内部业务服务,命名规范企业化;
核心能力:
-
Web 接口服务,全局跨域;
-
内置定时任务调度;
-
独立计算引擎模块;
框架定制化配置:
-
手动扩展 Bean 扫描包,兼容多模块;
-
排除 MyBatis 自动装配,自定义数据库配置;
-
关闭 JMX 监控,提升部署稳定性与安全性;
缺陷 / 优化点:
包名拼写错误 bussiness → business;
生产环境@CrossOrigin("*")存在安全风险,应限定前端域名;
无 Actuator 健康监控配置,线上运维排查不方便;
MyBatis 自动装配被排除,需要确认项目是否手动配置了 Mapper 扫描。
配置文件 : application-dev.yml – 了解数据库、Redis、ES 配置
application-dev.yml
# 允许 Bean 定义覆盖
spring:
main:
allow-bean-definition-overriding: true
# 数据源配置 – 达梦数据库
datasource:
driver-class-name: dm.jdbc.driver.DmDriver
url: jdbc:dm://localhost:5236/ZNYW
username: SYSDBA
password: Llf123456
type: com.alibaba.druid.pool.DruidDataSource
druid:
# 初始化连接数
initial-size: 8
# 最小空闲连接数
min-idle: 1
# 最大活动连接数
max-active: 20
# 获取连接时最大等待时间,单位毫秒
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-timeMillis: 300000
# 用来检测连接是否有效的 SQL,要求是一个查询语句(达梦使用标准SQL)
validation-query: SELECT 1 FROM DUAL
# 建议配置为 true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于 timeBetweenEvictionRunsMillis,执行 validationQuery 检测连接是否有效。
test-while-idle: true
# 申请连接时执行 validationQuery 检测连接是否有效,做了这个配置会降低性能。
test-on-borrow: false
# 归还连接时执行 validationQuery 检测连接是否有效,做了这个配置会降低性能。
test-on-return: false
# 打开 PSCache,并且指定每个连接上 PSCache 的大小
pool-prepared-statements: false
#### 缓存服务开始 ####
redis:
host: localhost
port: 6379
password:
jedis:
pool:
enabled: true
max-active: 20
min-idle: 2
max-idle: 10
# Elasticsearch多数据源配置
elasticsearch:
# 默认使用的ES(local=本地, prod=生产)
default: prod
# 本地ES配置
local:
uris: http://localhost:9200
username: elastic
password: 123456
connection-timeout: 5000
socket-timeout: 60000
# 生产ES配置 – sl集群(3节点)
prod:
uris:
– https://10.xx.xxx.xxx:9200
– https://10.xx.xxx.xxx:9200
– https://10.xx.xxx.xxx:9200
username: elastic
password: tUUPsYdJpY5ZyAhIsCuM
connection-timeout: 30000
socket-timeout: 180000
# Journal索引配置
index:
# 索引名称前缀
prefix: journal
# 是否使用日期后缀(本地false,生产true)
use-date-suffix: true
# 日期格式(生产环境使用)
date-format: yyyyMMdd
# 工程启动端口号
server:
port: 8091
# session 失效时间
servlet:
session:
timeout: 480m
# 根地址
context-path: /
# tomcat 配置
tomcat:
# 最小线程数
min-spare-threads: 50
# 最大线程数
max-threads: 2500
# 最大等待队列长度
accept-count: 1000
# 最大连接数
max-connections: 10000
# JMX 配置 – 解决JMX服务URL检索问题
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
jmx:
enabled: false # 禁用JMX以避免检索问题
# MyBatis 配置,开启下划线转驼峰命名
mybatis:
mapper-locations: classpath:config/mappers/**/*.xml
configuration:
map-underscore-to-camel-case: true
# 配置日志实现类,使用 SLF4J
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
# 禁用缓存,确保配置更改立即生效
cache-enabled: false
# 配置日志级别,将 Mapper 接口所在包的日志级别设置为 DEBUG
logging:
level:
cn.com.sinopec.api.base: DEBUG
cn.com.sinopec.bussiness.znyw.mapper: DEBUG # 添加 Mapper 的 DEBUG 日志
# 工单系统配置(接口文档:/api/workorders/external/inspection)
inspection:
work-order:
base-url: http://10.xx.xxx.xxx/
app-key: inspection-system
app-secret: change-me
category-id: 1
timeout: 30000
这份是xxx业务服务的生产级配置文件,搭配上一篇的启动类,整体架构:SpringBoot + 达梦国产数据库 (Druid 连接池) + Redis 缓存 + Elasticsearch 双集群 + MyBatis + 定时任务 + 外部工单系统接口。
一、Spring 容器基础配置
spring:
main:
allow-bean-definition-overriding: true
作用
允许同名 Bean 覆盖,Spring 默认关闭,这里开启是适配项目场景:
启动类排除了 MyBatis/MyBatisPlus 自动配置,项目手动自定义 SqlSessionFactory、Mapper 扫描 Bean;
多模块(business 业务、calculation 计算引擎)存在同类型 Bean,允许后不会启动报 BeanDefinitionOverrideException 冲突异常51CTO。
二、达梦数据库 + Druid 连接池(核心业务库)
datasource:
driver-class-name: dm.jdbc.driver.DmDriver
url: jdbc:dm://localhost:5236/ZNYW
username: SYSDBA
password: Llf123456
type: com.alibaba.druid.pool.DruidDataSource
数据库类型:达梦 DM8 国产数据库(信创项目标配,兼容 Oracle 语法)稀土掘金;
连接地址:本地达梦实例,端口 5236,库名ZNYW(智能业务库);
连接池:指定 Druid 阿里高性能连接池,替代 Spring 默认 Hikari。
Druid 连接池调优参数
druid:
initial-size: 8 # 服务启动初始化8个数据库连接
min-idle: 1 # 最小空闲连接,至少保留1个不回收
max-active: 20 # 连接池最大20个连接(业务并发不高,限制资源占用)
max-wait: 60000 # 获取连接最长等待60秒,超时抛异常
time-between-eviction-runsMillis: 60000 # 每60秒检测空闲连接,回收闲置连接
min-evictable-idle-timeMillis: 300000 # 空闲连接5分钟后自动回收
validation-query: SELECT 1 FROM DUAL # 达梦数据库连通性检测SQL(兼容Oracle)
test-while-idle: true # 空闲时后台检测连接有效性(推荐,不影响性能)
test-on-borrow: false # 拿连接时不检测,避免拖慢接口响应
test-on-return: false # 归还连接时不检测
pool-prepared-statements: false # 关闭PS缓存,达梦场景开启易内存溢出
设计思路:优先保证接口响应速度,仅后台异步检测连接,避免频繁 SQL 校验拖慢业务。
三、Redis 缓存配置
redis:
host: localhost
port: 6379
password:
jedis:
pool:
enabled: true
max-active: 20
min-idle: 2
max-idle: 10
本地 Redis 实例,无密码;
使用 Jedis 客户端连接池,最大 20 个缓存连接,保留 2 个常驻空闲连接;
用途:业务热点数据缓存、定时任务分布式锁、接口重复请求防重。
四、Elasticsearch 双集群多环境配置(日志 / 检索引擎)
elasticsearch:
default: prod # 默认使用生产ES集群(xxx3节点集群)
# 本地开发ES
local:
uris: http://localhost:9200
username: elastic
password: 123456
connection-timeout: 5000
socket-timeout: 60000
# 生产ES集群(xxx3台节点,HTTPS加密访问)
prod:
uris:
– https://10.66.205.242:9200
– https://10.66.205.151:9200
– https://10.66.205.125:9200
username: elastic
password: tUUPsYdJpY5ZyAhIsCuM
connection-timeout: 30000
socket-timeout: 180000
# 业务日志索引通用规则
index:
prefix: journal # 索引前缀 journal_20260727
use-date-suffix: true # 索引按日期分表,每日生成新索引
date-format: yyyyMMdd # 日期格式年月日
核心业务场景
双环境隔离:开发环境连本地单节点 ES,生产直连油田内网 3 节点高可用集群;
HTTPS 安全访问:生产 ES 开启 SSL 加密,内网安全规范;
日志时序存储:日志按天分索引,方便日志检索、计算引擎数据分析,避免单索引数据过大查询卡顿。
五、Web 服务容器(Tomcat 高并发调优)
server:
port: 8091 # 服务启动端口8091
servlet:
session:
timeout: 480m # Session失效时间8小时
context-path: / # 接口根路径无前缀
tomcat:
min-spare-threads: 50 # 常驻50个空闲线程,应对突发流量
max-threads: 2500 # Tomcat最大工作线程2500(远超默认200,支持高并发接口)
accept-count: 1000 # 请求等待队列1000,线程耗尽后请求排队不直接拒绝
max-connections: 10000 # Tomcat最大支持10000条TCP长连接
调优说明
默认 Tomcat 最大线程仅 200,本项目集成定时任务、计算引擎、大量查询接口,调高线程池参数,支撑多任务并行执行,适配油田业务批量计算场景稀土掘金。
六、Actuator 监控 + JMX 关闭(和启动类配套)
management:
endpoints:
web:
exposure:
include: health,info,metrics # 对外开放健康、服务信息、指标监控端点
endpoint:
health:
show-details: always # 健康检查完整展示:数据库、Redis、ES连通状态
jmx:
enabled: false # 全局关闭JMX,和启动类System.setProperty配置统一,解决JMX端口检索报错、安全管控需求
运维监控:/actuator/health 运维可快速校验数据库、缓存、ES 全部中间件连通性;
JMX 关闭:企业内网安全规范,禁用远程 JMX 服务,避免端口冲突、远程漏洞风险。
七、MyBatis 持久层配置(达梦数据库 SQL 映射)
mybatis:
mapper-locations: classpath:config/mappers/**/*.xml # Mapper XML文件扫描路径
configuration:
map-underscore-to-camel-case: true # 自动数据库下划线字段 → Java驼峰实体映射(如user_name → userName)
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl # SQL日志输出使用SLF4J统一日志框架
cache-enabled: false # 全局关闭MyBatis二级缓存
关闭二级缓存原因
项目存在定时任务批量更新数据、多服务同时操作达梦库,二级缓存易产生脏读、数据不一致;
业务实时性要求高,每次查询直接走数据库,不依赖缓存;
热点数据统一交给 Redis 做分布式缓存,放弃 MyBatis 本地缓存。
八、日志级别配置(调试数据库 SQL)
logging:
level:
cn.com.sinopec.api.base: DEBUG
cn.com.sinopec.bussiness.znyw.mapper: DEBUG
-
Mapper 包日志设为 DEBUG,打印完整执行 SQL、参数、执行耗时;
-
开发、线上排查数据库慢查询、SQL 报错必备;
-
基础公共 API 包开启 DEBUG,方便追踪接口入参、出参日志。
九、外部工单系统接口配置(第三方远程接口)
inspection:
work-order:
base-url: http://10.66.205.199/ # 油田巡检工单系统根地址
app-key: inspection-system # 接口身份认证key
app-secret: change-me # 密钥(生产环境需修改,当前占位符)
category-id: 1 # 工单分类ID
timeout: 30000 # 接口调用超时30秒
业务用途:本服务作为计算引擎,需要远程调用油田巡检工单系统,同步工单数据、生成巡检计算报表,独立抽取配置方便环境切换(开发 / 测试 / 生产更换 base-url)。
整体项目架构总结
技术栈:SpringBoot + 达梦国产数据库 (Druid) + Redis + Elasticsearch 集群 + MyBatis + Tomcat 高并发;
业务分层:
-
业务模块:cn.com.xxx.bussiness 工单、智能业务处理;
-
核心模块:cn.com.xxx.calculation 数据计算引擎;
-
存储层:达梦存业务主数据,ES 存时序日志,Redis 存缓存;
-
外部依赖:远程巡检工单第三方接口;
环境适配设计:ES 区分本地开发 / 生产集群,配置抽离,无需修改代码切换环境;
生产安全规范:关闭 JMX、生产 ES 启用 HTTPS、第三方接口密钥配置化、限制数据库 / 缓存最大连接数,防止资源耗尽;
配套启动类呼应点:关闭 JMX、排除 MyBatis 自动配置(配置开启 Bean 覆盖)、全局跨域、启用定时任务,配置文件与启动类完全配套。
优化建议(生产环境)
@CrossOrigin(origins = "*") 生产禁止全局放行所有域名,指定前端真实域名;
工单系统app-secret: change-me必须替换为生产真实密钥,避免接口越权访问;
ES 生产密码、达梦数据库密码可放入环境变量,禁止明文写在 yml 配置;
MyBatis 二级缓存根据业务实时性评估,若读多写少可选择性开启;
Tomcat 最大线程 2500 过高,根据服务器 CPU / 内存资源下调,避免操作系统线程切换开销过大。
前端路由 : router.define.js – 了解页面结构
router.define.js
这份代码是 Vue2/Vue3 后台管理系统路由定义文件,对应后端 ZNYW 智能运维业务 前端页面,整体分为:页面静态导入、智能运维独立路由znywRoutes、独立页面路由routesUseViews、框架布局子路由routesUseLayout、统一导出五大部分。
一、顶部:静态 import 页面组件
import Dashboard from '@/views/home/dashboard.vue';
import DemoPage from '@/views/DemoPage.vue';
import FileUpload from '@/views/fileupload/fileupload.vue';
// 省略大量UI组件页面导入
作用
静态引入:页面打包时直接打包进主 chunk,访问页面无需异步加载;
适用页面:通用 UI 演示页、文件上传、仪表盘等低频 / 小型页面;
对比后文 ()=>import() 动态导入:大型业务页面使用路由懒加载,拆分 JS 包,优化首屏加载速度。
注释代码说明
//import Login from '@/views/home/login.vue';
// import { znywRoutes } from './znyw.define.js';
旧系统登录页面已弃用注释;
原先智能运维路由抽离到单独文件,现在直接写在当前文件,注释掉旧引入。
二、核心业务路由:const znywRoutes = []
ZNYW = 智能运维(和后端 yml、启动类的ZNYW库完全对应,油田智能监控工单系统),这是项目核心业务模块路由。
1. 第一条路由:/znyw 主业务入口
{
path: "/znyw",
name: "znyw-home",
component: () => import("@/components/layout/znyw/MainLayout.vue"),
meta: { title: "新系统首页", independent: true },
children: [/* 子页面路由 */]
}
关键字段拆解
path: "/znyw" 独立一级路由,不嵌套在旧后台管理系统布局,完全隔离新旧两套系统页面。
component: ()=>import(布局组件)
-
路由懒加载,访问/znyw才加载布局 JS;
-
MainLayout.vue:智能运维专属侧边栏、顶部导航、页面内容容器布局,和旧系统布局分开。
meta: { independent: true } 自定义路由元信息:标记该路由为独立新系统,全局路由守卫(登录鉴权、权限拦截)会跳过旧系统的权限、登录校验逻辑,实现两套系统登录隔离。
children 子路由列表(核心业务页面)
|
空 path |
Home.vue |
智能运维首页总览 |
|
list |
SystemList.vue |
系统清单管理 |
|
application |
ApplicationList.vue |
应用管理 |
|
metric |
MetricNaming.vue |
指标名称配置 |
|
metricAlgorithm |
MetricAlgorithm.vue |
指标计算算法配置(后端 calculation 计算引擎配套) |
|
alertRule |
AlertRule.vue |
告警规则配置 |
|
alertModel |
AlertModel.vue |
告警模型配置 |
|
alertTask |
AlertTask.vue |
告警定时任务(对应后端 @EnableScheduling 定时任务) |
|
taskRecord |
TaskRecord.vue |
定时任务执行记录 |
|
monitorObject |
MonitorObjectList.vue |
油田监控对象管理 |
|
analysis |
Analysis.vue |
监控数据分析页面 |
|
ticket |
TicketManagement.vue |
巡检工单管理(对接后端工单第三方接口) |
2. 第二条路由:/znyw/alarm
path: "/znyw/alarm",
children: [和上面完全一致的页面路由]
问题说明
这条路由存在严重冗余:子路由列表和/znyw完全重复。
-
设计意图:原本想单独做告警模块一级路由;
-
缺陷:重复代码,维护成本高,修改页面需要两处同步修改,后续建议合并、拆分独立告警路由数组复用。
3. 注释掉的登录路由
// {
// path: "/znyw/login",
// name: "znyw-login",
// component: () => import("@/views/znyw/login/Login.vue"),
// meta: { title: "智能运维系统登录", independent: true }
// }
独立登录页已临时注释,说明当前系统登录逻辑暂时复用旧系统登录,后续可放开,实现智能运维系统独立登录页面。
三、独立页面路由:const routesUseViews = []
存储不嵌套任何侧边栏布局的纯独立页面,访问时只渲染页面自身,无导航栏。
1. 根路径重定向
{
path: "/",
redirect: "/znyw",
meta: { hidden: true }
}
-
redirect: "/znyw":用户直接访问域名根地址http://ip:8091/,自动跳转到智能运维首页;
-
meta.hidden:true:路由菜单渲染时隐藏该路由,侧边栏不显示根路径菜单。
2. 文件上传页面
{
path: "/fileUpload",
component: FileUpload,
meta: { title: "文件上传" }
},
{
path: "/fileIndex",
component: FileIndex,
meta: { title: "文件上传列表" }
}
独立文件上传功能,不嵌入后台布局,用于附件、报表文件上传存储。
四、框架布局子路由:const routesUseLayout = []
该数组内所有路由都嵌套在旧版后台通用布局中(侧边栏 + 顶部导航),存放 UI 组件演示、微前端嵌入页面。
1. 微前端子应用路由(重点)
{
path: '/micro/:path(.*)*',
component: () => import("@/views/home/micro-container.vue"),
meta: { title: "微前端1加载", keepAlive: false }
},
{
path: '/micro2/:path(.*)*',
component: () => import("@/views/home/micro-container.vue"),
meta: { title: "微前端2加载", keepAlive: false }
}
路由匹配规则 /:path(.*)*:正则匹配/micro/后的所有子路径,用于微前端基座转发子应用路由;
micro-container.vue:微前端容器组件,通过 qiankun/iframe 加载外部子系统;
keepAlive:false:页面离开不缓存,每次进入微应用重新加载,避免子应用状态污染。
2. UI 组件演示路由
数组剩余全部路由为后台组件演示页面: 仪表盘、表格、表单、图表、按钮、选择器、标签、进度条、提示、加载组件等;
-
全部使用静态导入组件(文件顶部 import);
-
meta.title:侧边栏菜单显示的中文名称;
-
全部为二级路由,拼接旧系统布局,例如完整访问地址:/dashboard、/table。
五、末尾统一导出
export {
znywRoutes,
routesUseLayout,
routesUseViews,
}
将三组路由数组导出,在项目路由总入口 router/index.js中引入,合并成完整路由表。
六、整体项目前端架构梳理
两套系统隔离
-
旧系统:通用后台布局,UI 组件演示、微前端嵌入、文件上传;
-
新系统 ZNYW:独立专属布局,xx智能监控、指标、告警、工单核心业务;
路由加载策略区分
-
大型业务页面(znyw 子页面):懒加载()=>import,分包优化首屏;
-
小型 UI 演示页面:静态 import,减少异步请求;
业务前后端对应关系 前端 znyw 全部页面,完全匹配后端 SpringBoot 服务:达梦 ZNYW 数据库、指标计算引擎、定时告警任务、工单第三方接口、ES 日志检索;
路由元信息 meta 作用
-
independent:true:路由守卫区分新旧系统鉴权逻辑;
-
title:浏览器标签标题、侧边栏菜单文字;
-
hidden:true:菜单隐藏;
-
keepAlive:页面缓存控制。
七、代码存在的优化点
/znyw/alarm 子路由完全重复,抽离公共子路由数组复用,消除冗余;
大量 UI 组件页面命名混用拼音(jindutiao、biaoqian),规范为英文命名;
智能运维登录路由注释,可根据业务需求放开独立登录;
路由数组拆分逻辑可优化:将微前端路由单独抽离数组,结构更清晰;
未配置meta.requiresAuth鉴权标记,路由守卫无法统一拦截未登录访问。
代码写得太乱了,逻辑拼贴得很乱。
太难为维护了,一般重构是最好的办法。
第二阶段【核心业务模块】
告警模型管理
AlarmModelController.java
这是xxx智能运维 ZNYW 模块后端接口控制器,对应前端路由 /znyw/alertModel 告警模型页面,标准 SpringBoot RESTful 分层架构 Controller 层,提供告警模型分页查询、单条 CRUD、多条件筛选、模型关联配置全套接口。
一、基础头部信息解析
1. 包路径
package cn.com.xxx.bussiness.znyw.controller;
和之前启动类、yml 配置、前端路由完全对应:
-
bussiness 业务主模块
-
znyw 智能运维子业务
-
controller 接口控制层
2. 导入类说明
分页工具 DataPaging:项目封装通用分页返回对象,包含总条数、页码、数据列表;
统一返回体 JsonMessage:企业全局标准接口返回格式,区分成功 / 失败、携带数据 / 错误信息;
实体 AlarmModel:数据库告警模型表映射实体类;
业务 Service
-
AlarmModelService:告警模型基础增删改查服务
-
AlarmModelConfigService:告警模型关联配置专用服务(规则、指标、监控范围关联逻辑)
Spring Web 注解:@RestController、@RequestMapping、@Get/Post/Put/DeleteMapping、@RequestParam、@PathVariable、@RequestBody;
工具类:HashMap/Map 封装动态查询参数、动态配置返回数据。
3. 类注解
@RestController
@RequestMapping("/api/alarmModel")
@RestController = @Controller + @ResponseBody 所有接口返回值自动序列化为 JSON,无需额外注解;
全局接口前缀 /api/alarmModel 前端完整请求地址示例:http://127.0.0.1:8091/api/alarmModel/list/page
4. 依赖注入
@Autowired
private AlarmModelService alarmModelService;
private AlarmModelConfigService alarmModelConfigService;
Spring 自动注入两个业务服务,职责拆分清晰:
-
AlarmModelService:告警模型本身基础 CRUD;
-
AlarmModelConfigService:告警模型关联配置(指标、告警规则、监控范围)复杂业务逻辑。
二、逐个接口功能详解(REST 规范)
1. 分页模糊查询接口 GET /api/alarmModel/list/page
作用:前端告警模型列表页面分页加载、多条件筛选
入参说明(前端传参)
|
modelName |
非必填 |
模型名称模糊搜索 |
拼接 %关键词% 用于数据库 like 查询 |
|
modelCode |
非必填 |
模型编码精确匹配 |
直接等值查询 |
|
status |
非必填 |
模型启用 / 禁用状态 |
等值查询 |
|
page |
必填 |
当前页码 |
分页参数 |
|
row |
必填 |
每页条数 |
分页参数 |
核心逻辑
封装所有查询条件到 paramMap;
空值、空白字符串过滤,避免无效查询参数;
调用 service 分页查询,返回分页对象DataPaging<AlarmModel>;
统一包装为成功 JSON 返回。
2. 根据 ID 单条查询 GET /api/alarmModel/{id}
路径参数:id 告警模型主键 逻辑:
-
查询存在返回模型实体;
-
查询无数据返回业务失败提示;
-
全局捕获异常,返回异常信息给前端。
3. 查询全量告警模型 GET /api/alarmModel/all
作用:下拉选择框、基础数据字典加载,返回无分页全量列表,适用于数据量不大场景。
4. 新增告警模型 POST /api/alarmModel/add
-
请求体 @RequestBody AlarmModel:前端页面填写的告警模型表单 JSON;
-
调用 service 新增,返回布尔标识;
-
新增失败 / 异常统一返回错误信息。
5. 修改告警模型 PUT /api/alarmModel/update
REST 规范 PUT 用于全量更新,接收完整 AlarmModel 实体,根据主键 id 更新数据库记录。
6. 删除告警模型 DELETE /api/alarmModel/{id}
标准 DELETE 删除接口,根据主键逻辑 / 物理删除(删除逻辑在 Service 层)。
7. 根据状态筛选 GET /api/alarmModel/byStatus
入参 status,查询对应启用 / 停用状态下所有告警模型,用于状态筛选下拉、过滤列表。
8. 根据监控范围筛选 GET /api/alarmModel/byScope
入参:scopeType(监控范围类型,设备 / 站点 / 油田)、scopeId(范围主键); 业务场景:根据选中的监控对象,过滤绑定的告警模型。
9. 根据 ID 查询完整关联详情 GET /api/alarmModel/{id}/details
普通getById只返回告警模型基础字段; 本接口返回组装后的 Map 完整详情,包含:模型基础信息 + 关联告警规则、指标、告警级别、监控范围等关联子数据,用于详情弹窗页面。
10. 保存告警模型关联配置 POST /api/alarmModel/{id}/config
核心复杂业务接口,调用专用AlarmModelConfigService
-
路径 id:告警模型主键;
-
请求体 configData:前端页面配置的指标、规则、阈值等配置 JSON;
-
业务逻辑:智能解析配置,自动生成 / 更新关联告警规则,过滤无效冗余规则;
-
返回执行结果 + 提示信息。
11. 获取模型已保存配置 GET /api/alarmModel/{id}/config
回显接口:编辑配置页面加载历史保存的指标、规则、阈值配置,用于前端表单回填。
12. 配置变更检测 POST /api/alarmModel/{id}/config/detectChanges
增量更新核心接口
读取数据库当前旧配置;
接收前端提交的新配置;
自动对比,识别三类变更:新增规则、修改原有规则、删除废弃规则;
将变更明细返回前端,可用于变更预览、操作日志记录。
三、代码设计亮点
职责单一拆分 基础模型 CRUD 和 复杂关联配置 拆分两个 Service,解耦业务逻辑,便于维护;
标准 RESTful 接口规范
-
查询:GET
-
新增:POST
-
修改:PUT
-
删除:DELETE 语义清晰,前后端协作统一;
全局异常捕获 每个接口内部try-catch,所有数据库异常、业务异常不会直接抛出堆栈,统一返回友好提示给前端,生产环境友好;
动态参数适配 查询条件使用Map<String,Object>封装,无需新增实体类接收多条件,适配灵活的前端筛选条件;
分层返回设计
-
简单列表:List<AlarmModel>
-
分页列表:DataPaging<AlarmModel>
-
多表关联复杂详情:Map<String,Object> 根据数据复杂度选择合适返回载体;
接口粒度划分合理 区分基础单表操作、关联详情、配置保存、变更检测,单个接口只做一件事,前端可按需调用,避免接口数据冗余。
四、对应前后端业务联动关系
前端页面(之前 Vue 路由)
/znyw/alertModel 告警模型管理页面
列表分页:调用 /list/page
新增弹窗:调用 /add
编辑弹窗回显基础信息:调用 /{id}
编辑弹窗回显指标 / 规则配置:调用 /{id}/config
保存配置修改:调用 /{id}/config POST
删除按钮:调用 DELETE /{id}
详情弹窗(完整关联数据):/{id}/details
配置修改前预览变更:/config/detectChanges
后端配套组件
数据库:达梦数据库 ZNYW 库 alarm_model 表;
持久层:MyBatis,分页工具DataPaging;
定时任务:告警模型绑定的告警任务,对应后端@EnableScheduling定时任务;
计算引擎:告警模型关联指标,对接 calculation 指标计算模块;
工单模块:告警触发后自动生成巡检工单,对接第三方工单接口。
五、可优化点
重复 try-catch 模板代码过多,可使用全局统一异常处理器 @ControllerAdvice,删除每个接口内部重复捕获代码,简化控制器;
接口入参大量@RequestParam零散参数,复杂分页查询可封装 DTO 接收参数,代码可读性更高;
魔法字符串硬编码(如状态、scopeType),建议定义常量类统一管理;
返回值Map<String,Object>动态结构无约束,复杂详情建议创建专用 VO 视图实体替代 Map,强类型校验,减少前后端字段沟通错误;
缺少接口权限校验注解,可结合项目权限框架添加@PreAuthorize控制增删改查按钮权限。
AlarmModelService.java
这份是 告警模型业务层标准接口,遵循 SpringBoot 分层开发规范(Controller → Service 接口 → ServiceImpl 实现类 → Mapper),定义了告警模型所有业务能力契约,Controller 只依赖该接口,不直接耦合实现层,做到面向接口编程、解耦、易扩展、单元测试友好。
一、基础信息
1. 包路径
package cn.com.sinopec.bussiness.znyw.service;
和前面 Controller、实体类包层级统一: znyw 智能运维模块下的 service 业务层。
2. 导入类说明
DataPaging:项目通用分页返回载体,分页查询统一返回该对象;
AlarmModel:数据库表映射实体类,单表基础操作的入参 / 返回载体;
集合容器:List、Map,适配全量列表、多表关联复杂详情数据。
3. 接口定位
-
作用:定义业务能力规范,只声明方法签名、入参、返回值、业务注释,不写任何业务逻辑;
-
实现:会存在一个 AlarmModelServiceImpl 类 implements AlarmModelService,所有 SQL 查询、事务、复杂业务逻辑写在实现类;
-
解耦优势:Controller 注入 private AlarmModelService alarmModelService;,只依赖接口,后续更换存储(达梦→其他数据库)、重构逻辑,只需修改实现类,上层 Controller 完全不用改动。
二、所有方法逐一分组讲解
分组 1:分页 / 多条件列表查询(对应前端列表页面)
DataPaging<AlarmModel> selectPagingAlarmModelList(Map<String, Object> paramMap, int page, int row);
入参
-
paramMap:动态查询条件(模型名称模糊、编码、状态);
-
page:当前页码;row:每页条数;
返回:分页封装对象 DataPaging<AlarmModel>,包含总条数、当前页数据;
对应接口:GET /api/alarmModel/list/page 分页列表。
分组 2:单 ID 基础 CRUD(增删改查基础能力)
// 根据主键查询单条基础信息
AlarmModel getById(String id);
// 新增告警模型
boolean add(AlarmModel alarmModel);
// 更新告警模型
boolean update(AlarmModel alarmModel);
// 根据ID删除
boolean deleteById(String id);
// 判断ID是否存在
boolean existsById(String id);
返回值 boolean:标识数据库操作是否成功(插入 / 更新 / 删除影响行数 > 0 则 true);
existsById:业务校验专用,删除 / 编辑前校验模型是否存在,避免无效操作;
对应前端接口:单条查询、新增、修改、删除。
分组 3:多条件筛选查询(下拉、过滤场景)
// 根据模型编码精确查询(编码唯一,用于重复校验)
AlarmModel getByModelCode(String modelCode);
// 根据状态筛选(启用/停用)
List<AlarmModel> getByStatus(String status);
// 根据监控范围筛选(范围类型+范围ID,绑定监控对象)
List<AlarmModel> getByScope(String scopeType, String scopeId);
业务场景:
getByModelCode:新增模型时校验编码重复,保证 modelCode 唯一;
getByStatus:前端下拉选择启用 / 停用模型;
getByScope:选中监控设备 / 站点,查询绑定的告警模型。
分组 4:关联复杂数据查询(详情弹窗,多表联查)
Map<String, Object> getByIdWithDetails(String id);
区别于 getById:getById 只返回单表基础字段;该方法多表关联查询,组装告警模型 + 关联指标、告警规则、告警级别、监控对象等子数据;
返回 Map:动态结构,适配多表组合的复杂详情;
对应接口:GET /api/alarmModel/{id}/details 详情页面。
分组 5:业务关联校验方法(上层业务逻辑判断)
// 判断模型是否绑定指定监控对象
boolean isAssociatedWithObject(String modelId, String objectId);
业务用途:
删除监控对象前校验:如果存在绑定的告警模型,禁止删除;
解绑 / 绑定操作前置校验,用于业务拦截、弹窗提示。
三、接口设计规范亮点
分层职责清晰
-
Controller:只做请求接收、参数封装、统一返回、异常捕获;
-
Service 接口:统一定义业务能力标准;
-
ServiceImpl:实现 SQL、事务、复杂业务逻辑;
-
Mapper:仅负责数据库 CRUD;
面向接口编程 依赖倒置,上层 Controller 只依赖抽象接口,不耦合具体实现,方便:
-
单元测试:Mock 接口,无需真实数据库;
-
业务重构:替换实现类不改动 Controller;
方法粒度拆分合理
-
基础单表操作独立方法;
-
筛选、分页、详情、业务校验完全拆分; 一个方法只做单一业务,复用性强;
完善的业务校验方法 提供 existsById、isAssociatedWithObject 前置校验方法,把业务判断能力下沉到 Service 层,Controller 无需写重复判断逻辑;
注释规范统一 每个方法都具备完整 JavaDoc 注释:功能说明、入参含义、返回值含义,便于团队协作、代码阅读。
四、接口与上层 Controller 对应关系
|
selectPagingAlarmModelList |
/list/page |
告警模型列表分页加载 |
|
getById |
/{id} |
编辑弹窗回显基础信息 |
|
add |
/add |
新增告警模型 |
|
update |
/update |
修改告警模型 |
|
deleteById |
DELETE /{id} |
删除模型 |
|
getAll |
/all |
下拉框加载全部模型 |
|
getByStatus |
/byStatus |
按状态筛选列表 |
|
getByScope |
/byScope |
根据监控对象筛选模型 |
|
getByIdWithDetails |
/{id}/details |
详情弹窗展示全量关联数据 |
|
existsById / isAssociatedWithObject |
内部业务调用 |
新增 / 删除前置校验 |
|
getByModelCode |
内部业务调用 |
新增时校验编码唯一性 |
五、补充配套说明
该接口只处理告警模型主表相关业务;
告警模型关联配置(规则、指标保存、变更检测)不在此接口,拆分到独立 AlarmModelConfigService,职责拆分更细,避免单个 Service 接口过于臃肿;
实现类 AlarmModelServiceImpl 会注入 AlarmModelMapper,调用 MyBatis 的数据库操作,实现当前接口所有方法;
事务控制:在实现类方法上加 @Transactional,处理新增、修改、删除时的数据库事务回滚。
六、优化建议
返回值 Map<String, Object> 无类型约束,复杂详情建议新建 AlarmModelDetailVO 视图实体类替换 Map,强类型、减少前后端字段沟通错误;
可新增批量操作接口(批量新增、批量删除),适配前端批量操作场景;
所有入参字符串(id、modelCode、status)可统一封装 DTO,减少大量零散入参,提升可读性;
常量抽离:状态、scopeType 魔法字符串,定义常量类,避免硬编码。
AlarmModelServiceImpl.java
这是AlarmModelService 接口的完整业务实现层,遵循标准三层架构:Controller → Service接口 → ServiceImpl实现类 → Mapper持久层,承载所有告警模型的数据校验、参数处理、数据库交互、树形规则组装、复杂业务计算,是整个业务的核心逻辑载体。
一、基础头部与类定义
1. 包结构
package cn.com.sinopec.bussiness.znyw.serviceImpl;
规范分层:serviceImpl 专门存放 Service 接口实现类,与上层service接口包完全隔离,分层清晰。
2. 导入依赖说明
分页工具:DataPaging 项目统一分页封装对象;
实体类:
-
AlarmModel:告警模型主表实体;
-
AlarmRuleTreeUnified:告警规则树形节点实体(规则树存储);
Mapper 持久层:
-
AlarmModelMapper:告警模型主表 CRUD;
-
AlarmRuleTreeUnifiedMapper:规则树形节点查询;
日志工具:Logger、LoggerFactory,业务关键步骤、异常打印日志;
Spring 核心注解:@Service、@Autowired;
集合与流式处理:List/Map/Stack/Comparator/Stream,用于树形遍历、数据组装、集合过滤。
3. 类注解与基础成员
@Service
public class AlarmModelServiceImpl implements AlarmModelService {
private static final Logger logger = LoggerFactory.getLogger(AlarmModelServiceImpl.class);
@Autowired
private AlarmModelMapper alarmModelMapper;
@Autowired
private AlarmRuleTreeUnifiedMapper alarmRuleTreeUnifiedMapper;
}
@Service:Spring 将该类注册为业务层 Bean,Controller 可自动注入上层接口;
静态 Logger:统一日志输出,区分业务日志与异常堆栈;
Mapper 自动注入:直接操作达梦数据库两张核心表;
实现AlarmModelService接口:强制实现接口中定义的全部业务方法,约束上层契约。
二、分页查询方法 selectPagingAlarmModelList
核心作用
前端告警模型列表分页、多条件模糊 / 精确筛选。
分步逻辑拆解
提取并清洗查询参数 从paramMap取出modelName/modelCode/status,空字符串转为null,避免 MyBatis 执行无效like ''查询。
分页参数容错处理 前端传入页码page<=0强制重置为 1;每页条数row<=0默认 10 条,防止分页参数非法导致 SQL 报错。 计算偏移量 offset = (page-1)*row,适配数据库limit offset,row语法。
两次 Mapper 数据库查询
-
manualSelectAlarmModel:分页查询当前页数据;
-
manualCountAlarmModel:统计符合条件总条数; 采用手动分页 SQL(未使用 PageHelper 插件),适配达梦国产数据库语法。
封装分页返回对象 填充DataPaging的rows列表、total总条数,返回给上层 Controller。
三、基础 CRUD 方法(getById /getAll/add /update/deleteById)
1. 单条查询、全量查询、删除
@Override
public AlarmModel getById(String id) {
return alarmModelMapper.selectById(id);
}
@Override
public List<AlarmModel> getAll() {
return alarmModelMapper.selectAll();
}
@Override
public boolean deleteById(String id) {
return alarmModelMapper.deleteById(id) > 0;
}
-
极简封装,直接调用 Mapper 基础 SQL;
-
删除返回值判断:数据库受影响行数 > 0 才返回 true,区分删除成功 / 无数据。
2. 新增方法 add(重点,后端强制赋值,防前端脏数据)
@Override
public boolean add(AlarmModel alarmModel) {
// 1. 后端生成唯一ID,覆盖前端传入ID
String id = UUID.randomUUID().toString().replaceAll("-", "");
alarmModel.setId(id);
// 2. 后端统一创建/更新时间
Date now = new Date();
alarmModel.setCreatedTime(now);
alarmModel.setUpdateTime(now);
// 3. 版本号默认V1.0.0
if (alarmModel.getVersion() == null || alarmModel.getVersion().trim().isEmpty()) {
alarmModel.setVersion("V1.0.0");
}
// 4. 状态默认启用"1"
if (alarmModel.getStatus() == null || alarmModel.getStatus().trim().isEmpty()) {
alarmModel.setStatus("1");
}
return alarmModelMapper.insert(alarmModel) > 0;
}
业务安全设计亮点
主键 ID 完全由后端生成:UUID 去除横杠,杜绝前端传入自定义 ID 导致主键冲突、数据污染;
时间戳后端统一管控:创建时间、更新时间不依赖前端传参,保证数据时间准确性;
字段默认值兜底:版本号、启用状态为空时自动填充默认值,避免数据库字段为空引发业务逻辑异常;
插入成功判断:insert 返回影响行数 > 0 才返回 true。
3. 修改方法 update(参数强校验)
@Override
public boolean update(AlarmModel alarmModel) {
// 更新必须携带主键ID,否则直接抛出参数异常
if (alarmModel.getId() == null || alarmModel.getId().trim().isEmpty()) {
throw new IllegalArgumentException("更新操作必须指定ID");
}
// 强制刷新更新时间
alarmModel.setUpdateTime(new Date());
return alarmModelMapper.update(alarmModel) > 0;
}
-
前置参数校验:无 ID 直接抛出非法参数异常,拦截无效更新 SQL;
-
自动刷新更新时间,记录数据最后修改时刻。
四、条件筛选查询方法(getByModelCode /getByStatus/getByScope)
全部为简单单表查询,直接调用 Mapper 对应 SQL,用于前端下拉框、列表筛选:
getByModelCode:按模型编码精确查询,新增时校验编码唯一性;
getByStatus:按启用 / 停用状态过滤模型列表;
getByScope:根据监控对象类型 + ID,查询绑定的告警模型。
五、核心复杂业务:getByIdWithDetails 模型详情树形规则组装
该方法是整个类业务复杂度最高的方法,实现:查询告警模型基础信息 + 关联树形告警规则节点 + 规则树后序遍历重排 + 自动填充逻辑运算符 + 拼接格式化 JSON 返回前端。
整体流程拆解
基础数据查询 通过 Mapper 查询模型基础详情 Map(包含原始规则关系 JSON 字符串RULE_RELATIONS)。
查询完整规则树节点 调用alarmRuleTreeUnifiedMapper.selectByModelId(id),查询当前模型下全部树形规则节点(包含逻辑父节点、规则叶子节点)。
构建两类映射集合
-
ruleNodeMap:只筛选NODE_TYPE=RULE的叶子规则节点,ID 映射实体;
-
parentMap:存储每个节点对应的父节点,用于读取父节点存储的逻辑运算符(AND/OR)。
调用工具方法 getPostOrderRuleNodeIds 对规则树执行非递归双栈后序遍历,获取规则叶子节点的正确执行顺序 ID 列表。
重构规则关联列表 抛弃原始数据库 JSON 字符串,直接遍历树形节点组装规则对象 Map,填充基础字段(ID、ruleId、执行顺序、告警级别)。
按后序遍历顺序重新排序规则 遍历后序节点 ID 列表,按顺序重组规则列表;同时读取父节点逻辑运算符赋值给当前规则,无父节点默认 AND。
手动拼接标准 JSON 字符串 循环排序后的规则 Map,手动拼接 JSON 数组字符串,覆盖原始RULE_RELATIONS字段,组装完成完整详情 Map 返回。
异常捕获兜底 树形组装全程 try-catch,组装失败打印错误日志,直接返回数据库原始数据,保证前端页面不会报错空白。
六、工具私有方法 getPostOrderRuleNodeIds(树形后序遍历)
作用
对告警规则多叉树做非递归后序遍历,获取规则叶子节点执行顺序,保证告警计算引擎按正确先后顺序执行规则判断。
实现逻辑(双栈经典后序遍历算法)
遍历全部节点,找到根节点(isRoot=true);
构建childrenMap:父 ID 映射子节点列表,子节点按executionOrder升序排序;
初始化双栈stack1、stack2,根节点压入 stack1;
循环弹出 stack1 节点,压入 stack2;再逆序压入子节点(栈 LIFO 特性保证遍历顺序正确);
stack1 清空后,循环弹出 stack2,只收集NODE_TYPE=RULE规则节点 ID,形成有序列表返回。
优势
-
非递归实现,避免规则树层级过深引发递归栈溢出;
-
严格按照业务定义的执行顺序遍历,匹配后端计算引擎规则执行逻辑。
七、业务校验辅助方法 existsById /isAssociatedWithObject
existsById:判断模型 ID 是否存在,编辑、删除前置校验;
isAssociatedWithObject:查询中间关联表t_model_monitor_rel,判断告警模型是否绑定指定监控对象; 业务场景:删除监控对象前校验,存在绑定模型则禁止删除,防止数据关联断裂。
八、代码设计亮点总结
1. 分层职责严格分离
-
Controller:只处理请求、参数接收、统一返回;
-
Service 接口:定义业务能力契约,上层只依赖抽象;
-
ServiceImpl:承载全部业务逻辑、参数校验、数据组装、复杂算法;
-
Mapper:仅执行原生 SQL,无任何业务判断。
2. 数据安全管控(新增 / 更新强约束)
主键、时间戳、默认字段全部由后端强制赋值,完全隔离前端可控字段,杜绝脏数据入库。
3. 复杂业务解耦
将树形遍历逻辑抽离私有工具方法,详情查询主方法逻辑清晰,便于后期维护规则排序逻辑。
4. 容错健壮性设计
分页参数、更新 ID 非法时主动拦截抛出异常;
树形规则组装全程异常捕获,失败兜底返回原始数据;
数据库查询空值兼容,空字符串统一转为 null,避免无效 SQL;
所有数据库操作判断受影响行数,精准区分操作成功 / 失败。
5. 日志完备
关键业务步骤(规则组装完成数量)、异常场景打印日志,线上问题可快速定位。
九、可优化改进点
缺少事务注解 @Transactional 新增、修改、删除、批量规则组装方法未加事务,若多表操作中途异常会产生脏数据,建议在add/update/deleteById/getByIdWithDetails添加@Transactional。
手动拼接 JSON 字符串不规范 规则列表 JSON 采用 StringBuilder 手动拼接,易出现引号、逗号语法错误,建议使用Jackson/Alibaba FastJSON工具类序列化 Map 生成标准 JSON。
大量魔法字符串硬编码 RULE、AND、1、RULE_RELATIONS等状态、字段、类型字符串分散写死,建议抽离全局常量类统一管理。
返回值 Map<String,Object> 无强类型约束 详情接口返回动态 Map,前后端字段沟通易出错,建议新建AlarmModelDetailVO视图实体,强类型返回。
重复参数清洗逻辑可抽工具类 分页查询中空字符串转 null 的逻辑多处复用,可封装通用参数清洗工具方法。
未统一全局异常抛出 仅更新方法抛出IllegalArgumentException,其余参数非法场景未做拦截,建议自定义业务异常BusinessException统一抛出。
告警规则管理
AlarmRuleController.java
该控制器是智能运维 ZNYW 模块告警规则的 REST 接口层,和前面AlarmModelController架构、编码规范完全统一,负责接收前端告警规则页面请求、封装查询参数、调用业务层、统一返回标准 JSON 结构。
一、头部基础信息
1. 包路径
package cn.com.xxx.bussiness.znyw.controller;
与告警模型控制器同包,属于智能运维子模块的接口控制层。
2. 导入类说明
分页工具 DataPaging:统一分页返回载体;
全局统一返回 JsonMessage:前后端标准响应体,区分成功 / 失败;
实体类:
-
AlarmRule:告警规则数据库实体;
业务层:AlarmRuleService 告警规则业务接口;
Spring Web 注解:RESTful 接口必备注解,路径参数、请求体、请求参数注解。
3. 类注解与依赖注入
@RestController
@RequestMapping("/api/alarmRule")
@Autowired
private AlarmRuleService alarmRuleService;
@RestController:自动将返回值转为 JSON,无需额外@ResponseBody;
全局接口前缀 /api/alarmRule 完整请求示例:http://127.0.0.1:8091/api/alarmRule/list/page;
自动注入告警规则业务接口,Controller 只依赖抽象 Service,不耦合实现类。
二、全部接口逐行拆解
接口 1:分页多条件查询 GET /api/alarmRule/list/page
用途:前端告警规则列表页面分页加载、多维度筛选
1. 入参说明(全部前端可传筛选条件)
|
ruleName |
非必填 |
规则名称模糊查询 |
|
ruleCode |
非必填 |
规则编码精确查询(新增扩展字段) |
|
status |
非必填 |
规则启用 / 停用状态筛选 |
|
metricId |
非必填 |
绑定指标 ID 筛选(对接指标计算引擎) |
|
algorithmId |
非必填 |
绑定算法 ID 筛选(计算引擎算法) |
|
operator |
非必填 |
阈值运算符(> < >= <= =) |
|
page |
必填 |
当前页码 |
|
row |
必填 |
每页条数 |
2. 参数封装逻辑亮点
使用 Optional.ofNullable().ifPresent() 封装参数到paramMap:
-
自动过滤null空参数,不会存入 Map,避免 Service 层处理无效查询条件;
-
注释说明:模糊匹配的%通配符由后端 Service 拼接,前端只传纯文本,前后端分工清晰。
3. 执行流程
组装所有筛选条件存入 Map;
调用alarmRuleService.selectPagingAlarmRuleList执行分页查询;
将分页对象DataPaging<AlarmRule>包装为成功 JSON 返回前端。
接口 2:根据主键 ID 单条查询 GET /{id}
@PathVariable String id:路径传参规则主键;
逻辑:
-
查询到实体直接返回成功数据;
-
无数据返回业务提示「未找到对应的告警规则」;
-
所有异常捕获,将异常信息封装为失败提示返回前端,不抛出原始堆栈。
接口 3:查询全量告警规则 GET /all
返回无分页完整List<AlarmRule>;
业务场景:下拉选择框、基础数据字典加载,适用于数据量不大的场景。
接口 4:新增告警规则 POST /add
@RequestBody AlarmRule:接收前端表单完整 JSON 实体;
调用 Service 新增方法,根据返回布尔值判断是否新增成功;
全局捕获异常,返回友好失败信息。
接口 5:修改告警规则 PUT /update
遵循 REST 规范,PUT 用于全量更新实体; 接收完整AlarmRule实体,后端 Service 根据主键 ID 更新数据库记录。
接口 6:删除告警规则 DELETE /{id}
标准 DELETE 删除接口,根据主键执行删除逻辑,返回删除操作结果。
接口 7:按状态筛选 GET /byStatus
入参status,查询对应启用 / 停用状态的全部规则; 用于前端列表状态筛选下拉。
接口 8:按指标 ID 筛选 GET /byMetricId
入参metricId指标主键,查询绑定该指标的所有告警规则; 业务场景:指标详情页面,查看当前指标关联了哪些告警判断规则。
三、代码统一设计规范(和 AlarmModelController 保持一致)
严格 RESTful 接口规范 查询 – GET、新增 – POST、修改 – PUT、删除 – DELETE,语义标准,前后端协作统一;
全接口 try-catch 异常捕获 每个接口内部独立捕获所有异常,不会抛出 500 原始错误堆栈给前端,统一封装业务化失败提示,线上友好;
统一返回格式 JsonMessage 所有接口返回结构标准化,前端统一处理成功 / 失败弹窗、页面渲染;
分层职责清晰 Controller 只做三件事:接收请求参数、组装参数调用 Service、封装返回结果;无任何数据库操作、复杂业务逻辑,业务逻辑全部下沉至 Service 层;
扩展性强 分页查询接口预留大量扩展筛选字段(ruleCode、algorithmId、operator),适配指标、算法、阈值运算符多维度筛选,适配油田智能计算引擎业务场景。
四、前后端业务联动关系
前端页面(对应之前 Vue 路由)
/znyw/alertRule 告警规则管理页面
列表分页筛选:/list/page
新增弹窗:/add
编辑弹窗回显单条数据:/{id}
删除按钮:DELETE /{id}
状态下拉筛选:/byStatus
指标详情关联规则:/byMetricId
规则下拉选择框:/all
后端业务链路联动
数据库:达梦 ZNYW 库 t_alarm_rule 告警规则表;
关联模块:
-
指标模块:metricId 关联指标配置;
-
算法计算引擎:algorithmId 绑定计算算法;
-
告警模型模块:多条告警规则组装为一套告警模型(对应前面 AlarmModel 树形规则结构);
定时任务:规则配置完成后,定时任务按规则阈值执行数据判断,触发告警并生成工单。
五、代码优化建议
重复 try-catch 模板代码冗余 建议使用全局统一异常处理器 @ControllerAdvice,移除每个接口内部重复的 try-catch,简化控制器代码;
分页入参零散 分页接口大量@RequestParam零散参数,可新建 DTO 分页查询对象统一接收参数,代码可读性更高;
魔法字符串硬编码 状态、运算符、字段名硬编码,建议抽取常量类统一管理;
缺少接口权限控制 未添加权限校验注解,无法区分管理员 / 普通用户的增删改查操作权限;
缺少批量操作接口 无批量新增、批量删除接口,前端批量操作场景需要循环调用单条接口,性能较差。
AlarmRuleService.java
这是告警规则模块的业务层标准抽象接口,遵循后端分层架构规范 Controller → Service接口 → ServiceImpl实现类 → Mapper,只定义业务能力契约、方法入参 / 返回值与注释,不包含任何业务逻辑,实现面向接口编程、解耦分层。
一、基础信息
1. 包路径
package cn.com.xxx.bussiness.znyw.service;
和之前 AlarmModelService 同包,属于智能运维 ZNYW 模块统一业务接口层。
2. 导入依赖说明
DataPaging:项目全局通用分页封装对象,分页查询统一返回该载体;
AlarmRule:数据库告警规则表对应的实体类,单表 CRUD 入参、返回载体;
List / Map:动态参数、集合列表承载容器。
3. 接口定位与设计思想
契约约束:强制实现类必须完成接口定义的全部业务能力,统一团队开发标准;
解耦优势:Controller 仅注入 AlarmRuleService 接口,不依赖具体实现类 AlarmRuleServiceImpl;
-
单元测试:可 Mock 接口,无需连接真实达梦数据库;
-
业务重构:修改 SQL、业务逻辑仅改动实现类,上层 Controller 零改动;
职责边界:接口只做「能力定义」,参数校验、数据库交互、复杂业务逻辑全部下沉至 ServiceImpl 实现类。
二、所有方法分组详解
分组 1:分页多条件列表查询(前端规则列表页核心接口)
DataPaging<AlarmRule> selectPagingAlarmRuleList(Map<String, Object> paramMap, int page, int row);
入参:
-
paramMap:动态查询条件 Map,承载规则名称、编码、状态、指标 ID、算法 ID、运算符等多维度筛选条件;
-
page 当前页码、row 每页条数;
返回:分页封装对象 DataPaging<AlarmRule>,包含总数据量、当前页规则列表;
对应前端接口:GET /api/alarmRule/list/page。
分组 2:基础单表 CRUD(增删改查基础能力)
// 根据主键ID查询单条告警规则基础信息
AlarmRule getById(String id);
// 查询全量无分页规则列表(下拉字典使用)
List<AlarmRule> getAll();
// 新增告警规则
boolean add(AlarmRule alarmRule);
// 更新告警规则
boolean update(AlarmRule alarmRule);
// 根据主键删除告警规则
boolean deleteById(String id);
返回值 boolean:标识数据库操作是否生效(受影响行数 > 0 则返回 true);
业务场景:新增 / 编辑 / 删除弹窗、单条详情回显、下拉选择框加载全部规则;
对应接口:/{id}、/all、/add、/update、DELETE /{id}。
分组 3:按指定条件批量筛选查询(页面筛选、关联查询)
// 根据启用/停用状态筛选规则列表
List<AlarmRule> getByStatus(String status);
// 根据指标ID,查询绑定该指标的所有告警规则
List<AlarmRule> getByMetricId(String metricId);
// 根据算法ID,查询绑定该计算算法的所有告警规则
List<AlarmRule> getByAlgorithmId(String algorithmId);
// 根据告警模型ID,查询该模型下绑定的全部告警规则
List<AlarmRule> getRulesByModelId(String modelId);
逐个业务场景说明
getByStatus:前端列表状态筛选下拉,只展示启用 / 停用规则;
getByMetricId:指标管理页面,查看当前指标绑定了哪些告警判断规则;
getByAlgorithmId:算法计算引擎页面,筛选使用该算法的告警规则;
getRulesByModelId【核心关联方法】:告警模型详情页面、规则树组装逻辑专用,根据模型 ID 查询模型绑定的所有规则,对应前文 AlarmModelServiceImpl 中树形规则组装业务。
三、接口与 Controller 层完整映射对照表
|
selectPagingAlarmRuleList |
/api/alarmRule/list/page |
告警规则管理列表分页多条件筛选 |
|
getById |
/api/alarmRule/{id} |
编辑弹窗回显单条规则详情 |
|
getAll |
/api/alarmRule/all |
下拉选择框加载全部告警规则 |
|
add |
POST /api/alarmRule/add |
新增告警规则弹窗提交 |
|
update |
PUT /api/alarmRule/update |
编辑规则表单提交更新 |
|
deleteById |
DELETE /api/alarmRule/{id} |
列表删除按钮操作 |
|
getByStatus |
/api/alarmRule/byStatus |
列表按启用 / 停用状态过滤 |
|
getByMetricId |
/api/alarmRule/byMetricId |
指标页面查看关联告警规则 |
|
getByAlgorithmId |
内部业务调用 |
算法管理页面筛选关联规则 |
|
getRulesByModelId |
内部业务调用 |
告警模型详情组装规则树 |
四、接口设计亮点
方法粒度划分清晰,单一职责
-
分页查询独立方法;
-
基础 CRUD 拆分独立;
-
各类关联筛选单独抽方法,一个方法只处理一类查询,复用性极高;
业务关联链路完整,贴合整体 ZNYW 业务 覆盖「指标→规则→算法→告警模型」完整业务关联链路,支撑告警模型规则树组装、多页面关联查询;
注释规范统一 关键关联方法 getRulesByModelId 添加 JavaDoc 注释,清晰说明方法用途,降低团队协作阅读成本;
参数设计灵活 分页查询使用 Map<String,Object> 承载动态筛选条件,后续新增筛选字段无需修改方法签名,扩展性强。
五、优化建议
动态分页参数 Map<String,Object> 无类型约束,复杂场景可新增专用分页 DTO 实体替换 Map,实现强类型校验;
可补充批量操作接口(批量新增、批量删除),适配前端批量处理场景;
状态、运算符、字段名等魔法字符串,建议统一抽离常量类,消除硬编码;
可新增唯一性校验方法(如根据 ruleCode 查询规则,用于新增时校验编码重复)。
AlarmRuleServiceImpl.java
本类是 AlarmRuleService 接口的完整业务实现,分层架构:Controller → AlarmRuleService(接口) → AlarmRuleServiceImpl(实现) → AlarmRuleMapper; 负责分页多条件查询、新增 / 更新数据字段兜底校验、各类关联筛选查询、异常容错,和前面 AlarmModelServiceImpl 编码规范、安全设计思路完全统一。
一、基础头部与类结构
1. 包、导入、类注解
package cn.com.sinopec.bussiness.znyw.serviceImpl;
@Service
public class AlarmRuleServiceImpl implements AlarmRuleService {
@Autowired
private AlarmRuleMapper alarmRuleMapper;
}
@Service:Spring 将当前类注册为业务层 Bean,上层 Controller 可通过接口注入;
自动注入 AlarmRuleMapper:直接操作达梦数据库告警规则表;
实现 AlarmRuleService 接口,强制实现接口全部方法。
2. 关键导入类说明
-
DataPaging:项目统一分页封装对象;
-
AlarmRule:告警规则数据库实体;
-
UUID:后端生成主键 ID;
-
BigDecimal:阈值数值类型,用于区间 / 单条件阈值兜底;
-
集合工具:HashMap、ArrayList 用于参数封装、空列表兜底。
二、核心方法 1:分页多条件查询 selectPagingAlarmRuleList
核心作用
前端告警规则列表分页筛选,支持规则名称、编码、状态、指标 ID、条件类型、运算符多维度过滤,内置大量容错处理,避免空指针、无效 SQL。
分步逻辑拆解
判空保护,防止空指针
if (paramMap == null) {
paramMap = new HashMap<>();
}
防止前端不传任何筛选参数时,Map 为 null 导致 getOrDefault 报错。
统一提取、清洗全部筛选参数 完整覆盖前端所有筛选字段:ruleName、ruleCode、status、metricId、conditionType、operator; 全部执行 trim() 去除首尾空格,避免空格干扰精确匹配。
空字符串转 null(MyBatis SQL 优化核心)
ruleName = ruleName.isEmpty() ? null : ruleName;
空字符串转为 null,MyBatis 动态 SQL 会自动跳过该查询条件,不会拼接 AND rule_name LIKE '' 这种无效查询,避免查询结果缺失。
分页参数容错
int validPage = page <= 0 ? 1 : page;
int validRow = row <= 0 ? 10 : row;
int offset = (validPage – 1) * validRow;
前端传入非法页码 / 每页条数(负数、0)时自动修正,防止数据库 limit offset,row 语法报错。
调用 Mapper 执行分页查询 + 总数统计
-
manualSelectAlarmRule:分页查询当前页数据,传递全部筛选参数;
-
manualCountAlarmRule:统计符合条件总条数,必须和查询参数完全一致,保证分页总条数和列表匹配。
分页结果兜底封装
dataPaging.setRows(rows != null ? rows : new ArrayList<>());
若 Mapper 查询返回 null 列表,替换为空集合,避免前端遍历列表时空指针异常。
三、核心方法 2:新增告警规则 add (AlarmRule alarmRule)
核心设计:后端强制管控主键、时间、阈值、运算符字段,杜绝前端脏数据
后端生成唯一主键 ID
String uuid = UUID.randomUUID().toString().replace("-", "");
alarmRule.setId(uuid);
完全忽略前端传入的 ID,UUID 去除横杠作为主键,防止主键冲突、前端随意篡改主键。
区分条件类型(range 区间 /single 单阈值),兜底填充运算符 operator
-
区间条件 range:运算符无意义,强制设为空字符串,避免数据库字段为 null;
-
单阈值 single:前端未传运算符时,兜底赋值空字符串;
阈值 thresholdValue 数值兜底(BigDecimal 类型不能为 null)
-
区间条件:单一阈值无业务意义,强制赋值 BigDecimal.ZERO;
-
单阈值条件:前端未传阈值时兜底 0,避免数据库 decimal 字段 null 报错。
统一填充时间戳
Date now = new Date();
alarmRule.setCreatedTime(now);
alarmRule.setUpdateTime(now);
创建时间、更新时间全部由后端生成,不依赖前端传参,保证数据时间准确。
数据库插入 + 异常捕获 try-catch 包裹数据库操作,出现 SQL 异常、类型转换异常时打印堆栈并返回 false,不会抛出异常中断上层逻辑。
四、核心方法 3:更新告警规则 update (AlarmRule alarmRule)
逻辑和 add 高度统一,专注更新场景字段兜底 + 刷新更新时间:
同样区分 range/single 条件类型,对 operator、thresholdValue 做非 null 兜底;
强制刷新更新时间:alarmRule.setUpdateTime(new Date());,记录最后修改时间;
try-catch 异常捕获,操作失败返回 false。
五、基础 CRUD 简单方法
1. 单条 / 全量查询、删除
@Override
public AlarmRule getById(String id) {
return alarmRuleMapper.selectById(id);
}
@Override
public List<AlarmRule> getAll() {
return alarmRuleMapper.selectAll();
}
@Override
public boolean deleteById(String id) {
return alarmRuleMapper.deleteById(id) > 0;
}
-
直接调用 Mapper 基础 SQL,逻辑极简;
-
删除判断 >0:仅当数据库真实删除数据时返回 true,无匹配数据返回 false。
2. 各类条件筛选查询
@Override
public List<AlarmRule> getByStatus(String status) {
return alarmRuleMapper.selectByStatus(status);
}
@Override
public List<AlarmRule> getByMetricId(String metricId) {
return alarmRuleMapper.selectByMetricId(metricId);
}
@Override
public List<AlarmRule> getByAlgorithmId(String algorithmId) {
return alarmRuleMapper.selectByAlgorithmId(algorithmId);
}
分别按状态、指标 ID、算法 ID筛选规则列表,供前端筛选、指标 / 算法详情页关联查询。
六、关联核心方法:getRulesByModelId (String modelId)
业务用途
根据告警模型 ID,查询该模型绑定的全部告警规则; 对应前文 AlarmModelServiceImpl 中规则树组装逻辑,是模型与规则关联的核心查询方法。
容错设计
try-catch 捕获数据库查询异常,异常时直接返回空 ArrayList,避免前端页面渲染空指针。
七、代码设计亮点总结
1. 极致的空指针、非法参数容错
-
分页参数 Map 判空;
-
分页页码、条数自动修正;
-
查询空字符串转 null 优化 SQL;
-
查询列表为 null 时替换空集合;
-
关联查询异常返回空列表。
2. 数据安全管控(新增 / 更新强约束)
主键 ID 完全后端生成,前端无法干预;
创建 / 更新时间统一后端赋值;
区分区间 / 单阈值两种业务类型,对运算符、阈值做强制非 null 兜底,适配达梦 decimal、varchar 字段非空约束,防止入库报错。
3. 分层职责清晰
-
Controller:只接收参数、调用 Service;
-
Service 接口:定义标准业务能力;
-
ServiceImpl:全部参数清洗、字段校验、业务判断、容错处理;
-
Mapper:仅执行 SQL,无任何业务逻辑。
4. 适配完整业务链路
覆盖「指标 ID→规则→算法 ID→告警模型」全链路关联查询,支撑告警模型规则树、前端多页面筛选、详情关联展示。
5. 异常处理友好
所有写库(新增、更新)、关联查询均包裹 try-catch,打印异常堆栈便于线上排查,同时返回布尔 / 空列表保证上层流程不会崩溃。
八、可优化改进建议
缺少事务注解 @Transactional add、update、批量关联操作未添加事务,多表联动操作异常时会产生脏数据,建议添加 @Transactional(rollbackFor = Exception.class)。
异常打印使用 e.printStackTrace () 不规范 项目已有日志框架 Logger,替换为 logger.error 打印异常,可输出日志文件、链路追踪,控制台堆栈不利于线上排查。
大量硬编码魔法字符串 range、single 条件类型、字段名、状态值分散硬编码,建议抽取全局常量类统一管理。
重复的 operator、thresholdValue 兜底逻辑 add 和 update 方法存在完全重复的字段兜底代码,可抽离私有工具方法复用,减少冗余代码。
未增加编码唯一性校验 无 getByRuleCode 方法,新增规则时无法校验 ruleCode 重复,易出现编码重复入库。
无批量操作实现 缺少批量新增、批量删除规则方法,前端批量操作只能循环调用单条接口,性能较差。
AlarmRuleTreeUnifiedController.java
一、整体定位
该控制器对应告警规则树形存储表(AlarmRuleTreeUnified),专门管理告警模型下的规则树节点数据,和前面 AlarmModelServiceImpl 中规则树后序遍历、组装详情的逻辑配套。 分层链路:前端告警模型编辑页 → 当前 Controller → AlarmRuleTreeUnifiedService → AlarmRuleTreeUnifiedMapper → 达梦数据库树形节点表。
二、头部基础信息
1. 包结构
package cn.com.xxx.bussiness.znyw.controller;
和告警模型、告警规则控制器同包,归属智能运维 ZNYW 模块接口层。
2. 导入依赖说明
业务层:AlarmRuleTreeUnifiedService 规则树业务接口;
实体:AlarmRuleTreeUnified 规则树节点实体(存储树形父子关系、节点类型、逻辑运算符、执行顺序等);
日志:@Slf4j lombok 日志注解,替代手动创建 Logger;
Web 注解:RESTful 接口标准注解;
容器:HashMap、List、Map 自定义返回结构。
3. 类注解
@Slf4j
@RestController
@RequestMapping("/api/alarm-rule-tree-unified")
@Slf4j:lombok 自动注入日志对象 log,简化日志打印;
@RestController:接口自动返回 JSON,无需 @ResponseBody;
全局接口前缀 /api/alarm-rule-tree-unified 完整请求示例:GET http://127.0.0.1:8091/api/alarm-rule-tree-unified/model/xxx;
自动注入 AlarmRuleTreeUnifiedService 业务层。
三、三个接口逐行拆解
接口 1:清空全部规则树数据 DELETE /api/alarm-rule-tree-unified/clear-all
业务作用
批量删除整张规则树表所有数据,多用于模型重建规则树、测试环境重置数据场景。
逻辑流程
初始化返回 Map,统一结构:success(布尔)、message(提示文本);
调用 service deleteAll() 执行全表删除;
根据删除结果填充成功提示;
全局捕获异常:
-
使用 log.error 打印完整异常堆栈(带异常对象 e,可记录堆栈);
-
返回 success=false + 异常信息给前端;
接口 2:根据模型 ID 查询整棵规则树 GET /api/alarm-rule-tree-unified/model/{modelId}
核心业务用途
告警模型详情 / 编辑页面加载完整规则树节点,是前面 AlarmModelServiceImpl 组装模型详情、规则排序的数据源。
逻辑流程
路径参数 modelId:告警模型主键;
调用 service getByModelId(modelId),返回该模型下全部树形节点集合;
返回 Map 结构:
-
success:请求标识;
-
data:树形节点 List(前端递归渲染规则树);
-
message:操作提示;
异常捕获并记录日志,返回失败信息。
接口 3:规则树数据统计接口 GET /api/alarm-rule-tree-unified/stats
现状说明
属于预留扩展接口,业务统计逻辑尚未实现,仅预留接口骨架。
规划可实现统计维度
-
规则树总节点数量;
-
根节点、逻辑节点、RULE 规则叶子节点各自数量;
-
各告警模型绑定规则树数量;
-
失效 / 废弃树形节点统计;
四、代码设计特点
1. 统一自定义返回结构(未使用全局 JsonMessage)
前面告警模型、告警规则控制器统一使用项目封装 JsonMessage<T> 标准返回体; 本控制器自主使用 HashMap 封装返回,结构为固定三字段:success、message、data(有数据时)。
差异点:通用业务 CRUD 走全局统一返回;树形特殊批量操作、重置接口自定义简易返回结构。
2. 日志规范更完善
使用 lombok @Slf4j,异常打印传入完整异常对象 log.error("xxx失败", e),日志文件会记录完整异常堆栈,线上排查树形 SQL、树形递归查询报错非常方便。
3. 接口语义严格遵循 REST 规范
-
全表清空:DELETE 请求(执行删除操作);
-
查询树形数据、统计数据:GET 请求(只读,无数据修改);
4. 异常容错全覆盖
三个接口全部包裹 try-catch,任何数据库异常、树形数据解析异常不会直接抛出 500 错误,统一返回前端可读的失败提示,同时落地日志留存问题记录。
五、前后端业务联动关系
前端页面(ZNYW 智能运维告警模型页面)
编辑告警模型,加载已有规则树:调用 /model/{modelId},拿到所有树形节点递归渲染前端可视化规则树;
重建 / 重置模型规则:调用 /clear-all 清空旧树形节点,后端重新生成规则树节点;
规则树数据看板:后续完善 /stats 统计接口,展示规则节点数量、结构指标。
后端配套链路
数据库:达梦 ZNYW 库 t_alarm_rule_tree_unified 规则树统一节点表;
联动 AlarmModel 模块:AlarmModelServiceImpl.getByIdWithDetails() 会调用本模块 Mapper 查询树形节点,完成规则后序排序、组装详情返回前端;
业务逻辑:新增 / 修改告警模型配置时,后端会批量插入、更新、删除该 modelId 对应的树形节点,本控制器提供手动清空、查询树形节点的运维接口。
六、优化建议
1. 统一项目标准返回体 JsonMessage
当前使用 HashMap 自定义返回,和项目其他控制器格式不统一,前端需要写两套解析逻辑。 改造示例:
return new JsonMessage<List<AlarmRuleTreeUnified>>().success(nodes);
2. 全表清空接口增加权限校验与二次确认参数
/clear-all 是高危批量删除接口,生产环境存在误操作风险:
添加权限注解 @PreAuthorize("hasRole('ADMIN')"),仅管理员可调用;
增加请求参数 @RequestParam String confirm,前端传入confirm=1才执行删除,防止误调用。
3. 抽离通用返回 Map 构建工具方法
三个接口重复创建 HashMap、填充 success/message/data,可抽离私有工具方法简化代码。
4. 完善 stats 统计接口
补充节点分类统计、模型规则数量统计,用于后台数据看板展示。
5. 新增单节点新增、编辑、删除接口
当前仅支持全表清空、按模型查询,缺少对单个树形节点的增删改接口,前端编辑规则树时需要后端补充对应接口。
6. 增加事务控制提醒
deleteAll() 全表删除操作建议在 Service 实现类方法添加 @Transactional,防止删除中途数据库异常导致数据半删残留。
早上就看上述文件代码,后续的告警引擎和定时任务部分的文件代码下午再看。
让我复习一下今天早上干了什么工作内容。
早上起来收拾整理回忆复习上周周五的工作内容,然后
不想那些不开心的事情,记住,永远不要去改变一个人,你只需要做的,就是远离他们。
首先开了例行早会,说了一下公司配置的glm的事情,然后就是进行每天的例行汇报,之后就强调了一下各个项目开发小组之间的沟通和共同的项目了解。
早会结束。
我回来就先总结了例行早会的内容,之后我就开始背单词,感觉这次背单词很有用,我是在电脑上背诵单词的,感觉很有用,因为我感受到我的脑子在发热,大脑里的神经元连接起来了,之后我听英语口语视频的时候我感觉我也能很快听懂。很有用。
接下来我就开始看相关代码文件。
我是分为两个阶段来看的。
第一阶段是配置入口类代码文件。
businessRunApplication.java后端入口类文件。
application.yml数据库配置文件
rounter.define.js前端路由配置文件
第二阶段是告警功能类的文件。这些文件都是后端文件。
分为四个小组来进行查看的。
告警模型
告警规则
告警引擎
定时任务
这四个小组
主要是按照这个流程来进行查看代码的,controller->service->impl->mapper,这个流程是一个规定的数据流转的流程。
会涉及到简单的CRUD的操作,后续查找还有借助很多条件来进行查找。
跨域问题,统一端口问题,接口API,
包package,导入import,注解@,
JMX,jdk,
复习复习复习复习
加油,郑卓颖,你可以的!!
还有一部分其实也可以回想今天背的英语单词。
function,definetily,roster,canoe,cirulation,circle,obtain,currency,local,logical,logicalist,ketchup,gourmet,supper,cutlery,formal,forum,chunk,photographic,record,comment,commend,company,closet,
告警引擎(核心)
AlarmEngine.java
一、整体定位与业务作用
这是ZNYW 智能运维系统核心计算引擎,独立包 cn.com.xxx.bussiness.znyw.engine,是定时任务调度执行告警判断的核心业务类。 整体业务链路:定时任务触发 → AlarmEngine.executeModel (模型 ID) 核心四大流程:
读取数据库规则树,构建内存树形结构;
查询告警模型绑定的全部监控设备 / 对象;
逐个监控对象拉取指标实时数据,递归 / 栈式遍历规则树做阈值、逻辑运算判断;
生成完整执行结果(是否告警、触发规则、耗时、错误信息),后续可落地入库、生成巡检工单。
分层依赖结构:
AlarmEngine(引擎调度入口)
├─ RuleTreeBuilder:规则树构建器
├─ RuleEvaluator:规则树计算评估器
├─ ModelMonitorRelMapper:模型-监控对象关联表查询
├─ MonitorObjectMapper:监控对象基础信息查询
└─ AlarmEngineMapper:引擎专属数据查询(指标时序数据等)
二、头部基础信息
1. 包与注解
package cn.com.xxx.bussiness.znyw.engine;
@Slf4j
@Component
public class AlarmEngine
@Component:注册为 Spring 容器 Bean,定时任务 Service 可直接注入调用;
@Slf4j:Lombok 日志注解,全流程打印分级日志,用于线上引擎执行排查;
2. 导入类分类说明
引擎内部工具
-
RuleTreeBuilder:读取规则树数据表,组装内存 RuleTreeNode 树形对象;
-
RuleEvaluator:栈遍历规则树、计算指标阈值、AND/OR 逻辑判断;
-
RuleTreeNode:内存规则树节点实体;
-
AlarmEngineResult:单次监控对象执行结果封装实体;
数据库 Mapper
-
ModelMonitorRelMapper:查询模型与监控对象绑定关系;
-
MonitorObjectMapper:查询监控对象名称等基础信息;
-
AlarmEngineMapper:拉取监控对象对应指标时序数值(计算引擎数据源);
数据库实体
-
MonitorObject:监控对象实体(油田设备、站点等);
时间、集合工具:LocalDateTime、ArrayList、流处理,用于耗时计算、结果汇总。
3. 依赖注入成员变量
@Autowired
private RuleTreeBuilder ruleTreeBuilder; // 构建规则树
@Autowired
private RuleEvaluator ruleEvaluator; // 规则计算评估
@Autowired
private ModelMonitorRelMapper modelMonitorRelMapper; // 模型-监控对象关联
@Autowired
private MonitorObjectMapper monitorObjectMapper; // 监控对象信息
@Autowired
private AlarmEngineMapper alarmEngineMapper; // 指标数据查询
职责完全拆分,单一工具类只做一件事,引擎仅做流程调度,不掺杂构建、计算逻辑。
三、核心入口方法 executeModel (String modelId)
对外暴露的主执行方法,定时任务、后台手动执行均调用该方法,完整实现一整套告警模型批量计算流程,分步拆解:
步骤 1:日志标记模型开始执行,初始化结果集合
log.info("========== 开始执行告警模型: {} ==========", modelId);
List<AlarmEngineResult> results = new ArrayList<>();
步骤 2:RuleTreeBuilder 构建内存规则树
RuleTreeNode ruleTree = ruleTreeBuilder.buildRuleTree(modelId);
if (ruleTree == null) {
log.warn("模型 {} 没有配置规则树,跳过执行", modelId);
return results;
}
ruleTreeBuilder.printRuleTree(ruleTree);
根据模型 ID 查询 t_alarm_rule_tree_unified 规则树节点表,递归组装完整树形结构;
无规则树直接终止执行,避免空指针;
打印树形结构日志,开发调试查看规则层级、逻辑运算符。
步骤 3:查询当前模型绑定的所有监控对象
通过中间关联表 t_model_monitor_rel 查询绑定的监控对象 ID 集合,这里使用反射读取关联实体的 getMonitorObjectId():
List objectRels = modelMonitorRelMapper.selectByModelId(modelId);
// 循环+反射提取监控对象ID
-
兼容通用关联实体,无需硬编码实体类,通用性强;
-
捕获反射异常,单条读取失败不中断整体流程,仅打印警告日志。
步骤 4:无绑定监控对象直接终止
if (objectIds.isEmpty()) {
log.warn("模型 {} 没有绑定监控对象,跳过执行", modelId);
return results;
}
步骤 5:循环每个监控对象,独立执行规则评估
for (String objectId : objectIds) {
AlarmEngineResult result = executeForObject(modelId, objectId, ruleTree);
results.add(result);
}
隔离设计:每个监控对象独立执行、独立生成结果,单个设备计算报错不会影响其他设备。
步骤 6:执行完成汇总统计
long triggeredCount = results.stream().filter(AlarmEngineResult::isTriggered).count();
log.info("总对象数: {}, 触发告警: {}, 未触发: {}", …);
使用流式统计触发告警的设备数量,输出汇总日志,便于运维查看当日告警总量。
异常兜底
外层大 try-catch 捕获模型执行全流程所有异常,打印完整堆栈,不会导致定时任务崩溃中断。
四、核心子方法 executeForObject 单个监控对象规则评估
最小执行单元,针对单台监控设备,完成「基础信息加载 → 规则树重置 → 栈式计算评估 → 结果封装」全流程。
1. 初始化执行结果实体 AlarmEngineResult
封装本次计算所有元数据:
-
唯一执行 ID generateExecutionId():毫秒时间戳 + 随机数,用于日志、告警记录关联;
-
模型 ID、监控对象 ID;
-
监控对象名称(从 MonitorObject 表查询,失败则使用 ID 兜底);
-
执行起止时间、初始状态 RUNNING。
2. 重置规则树评估状态
ruleTree.resetEvaluation();
规则树节点会缓存上次计算的布尔结果,多个监控对象循环计算前必须清空缓存,避免上一个设备的计算结果污染当前设备。
3. RuleEvaluator 执行规则树计算(引擎核心运算逻辑)
boolean treeResult = ruleEvaluator.evaluateRuleTree(ruleTree, objectId, result);
底层采用栈后序遍历规则树,依次执行:
拉取该监控对象对应指标实时数值(AlarmEngineMapper 查询时序库 / 达梦指标表);
执行单条规则阈值判断(> / < / = / 区间判断);
根据父节点 AND/OR 逻辑运算符合并子规则布尔结果;
把触发的规则、告警信息写入 AlarmEngineResult;
返回整棵规则树最终布尔值(true = 触发告警)。
4. 执行结果状态赋值
result.setTriggered(treeResult);
result.setStatus("SUCCESS");
5. 异常捕获 + 耗时计算 finally 块
无论计算成功或失败,都会记录:
结束时间、总执行耗时(毫秒);
计算失败时状态改为 FAILED,记录异常信息;
五、工具私有方法 generateExecutionId
生成全局唯一执行标识,格式 EXEC_毫秒时间戳_随机数,作用:
每条告警记录、引擎执行日志都携带该 ID,可全链路追踪;
区分同一模型、同一设备多次定时执行记录。
AlarmEngineService.java
一、类整体定位
该类是告警引擎对外的 Service 层,封装底层AlarmEngine、RuleTreeBuilder能力,提供可被 Controller、定时任务、其他业务模块调用的标准化接口,职责:
封装规则树构建逻辑,统一做规则树非空校验;
对外提供单监控对象独立执行告警能力;
提供调试接口,格式化输出整棵规则树文本结构,方便开发 / 运维排查规则配置问题;
统一日志打印,对外屏蔽底层引擎、构造器的复杂细节。
分层依赖关系:
AlarmEngineService(门面服务)
├─ AlarmEngine:核心告警计算引擎(批量 / 单对象执行逻辑)
└─ RuleTreeBuilder:规则树构造工具,从数据库组装内存树形节点
二、头部基础信息
1. 包路径
package cn.com.xxx.bussiness.znyw.engine.service;
独立引擎业务服务包,和核心计算引擎AlarmEngine(engine包)分层隔离,遵循门面模式:底层计算逻辑放在 engine 包,对外调用入口统一放在 engine.service 包。
2. 注解说明
@Slf4j
@Service
public class AlarmEngineService
@Service:注册为 Spring 业务 Bean,Controller、定时任务可直接@Autowired注入使用;
@Slf4j:Lombok 日志注解,所有操作打印分级日志,便于线上追踪执行记录。
3. 依赖注入
@Autowired
private AlarmEngine alarmEngine;
@Autowired
private RuleTreeBuilder ruleTreeBuilder;
-
RuleTreeBuilder:复用规则树构建逻辑,两个接口都需要先加载模型规则树;
-
AlarmEngine:调用底层最小执行单元executeForObject,完成单设备告警评估。
三、对外接口逐行详解
接口 1:executeForObject (String modelId, String objectId)
功能描述
单独执行某一个监控对象的告警规则计算,区别于AlarmEngine.executeModel批量执行模型下所有监控对象。 适用场景:
前端手动选中单个设备,一键执行告警检测;
工单触发时,单独对故障设备执行规则校验;
测试单台监控对象的规则配置是否生效。
完整逻辑流程
打印操作日志,记录模型 ID、监控对象 ID;
调用ruleTreeBuilder.buildRuleTree(modelId)加载模型规则树;
强校验:规则树为 null 直接抛出运行时异常,终止执行;
对比底层 AlarmEngine 只是打印警告并返回空集合,本服务作为上层调用门面,业务上无规则树属于非法配置,直接抛异常让调用方感知错误;
调用底层引擎单对象评估方法,返回完整AlarmEngineResult告警执行结果(包含是否触发告警、触发规则、执行耗时等)。
异常设计
无规则树时主动抛出RuntimeException,上层 Controller 可全局捕获异常,转换为前端可读错误提示。
接口 2:getRuleTreeStructure (String modelId)
功能描述
调试专用接口,将数据库存储的扁平规则节点,递归格式化输出带层级缩进的文本字符串,直观展示规则树父子层级、节点类型、运算符、规则名称编码。 适用场景:
开发调试:查看前端配置的规则树是否正确入库、父子关系是否错乱;
运维排查:告警触发异常时,核对逻辑节点 AND/OR 运算符配置;
接口可视化:前端可调用该接口,展示纯文本树形预览。
逻辑流程
打印调试日志,记录当前查询的模型 ID;
构建模型对应的规则树,若树为空直接返回文本规则树为空;
调用私有递归方法buildTreeString,逐层拼接带缩进的树形字符串;
返回完整格式化文本给调用方。
四、私有递归工具方法 buildTreeString
核心作用
递归遍历规则树根节点及所有子节点,根据节点层级添加空格缩进,区分逻辑节点与规则条件节点,拼接可读文本。
分支处理逻辑
空节点直接 return,避免空指针;
根据层级 level 循环拼接空格缩进,实现树形层级视觉区分;
节点类型区分渲染:
-
逻辑节点 LogicNode:打印节点 ID + 逻辑运算符(AND/OR);
-
规则条件节点 ConditionNode:打印节点 ID + 规则名称 + 规则编码; 无规则信息时兜底显示「未知」;
递归遍历当前节点所有子节点,层级 level+1,深度遍历整棵树。
输出文本示例
[逻辑节点] root-001 – 运算符: AND
[逻辑节点] node-002 – 运算符: OR
[规则节点] rule-003 – 规则: 温度超限 (RULE001)
[规则节点] rule-004 – 规则: 压力过高 (RULE002)
[规则节点] rule-005 – 规则: 流量过低 (RULE003)
AlarmEngineController.java
一、整体定位
这是告警引擎对外 HTTP 接口层,为前端页面、第三方系统提供手动触发告警计算、批量执行、规则树调试的 REST 接口。 分层调用链路:前端 HTTP 请求 → AlarmEngineController → AlarmEngineService/AlarmEngine → RuleTreeBuilder/RuleEvaluator → 数据库(规则树、监控对象、指标)
依赖注入说明
@Autowired
private AlarmEngine alarmEngine; // 底层批量执行核心引擎
@Autowired
private AlarmEngineService alarmEngineService; // 门面服务,提供单对象执行、规则树文本调试
职责拆分清晰:
批量执行全量监控对象、多模型批量执行:直接调用底层AlarmEngine;
单监控对象执行、规则树格式化调试:调用门面AlarmEngineService。
二、基础头部信息
1. 包路径
package cn.com.xxx.bussiness.znyw.engine.controller;
专属引擎模块的 Controller 包,和 engine 核心计算类、engine.service 门面服务分层隔离。
2. 注解说明
@Slf4j
@RestController
@RequestMapping("/api/alarmEngine")
@Slf4j:日志注解,所有接口入参、异常都会打印日志,线上问题排查;
@RestController:接口自动返回 JSON,无需额外@ResponseBody;
统一接口前缀:/api/alarmEngine,所有引擎接口统一路径;
Swagger 相关注解全部注释禁用,项目未接入接口文档框架。
3. 返回格式规范
本控制器统一使用 HashMap 自定义返回结构,和项目其他模块JsonMessage<T>全局标准返回体不一致,统一结构模板:
{
"success": true/false,
"message": "操作提示文字",
"data": { 业务数据对象 }
}
每个接口独立 try-catch 捕获全部异常,异常时返回success=false+ 错误信息,不会抛出 500 原始堆栈给前端。
三、4 个接口逐行拆解
接口 1:POST /api/alarmEngine/executeModel
功能
执行单个告警模型,批量计算该模型绑定的所有监控对象 前端场景:告警模型详情页,点击「执行检测」,批量计算全部设备告警。
入参
@RequestParam String modelId 告警模型 ID(URL 传参)
核心业务逻辑
打印请求日志,记录模型 ID;
调用底层alarmEngine.executeModel(modelId)获取所有监控对象执行结果;
流式统计汇总数据:
-
totalObjects:绑定监控对象总数量
-
triggeredObjects:触发告警的设备数量
-
totalAlarms:所有设备产生告警记录总数
组装统一返回 JSON,携带汇总统计 + 每条设备完整执行明细;
异常捕获,记录完整异常堆栈,返回失败提示。
返回 data 结构示例
"data": {
"modelId": "xxx",
"totalObjects": 10,
"triggeredObjects": 2,
"totalAlarms": 3,
"results": [每条监控对象执行结果AlarmEngineResult数组]
}
接口 2:POST /api/alarmEngine/executeForObject
功能
单独执行单个监控对象的告警规则计算 前端场景:单独选中某台设备,手动单点检测;工单触发单独校验故障设备。
入参
modelId 模型 ID、objectId 监控对象 ID,均为 URL 参数传递。
逻辑流程
打印请求日志,记录两个 ID;
调用门面服务alarmEngineService.executeForObject(modelId, objectId);
直接返回单个设备完整执行结果AlarmEngineResult;
异常捕获返回失败信息。
接口 3:POST /api/alarmEngine/executeModels
功能
批量执行多个告警模型,一次性传入多个 modelId,循环逐个执行模型全量设备检测。 前端场景:后台批量巡检任务、定时任务手动批量触发全部告警模型。
入参
@RequestBody List<String> modelIds 请求体 JSON 数组,多个模型 ID 集合。
核心逻辑
打印批量执行日志;
循环遍历每个模型 ID,调用alarmEngine.executeModel执行;
汇总全局统计指标:
-
totalModels:本次执行模型总个数
-
totalTriggered:全部触发告警的监控对象总数
-
totalAlarms:所有模型产生告警记录总数
存储每个模型对应的设备执行明细 Map;
组装批量执行汇总结果返回前端。
接口 4:GET /api/alarmEngine/testRuleTree
功能
调试接口:构建规则树并返回格式化文本树形结构,用于排查规则树配置错误、父子节点、逻辑运算符异常。 前端场景:规则树配置预览、运维排查告警异常。
入参
@RequestParam String modelId 模型 ID。
逻辑流程
打印调试日志;
调用alarmEngineService.getRuleTreeStructure(modelId),获取带层级缩进的纯文本规则树;
返回文本内容给前端展示;
捕获构建规则树失败异常,返回错误信息。
定时任务
AlarmTaskController.java
一、整体定位
该控制器属于 ZNYW 智能运维告警定时任务模块,提供告警定时任务的全套 CRUD、多条件分页筛选、条件查询接口。 整体分层链路:前端页面请求 → AlarmTaskController → AlarmTaskService → Mapper → 达梦数据库 t_alarm_task 告警定时任务表。 和前面 AlarmEngine 告警引擎配套:AlarmTask 是定时调度配置,AlarmEngine 是实际执行计算逻辑。
核心业务关系
AlarmTask:存储定时任务配置(任务名称、cron 执行表达式、绑定告警模型、启停状态、执行类型);
Spring @EnableScheduling 定时框架读取任务配置,定时调用 AlarmEngine 执行告警模型计算。
二、头部基础信息
1. 包路径
package cn.com.xxx.bussiness.znyw.controller;
和告警引擎、告警模型、告警规则控制器同包,统一智能运维接口层。
2. 导入类说明
分页工具:DataPaging 项目统一分页载体;
全局标准返回体:JsonMessage<T>,本控制器统一使用项目规范返回对象,和前面告警引擎 Controller 手动 HashMap 返回形成区分;
实体:AlarmTask 告警定时任务数据库实体;
业务层:AlarmTaskService 任务业务接口;
Spring Web RESTful 标准注解;
容器:HashMap、List、Map 用于封装分页筛选参数。
3. 类注解与依赖注入
@RestController
@RequestMapping("/api/alarmTask")
@Autowired
private AlarmTaskService alarmTaskService;
@RestController:接口自动序列化为 JSON;
全局接口前缀 /api/alarmTask,所有定时任务接口统一路径;
仅注入 AlarmTaskService,所有业务逻辑下沉至 Service 层,Controller 仅处理请求参数、调用业务、封装返回。
三、全部接口逐段详解(标准 REST 规范)
接口 1:分页多条件查询 GET /api/alarmTask/list/page
用途:前端告警任务管理列表页面,分页 + 多维度筛选任务。
入参说明
|
taskName |
非必填 |
无 |
任务名称模糊查询 |
|
taskCode |
非必填 |
无 |
任务编码精确匹配 |
|
executionType |
非必填 |
无 |
执行类型(定时 / 手动)筛选 |
|
status |
非必填 |
无 |
任务启用 / 停用状态筛选 |
|
page |
必填 |
1 |
当前页码,不传默认第一页 |
|
row |
必填 |
10 |
每页条数,不传默认 10 条 |
逻辑流程
初始化空 Map,仅将非空、非空白的筛选参数存入 map,避免传递空字符串给 SQL;
调用 service 分页查询方法,返回分页对象 DataPaging<AlarmTask>;
使用全局标准返回体 JsonMessage<DataPaging<AlarmTask>> 返回成功数据;
全局 try-catch 捕获所有异常,统一返回失败提示文案。
接口 2:根据主键 ID 查询单条任务 GET /{id}
路径参数 id:告警任务主键;
逻辑:
-
查询实体不为空返回成功数据;
-
无数据返回业务提示「未找到对应的告警任务」;
-
异常捕获返回失败信息。
接口 3:查询全部任务 GET /all
返回无分页的全量任务列表,业务场景:下拉选择框、数据字典加载,适用于任务总量不大场景。
接口 4:新增告警定时任务 POST /add
@RequestBody AlarmTask:接收前端表单完整 JSON 任务实体;
调用 service 新增方法,根据返回布尔值判断新增是否成功;
捕获入库异常,返回失败提示。
接口 5:修改告警定时任务 PUT /update
遵循 REST 规范,PUT 用于全量更新任务配置;接收完整 AlarmTask 实体,Service 层根据主键 ID 更新数据库记录。
接口 6:删除告警定时任务 DELETE /{id}
标准 DELETE 删除接口,根据主键执行删除操作,返回删除结果布尔值。
接口 7:按状态筛选任务 GET /byStatus
入参 status,查询指定启用 / 停用状态的全部定时任务,用于前端列表状态筛选下拉。
接口 8:按执行类型筛选 GET /byExecutionType
入参 executionType,根据执行类型(自动定时执行、手动触发)筛选任务列表。
AlarmTaskService.java
一、接口整体定位
这是告警定时任务模块的业务层标准抽象接口,遵循项目统一分层架构:Controller → Service接口 → ServiceImpl实现类 → Mapper。 接口仅定义全部业务能力契约,只声明方法、入参、返回值与 JavaDoc 注释,无任何业务逻辑、数据库操作;实现类AlarmTaskServiceImpl完成参数处理、SQL 调用、数据校验等逻辑。
设计核心价值(面向接口编程)
分层解耦:Controller 只依赖抽象接口,不绑定具体实现类;后续更换数据源、重构业务逻辑,仅修改 ServiceImpl,上层 Controller 完全不用改动。
单元测试友好:单元测试可直接 Mock 本接口,无需连接真实达梦数据库。
统一开发规范:和前面AlarmModelService、AlarmRuleService接口格式、方法命名、注释规范完全统一,团队协作可读性高。
二、基础头部信息
1. 包路径
package cn.com.xxx.bussiness.znyw.service;
和告警模型、告警规则业务接口同包,统一智能运维 ZNYW 模块业务接口层。
2. 导入依赖说明
DataPaging:项目全局通用分页封装对象,分页查询统一返回该载体;
AlarmTask:数据库t_alarm_task告警定时任务表实体,CRUD 操作的入参、返回载体;
集合容器:List承载多条任务数据,Map<String,Object>承载动态多条件分页筛选参数。
三、全部方法分组拆解
分组 1:分页多条件列表查询(前端任务列表核心接口)
DataPaging<AlarmTask> selectPagingAlarmTaskList(Map<String, Object> paramMap, int page, int row);
入参:
-
paramMap:动态筛选条件 Map,承载任务名称、任务编码、执行类型、状态等多维度查询条件;
-
page 当前页码、row 每页展示条数;
返回:分页封装对象DataPaging<AlarmTask>,包含总数据条数、当前页任务列表;
对应 Controller 接口:GET /api/alarmTask/list/page。
分组 2:基础单表 CRUD(增删改查基础能力)
// 根据主键ID查询单条定时任务详情
AlarmTask getById(String id);
// 查询全量无分页任务列表(下拉选择、字典)
List<AlarmTask> getAll();
// 新增告警定时任务
boolean add(AlarmTask alarmTask);
// 更新告警定时任务配置
boolean update(AlarmTask alarmTask);
// 根据主键删除定时任务
boolean deleteById(String id);
返回值boolean含义:数据库操作受影响行数 > 0 则返回 true(操作成功),无匹配数据返回 false;
业务场景:新增 / 编辑 / 删除弹窗、单条详情回显、页面下拉加载全部定时任务;
对应 Controller 接口:/{id}、/all、POST /add、PUT /update、DELETE /{id}。
分组 3:唯一性校验专用方法(新增任务编码重复校验)
AlarmTask getByTaskCode(String taskCode);
-
作用:根据任务编码 taskCode精确查询任务实体;
-
核心业务场景:新增定时任务时校验编码唯一性,防止数据库存在重复编码导致业务冲突;
-
当前 Controller 未提供前端调用接口,属于内部业务校验方法,供 add 新增逻辑前置校验。
分组 4:条件批量筛选查询(页面下拉过滤)
// 根据任务启停状态批量查询
List<AlarmTask> getByStatus(String status);
// 根据任务执行类型批量查询(自动定时/手动执行)
List<AlarmTask> getByExecutionType(String executionType);
getByStatus:筛选启用 / 停用的定时任务列表;
getByExecutionType:按执行类型筛选任务;
对应 Controller 接口:/byStatus、/byExecutionType,用于前端列表筛选下拉框。
四、接口与 Controller 完整映射对照表
|
selectPagingAlarmTaskList |
/api/alarmTask/list/page |
告警定时任务管理列表分页、多条件筛选 |
|
getById |
/api/alarmTask/{id} |
编辑弹窗回显单条任务完整配置 |
|
getAll |
/api/alarmTask/all |
告警模型新增页面下拉选择绑定定时任务 |
|
add |
POST /api/alarmTask/add |
新增定时任务弹窗提交 |
|
update |
PUT /api/alarmTask/update |
编辑定时任务表单保存配置 |
|
deleteById |
DELETE /api/alarmTask/{id} |
列表删除按钮操作 |
|
getByTaskCode |
内部调用,无前端接口 |
新增任务时校验 taskCode 编码唯一性 |
|
getByStatus |
/api/alarmTask/byStatus |
列表按任务启停状态筛选 |
|
getByExecutionType |
/api/alarmTask/byExecutionType |
列表按执行类型筛选 |
AlarmTaskServiceImpl.java
一、整体定位
本类是 AlarmTaskService 接口的完整实现层,分层链路:Controller → AlarmTaskService接口 → AlarmTaskServiceImpl实现类 → AlarmTaskMapper → 达梦数据库 t_alarm_task。 核心职责:参数清洗、业务默认值兜底、主键 / 时间管控、分页计算、数据库 SQL 调用、非法参数拦截,和前面 AlarmModelServiceImpl、AlarmRuleServiceImpl 编码规范、安全校验逻辑完全统一。
二、头部基础信息
1. 包与注解
package cn.com.xxx.bussiness.znyw.serviceImpl;
@Service
public class AlarmTaskServiceImpl implements AlarmTaskService
@Service:Spring 将当前类注册为业务层 Bean,上层 Controller 通过接口注入;
实现 AlarmTaskService 接口,强制实现接口内全部方法,约束业务能力规范。
2. 依赖注入
@Autowired
private AlarmTaskMapper alarmTaskMapper;
仅注入对应 Mapper,所有数据库操作均通过 Mapper 完成,业务实现层不写原生 SQL。
3. 导入类说明
-
DataPaging:统一分页返回载体;
-
AlarmTask:定时任务数据库实体;
-
AlarmTaskMapper:Mybatis 持久层;
-
UUID:后端生成主键 ID;
-
Date:创建 / 更新时间戳;
-
集合、Map:分页参数封装。
三、核心分页查询方法 selectPagingAlarmTaskList
1. 参数提取与清洗
从 paramMap 取出 4 个筛选条件,统一执行 trim() 去除前后空格,避免空格干扰查询。
2. 条件转换(Mybatis 动态 SQL 优化核心)
-
taskName 模糊查询:非空自动拼接 %关键词%,交给 Mapper 做 like 模糊匹配;
-
其余参数(taskCode、executionType、status)空字符串转为 null; 作用:Mybatis 动态 SQL 会自动忽略值为 null 的条件,不会拼接 AND xxx='' 无效语句,保证查询结果正确。
3. 分页参数容错处理
if (page <= 0) page = 1;
if (row <= 0) row = 10;
int offset = (page – 1) * row;
前端传入非法分页值(负数、0)自动修正,避免数据库 limit 语法报错。
4. 双 Mapper 查询
manualSelectAlarmTask:分页查询当前页数据列表;
manualCountAlarmTask:统计符合筛选条件总条数; 两条 SQL 传入完全相同的筛选参数,保证分页总数和列表数据匹配。
5. 分页对象封装
实例化 DataPaging,填充列表 rows 与总条数 total,返回给上层 Controller。
四、基础 CRUD 方法详解
1. add 新增定时任务(后端强管控,杜绝前端脏数据)
@Override
public boolean add(AlarmTask alarmTask) {
// 1. 后端生成唯一主键,完全忽略前端传入ID
String id = UUID.randomUUID().toString().replaceAll("-", "");
alarmTask.setId(id);
// 2. 统一时间戳,创建/更新时间由服务端生成
Date now = new Date();
alarmTask.setCreatedTime(now);
alarmTask.setUpdateTime(now);
// 3. 状态默认值兜底,未传则启用状态1
if (alarmTask.getStatus() == null || alarmTask.getStatus().trim().isEmpty()) {
alarmTask.setStatus("1");
}
// 4. 并发级别兜底,默认单线程执行定时任务
if (alarmTask.getConcurrencyLevel() == null) {
alarmTask.setConcurrencyLevel(1);
}
return alarmTaskMapper.insert(alarmTask) > 0;
}
安全设计亮点
主键完全后端管控:UUID 去除横杠生成唯一 ID,前端传递的 ID 直接覆盖,防止主键冲突、恶意篡改;
时间戳服务端统一生成:创建时间、更新时间不依赖前端传参,保证数据时间准确;
业务字段默认值兜底
-
status 任务启停状态,空值默认启用1;
-
concurrencyLevel 定时任务并发数,空值默认 1(防止多线程并发执行告警引擎造成资源挤压);
返回布尔值:数据库插入受影响行数 > 0 才返回 true,区分插入成功 / 无数据。
2. update 更新方法
@Override
public boolean update(AlarmTask alarmTask) {
// 更新操作必须携带主键ID,无ID直接抛出非法参数异常
if (alarmTask.getId() == null || alarmTask.getId().trim().isEmpty()) {
throw new IllegalArgumentException("更新操作必须指定ID");
}
// 强制刷新更新时间戳
alarmTask.setUpdateTime(new Date());
return alarmTaskMapper.update(alarmTask) > 0;
}
前置强校验:更新实体无主键 ID 直接抛异常,拦截无效更新 SQL;
自动刷新 updateTime,记录本次修改时间;
根据数据库影响行数判断操作结果。
3. deleteById 删除、单条 / 全量查询
@Override
public AlarmTask getById(String id) {
return alarmTaskMapper.selectById(id);
}
@Override
public List<AlarmTask> getAll() {
return alarmTaskMapper.selectAll();
}
@Override
public boolean deleteById(String id) {
return alarmTaskMapper.deleteById(id) > 0;
}
极简封装,直接调用 Mapper 对应 SQL;删除操作判断返回行数,仅真实删除数据返回 true。
五、条件筛选查询方法
@Override
public AlarmTask getByTaskCode(String taskCode) {
return alarmTaskMapper.selectByTaskCode(taskCode);
}
@Override
public List<AlarmTask> getByStatus(String status) {
return alarmTaskMapper.selectByStatus(status);
}
@Override
public List<AlarmTask> getByExecutionType(String executionType) {
return alarmTaskMapper.selectByExecutionType(executionType);
}
getByTaskCode:根据任务编码精确查询,用于新增任务时校验编码唯一性,避免重复编码入库;
getByStatus:按启停状态筛选定时任务列表;
getByExecutionType:按执行类型(定时 / 手动)筛选任务; 以上方法均直接调用 Mapper 查询,无额外业务逻辑。
TaskSchedulerController.java
一、整体定位与业务作用
该控制器归属 cn.com.xxx.bussiness.znyw.scheduler 调度专属包,是告警定时任务动态调度的 HTTP 操作入口。 和前面 AlarmTaskController 做清晰职责拆分:
AlarmTaskController:CRUD 层,只负责数据库 t_alarm_task 任务配置的增删改查;
TaskSchedulerController:调度运行控制层,负责内存中 Spring 定时任务的动态启停、手动执行、刷新、状态查询,不直接操作数据库,通过 DynamicTaskManager 同步数据库状态与内存调度器。
核心依赖组件
@Autowired
private AlarmTaskExecutor alarmTaskExecutor; // 任务执行器,调用告警引擎AlarmEngine计算告警
@Autowired
private DynamicTaskManager dynamicTaskManager; // 动态定时任务管理器,管理Spring调度器注册/取消任务
业务完整链路: 前端调用调度接口 → TaskSchedulerController → DynamicTaskManager(操作调度器 + 同步数据库任务状态)/ AlarmTaskExecutor(触发告警引擎执行规则计算)→ AlarmEngine 告警引擎执行规则判断
二、基础头部信息
1. 包路径
package cn.com.xxx.bussiness.znyw.scheduler;
单独scheduler调度模块包,和 controller 业务包隔离,分层清晰。
2. 注解说明
@RestController
@RequestMapping("/api/taskScheduler")
@RestController:接口返回自动序列化为 JSON;
统一接口前缀 /api/taskScheduler,所有定时任务调度操作统一路径;
统一使用项目标准返回对象 JsonMessage<T>,和其他业务控制器返回格式保持统一。
三、5 个接口逐行拆解
接口 1:POST /api/taskScheduler/execute/{taskId} 手动执行告警任务
业务场景
前端页面不等待定时 cron 周期,手动立即触发一次告警任务,调用告警引擎完成全量监控对象规则计算。
执行逻辑
路径参数 taskId:告警任务主键 ID;
调用 alarmTaskExecutor.executeTask(taskId),返回全局唯一执行 ID executionId;
判断 executionId 是否为空:
-
为空:任务不存在 / 已禁用,返回业务失败提示;
-
有值:封装执行 ID、任务 ID、成功提示返回前端;
全局 try-catch 捕获所有执行异常,返回异常信息。
返回数据说明
{
"success": true,
"data": {
"executionId": "EXEC_175xxxx",
"taskId": "任务主键",
"message": "任务执行成功"
}
}
executionId 可用于后续查询本次告警执行明细、日志。
接口 2:POST /api/taskScheduler/enable/{taskId} 启用定时任务
业务作用
更新数据库 t_alarm_task 任务状态为启用;
将该任务的 cron 表达式注册到 Spring 定时调度器,定时自动执行。
逻辑流程
传入任务 ID,调用 dynamicTaskManager.enableTask(taskId);
封装返回参数:任务 ID、是否启用成功、当前任务是否注册在调度器;
根据返回布尔值区分成功 / 失败,返回对应提示;
捕获数据库 / 调度器操作异常。
接口 3:POST /api/taskScheduler/disable/{taskId} 禁用定时任务
和启用接口逻辑完全对称,反向操作:
更新数据库任务状态为停用;
从 Spring 定时调度器中移除该任务,不再周期执行;
返回禁用结果、调度器注册状态。
接口 4:GET /api/taskScheduler/status/{taskId} 查询任务调度状态
用途
前端页面展示任务运行状态,判断:
该任务是否已经注册到内存定时调度器(是否自动周期运行);
当前调度器中总共注册了多少个启用的定时任务。
逻辑
调用 dynamicTaskManager.isTaskRegistered() 查询单个任务注册状态、getRegisteredTaskCount() 获取全局启用任务总数,封装返回。
接口 5:POST /api/taskScheduler/refresh 全局刷新所有定时任务
核心场景
批量修改数据库中多个任务 cron 表达式 / 启停状态后,手动同步刷新内存调度器;
服务重启、配置批量更新,重新全量加载数据库所有任务配置,重建定时调度器任务。
逻辑
调用 dynamicTaskManager.refreshAllTasks(),内部逻辑:
清空当前调度器内所有已注册定时任务;
重新查询数据库全部告警任务;
将状态为启用的任务,按 cron 重新注册到调度器; 返回刷新成功提示 + 当前调度器内任务总数量。
TaskExecutionController.java
一、整体业务定位
该控制器对应 t_task_execution 任务执行记录表,存储每一次告警定时任务 / 手动执行任务的完整运行日志,和前面模块形成完整业务闭环:
AlarmTask:定时任务配置信息(cron、绑定模型、启停状态);
TaskSchedulerController:调度启停、手动触发任务执行;
AlarmEngine:告警规则计算核心引擎;
TaskExecution:每次执行的运行日志记录(执行起止时间、执行结果、是否产生告警、执行类型、任务 ID 等)。
分层调用链路:前端日志页面请求 → TaskExecutionController → TaskExecutionService → Mapper → 达梦执行记录表。
二、基础头部信息
1. 包路径
package cn.com.xxx.bussiness.znyw.controller;
与告警任务、告警模型、告警规则控制器同包,统一智能运维接口层。
2. 导入类说明
DataPaging:项目统一分页封装对象;
JsonMessage<T>:全局标准统一返回体,全项目控制器统一使用;
TaskExecution:数据库执行记录实体,存储单次任务运行日志;
TaskExecutionService:执行记录业务层接口;
Spring Web RESTful 标准注解;
容器:HashMap、List、Map 用于封装分页筛选参数、统计结果。
3. 类注解与依赖注入
@RestController
@RequestMapping("/api/taskExecution")
@Autowired
private TaskExecutionService taskExecutionService;
@RestController:接口自动将返回对象序列化为 JSON;
统一接口前缀 /api/taskExecution,所有执行记录日志接口统一路径;
仅注入执行记录业务 Service,所有数据库、业务逻辑下沉至 Service 层,Controller 仅处理请求转发、参数封装、异常捕获、结果返回。
三、全部接口逐段详解(标准 REST 规范)
接口 1:分页多条件查询 GET /api/taskExecution/list/page
核心用途:前端任务执行日志列表页面,支持多维度复合筛选 + 分页展示。
全部筛选入参说明
|
taskId |
非必填 |
String |
所属告警任务 ID 精确筛选 |
|
executionStatus |
非必填 |
String |
执行状态(成功 / 失败)筛选 |
|
executionType |
非必填 |
String |
执行类型(定时自动 / 手动执行) |
|
hasAlarm |
非必填 |
Boolean |
是否产生告警(true = 本次执行触发告警) |
|
startTime / endTime |
非必填 |
String |
执行时间区间筛选,查询时间段内的执行记录 |
|
page |
可选默认 1 |
int |
当前页码 |
|
row |
可选默认 10 |
int |
每页条数 |
核心逻辑
初始化空 Map,仅把非空、非空白字符串参数存入 Map,空参数不传递给 SQL,避免无效查询条件;
调用 service 分页查询方法,返回分页对象 DataPaging<TaskExecution>;
使用全局标准泛型返回体 JsonMessage 封装分页数据;
整个方法包裹 try-catch,捕获数据库、参数异常,返回友好文字错误提示,不暴露原始 500 堆栈。
接口 2:根据主键 ID 查询单条执行记录 GET /{id}
路径参数 id:执行记录主键(单次任务执行唯一标识 executionId);
逻辑:
-
查询实体不为空,返回完整执行日志详情;
-
无匹配记录,返回业务提示「未找到对应的任务执行记录」;
-
捕获所有运行异常,统一返回失败信息。
接口 3:查询全部执行记录 GET /all
返回无分页的全量执行记录列表,适用场景:下拉选择、导出全部日志、简单数据字典展示(数据量较小时使用)。
接口 4:新增执行记录 POST /add
@RequestBody TaskExecution:接收后端引擎组装完成的执行日志 JSON 实体;
业务场景:告警引擎执行完成后自动调用保存执行日志,前端极少手动新增,仅后台系统内部调用;
调用 service 新增方法,根据返回布尔值判断新增是否成功。
接口 5:更新执行记录 PUT /update
REST 规范 PUT 全量更新执行记录;用于执行日志状态补全、告警数量回填、执行结束时间更新,由告警引擎执行完成后后台自动更新。
接口 6:删除执行记录 DELETE /{id}
根据执行记录主键删除日志,适用于日志清理、测试数据删除。
接口 7~10:多条件单列筛选查询(列表下拉过滤)
GET /byTaskId:根据告警任务 ID,查询该任务所有历史执行日志;
GET /byExecutionStatus:按执行状态(成功 / 失败)筛选日志;
GET /byExecutionType:按执行类型(定时自动 / 手动执行)筛选;
GET /byHasAlarm:按是否触发告警筛选(只看产生告警的执行记录,用于运维排查故障);
接口 11:执行日志统计接口 GET /statistics
业务价值
后台数据看板、运维监控首页,统计全量执行记录汇总指标; 返回 Map 结构固定 key:
-
total:任务总执行次数
-
success:执行成功次数
-
failed:执行失败次数
-
alarmCount:所有执行记录中产生告警的总次数
网硕互联帮助中心




评论前必须登录!
注册