云计算百科
云计算领域专业知识百科平台

实习第十二天日记周一【2026.7.27】

例行早会7 月 27 日完整整理

一、新人介绍

二、内网本地 GLM 大模型资源说明

  • 办公室部署 GLM 4.7 大模型,服务器显卡为 2080(22G 显存),仅运行该模型,其他模型已卸载;
  • 运行短板:模型响应速度一般;后续计划尝试安装 GLM 5.2,但显卡显存偏小,大概率无法支撑;
  • 使用场景:个人外部 API 额度不足时可内网本地模型补充使用,后续新增内网资源会同步通知,使用遵循各项目指导老师安排。
  • 三、各实习生上周五工作汇报 + 今日工作计划

  • 实习生 1(搭建本地开发环境)
    • 上周五:完成本地开发环境搭建,Redis、ES 数据库配置完成,导入测试数据,项目可正常运行;
    • 今日计划:分两阶段研读项目源码 ① 上午:熟悉整体架构,阅读启动类 Application、各项目配置、前端路由,梳理系统页面结构; ② 下午:深耕告警核心业务模块,学习告警模型 / 规则管理 Controller、Service,重点研究计算引擎、规则引擎,梳理定时任务调度与接口; ③ 配套动作:梳理代码调用链路,遇无法解决问题及时请教老师,同步记录架构、业务笔记便于复盘。
  • 实习生 2(职工医疗健康大模型小组)
    • 上周五:参与需求会议,设计通用 JSON 格式、开发个人信息模块,现存问题已同步金哥;
    • 今日计划:开会讨论现存模块问题。
  • 实习生 3(同医疗大模型小组)
    • 上周五:同步参与需求会议,完成 MD 转 JSON 标准化模板开发,以数据驱动转换;
    • 今日计划:随小组开会沟通模块问题。
  • 实习生 4(胜利油田成果数据 API 项目)
    • 上周五:参会确定开发方向 —— 对外提供第三方 API;需求背景:胜利油田仅有原始数据,研发人员成果数据分散杂乱,计划依托当前项目搭建统一成果数据库,先以舒华总项目作为示范接口展示,后续全油田推广;梳理接口开发所需字段、数据格式等基础信息;
    • 今日计划:完善需求方案设计。
  • 实习生 5(前端页面修复)
    • 上周五:修复清单页面按钮失效问题;收到王老需求:设计请假单类业务流程图流转逻辑;
    • 今日计划:思考流程图业务设计方案。
  • 实习生 6(环境部署 + 架构梳理)
    • 上周五:完成环境配置、数据导入,初步熟悉功能模块划分;
    • 今日计划:研读前后端代码、排查代码问题,绘制系统架构图。
  • 实习生 7(RPA 脚本开发)
    • 上周五:完成手动、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

    对应页面

    业务作用

    空 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 对应关系

    Service 方法

    对应后端接口地址

    前端页面用途

    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 层完整映射对照表

    Service 接口方法

    后端 API 地址

    前端业务场景

    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 完整映射对照表

    Service 接口方法

    后端 API 地址

    前端业务场景

    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:所有执行记录中产生告警的总次数

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 实习第十二天日记周一【2026.7.27】
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!