当前位置:

首页 > 编程开发 > 基于SpringBoot和Vue的实时设备告警系统全链路实现方案

基于SpringBoot和Vue的实时设备告警系统全链路实现方案

本文目录

    通过边沿检测与状态机实现告警去重与生命周期管理,以数据库未闭合记录作为状态源确保幂等性,结合REST接口与前端轮询或推送,构成从采集、判定、持久化到展示闭环的实时设备告警系统全链路方案。

    实时监控告警这个功能,说起来简单,但真正落地的时候,坑比想象中多——重复报警、僵尸告警、前端刷屏,哪个都能让人头疼。下面就把从数据采集、告警判定、持久化、接口暴露,到前端展示、闭环处理、兜底补偿的整个链条完整捋一遍。每个环节的关键设计要点和通用代码示例都会给到,而且尽量跟具体业务解耦,方便你直接拿过来参考。

    基于SpringBoot和Vue的实时设备告警系统全链路实现方案

    一、整体架构与数据流

    一个典型的实时告警系统,拆开来看,其实就五段:

    ┌──────────┐   采集    ┌──────────┐  判定/去重  ┌──────────┐
    │ 数据源    │ ───────▶ │ 采集任务  │ ─────────▶ │  告警表   │
    │(设备/API)│  周期轮询  │(定时/流) │  生成/闭环  │ (DB)     │
    └──────────┘           └──────────┘            └────┬─────┘
                                                         │ REST
                                                  ┌──────▼─────┐   推送/轮询  ┌─────────┐
                                                  │ 后端接口层  │ ──────────▶ │ 前端界面 │
                                                  └────────────┘             │ +提醒    │
                                                                             └─────────┘

    设计的时候,有几个原则需要先定下来:

    • 采集与判定解耦:采集只管拿到原始状态,判定逻辑独立出来,后面想加新告警类型就不用改采集代码。
    • 状态化而非事件流:告警落库要是一条有生命周期的记录(有 start/stop),而不是无穷无尽的日志流。这样才能做“当前未恢复告警”这种查询,不然每次都得扫全量。
    • 前端只读 + 幂等操作:前端不参与告警产生,只做展示,以及“确认/处理”这类幂等状态流转。写死了,省心。

    二、告警生成层:边沿检测与状态机

    2.1 电平 vs 边沿

    采集到的原始状态,通常是电平信号——布尔量,故障=true,正常=false。如果每个采集周期只要 true 就插一条告警,2秒一采集,一分钟就能刷出30条,一天下来表里全是重复数据。

    正确的做法是边沿检测(Edge Detection):只在状态发生跳变的时候动作。

    边沿上一次本次动作
    上升沿falsetrue生成新告警(记录 start_time)
    下降沿truefalse关闭告警(记录 stop_time、时长)
    保持相同相同什么都不做

    2.2 通用示例:边沿检测器

    /**
     * 通用布尔量边沿检测器,线程安全
     * key 通常是 "设备ID:信号名"
     */
    public class EdgeDetector {
    
        private final Map lastState = new ConcurrentHashMap<>();
    
        public enum Edge { RISING, FALLING, NONE }
    
        public Edge detect(String key, boolean current) {
            Boolean prev = lastState.put(key, current);
            if (prev == null) {
                // 首次采集:把 true 视为上升沿,false 视为无事件
                return current ? Edge.RISING : Edge.NONE;
            }
            if (!prev && current) return Edge.RISING;
            if (prev && !current) return Edge.FALLING;
            return Edge.NONE;
        }
    }
    

    2.3 在采集周期中使用

    EdgeDetector detector = new EdgeDetector();
    
    void onSample(String deviceId, String signal, boolean faultBit, Date now) {
        String key = deviceId + ":" + signal;
        switch (detector.detect(key, faultBit)) {
            case RISING:
                alarmService.open(deviceId, signal, now);   // 生成告警
                break;
            case FALLING:
                alarmService.close(deviceId, signal, now);  // 闭合告警
                break;
            default:
                // 状态未变,忽略
        }
    }
    

    状态存哪里? 单机可用内存 Map;多实例或需要重启不丢,可以把“上一次状态”放 Redis,或者直接以数据库中“是否存在未闭合告警”作为判断依据(见第3节,最稳,不需要额外状态存储)。

    三、告警去重与生命周期

    比内存边沿更可靠的方案:以数据库中“是否存在未闭合记录”作为状态源。天然幂等、重启不丢、多实例也安全。

    3.1 生命周期模型

    一条告警记录有三个关键时间点与两个派生字段:

    start_time ──────(持续中)──────▶ stop_time
                                      total_time = stop - start(秒)
    handle_status: 待确认 → 已确认 → 已处理(或 超时未确认)
    

    3.2 开告警(带去重)

    public void open(Long deviceId, String alarmName, Date startTime) {
        // 去重:若已存在该设备该类型"未闭合"告警,则不再新建
        if (mapper.selectUnfinished(deviceId, alarmName) != null) {
            return;
        }
        Alarm a = new Alarm();
        a.setDeviceId(deviceId);
        a.setAlarmName(alarmName);
        a.setStartTime(startTime);
        a.setAlarmLevel(resolveLevel(alarmName));   // 名称→等级映射
        a.setHandleStatus(STATUS_PENDING);          // 默认待确认
        mapper.insert(a);
    }
    

    3.3 关告警(计算时长)

    public boolean close(Long deviceId, String alarmName, Date stopTime) {
        Alarm a = mapper.selectUnfinished(deviceId, alarmName);
        if (a == null) return false;                // 没有未闭合记录,忽略
    
        long seconds = (stopTime.getTime() - a.getStartTime().getTime()) / 1000;
        return mapper.updateStop(a.getId(), stopTime, seconds) > 0;
    }
    

    3.4 名称 → 等级映射(可配置化)

    把“哪个告警多严重”抽成映射表,以后加告警只改配置,不改逻辑:

    public class AlarmLevel {
        public static final int INFO = 1, WARN = 2, SERIOUS = 3, FATAL = 4;
    
        private static final Map MAP = new HashMap<>();
        static {
            MAP.put("急停", FATAL);
            MAP.put("高压报警", SERIOUS);
            MAP.put("低流量报警", WARN);
            // ...
        }
        /** 未命中默认按严重处理,保证"漏配也不漏报" */
        public static int of(String name) {
            return MAP.getOrDefault(name, SERIOUS);
        }
    }
    

    更进一步,可以把映射表放到数据库字典表(sys_dict_data)或独立阈值配置表,做到运营可视化配置。

    四、数据库层设计

    4.1 建表 DDL(通用示例)

    CREATE TABLE device_alarm (
        id            BIGINT       NOT NULL AUTO_INCREMENT COMMENT '主键',
        device_id     BIGINT       NOT NULL               COMMENT '设备ID',
        alarm_name    VARCHAR(64)  NOT NULL               COMMENT '告警名称/类型',
        alarm_level   TINYINT      NOT NULL DEFAULT 3      COMMENT '等级 1提示2预警3严重4致命',
        start_time    DATETIME     NOT NULL               COMMENT '开始时间',
        stop_time     DATETIME     NULL                   COMMENT '结束时间(NULL=未恢复)',
        total_time    INT          NULL                   COMMENT '持续秒数',
        handle_status TINYINT      NOT NULL DEFAULT 0      COMMENT '0待确认1已确认2超时3已处理',
        handle_user   VARCHAR(64)  NULL                   COMMENT '处理人',
        handle_time   DATETIME     NULL                   COMMENT '处理时间',
        handle_remark VARCHAR(500) NULL                   COMMENT '处理备注',
        create_time   DATETIME     NOT NULL               COMMENT '创建时间',
        PRIMARY KEY (id),
        KEY idx_device_unfinished (device_id, alarm_name, stop_time),
        KEY idx_stop_time (stop_time),
        KEY idx_create_time (create_time)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备告警表';

    4.2 索引设计要点

    查询场景索引说明
    “该设备该类型是否有未闭合告警”(去重、闭合)(device_id, alarm_name, stop_time)最高频写路径,联合索引命中
    “当前所有未恢复告警”(大屏轮询)idx_stop_timeWHERE stop_time IS NULL
    历史分页/导出idx_create_time按时间倒序翻页

    stop_time IS NULL 表示未恢复——用 NULL 而不是额外的 is_finished 布尔字段,语义清晰且能与时间字段复用索引。

    4.3 关键 SQL

    -- 查未闭合(去重判断)
    SELECT * FROM device_alarm
    WHERE device_id = #{deviceId} AND alarm_name = #{alarmName}
      AND stop_time IS NULL LIMIT 1;
    -- 闭合告警
    UPDATE device_alarm
    SET stop_time = #{stopTime}, total_time = #{seconds}
    WHERE id = #{id} AND stop_time IS NULL;   -- 加 stop_time IS NULL 防并发重复闭合
    -- 当前未恢复列表
    SELECT a.*, d.device_name
    FROM device_alarm a LEFT JOIN device d ON a.device_id = d.id
    WHERE a.stop_time IS NULL
    ORDER BY a.alarm_level DESC, a.start_time DESC;

    并发防护:UPDATE ... WHERE id=? AND stop_time IS NULL 利用行锁 + 条件,天然防止两个线程重复闭合同一告警(第二个 UPDATE 影响 0 行)。

    五、后端接口层:REST API 设计

    5.1 接口清单(RESTful + 语义动作)

    方法路径用途
    GET/alarm/list分页历史查询
    GET/alarm/current当前未恢复告警(前端轮询)
    GET/alarm/{id}详情
    POST/alarm/confirm/{id}确认告警
    POST/alarm/batchConfirm批量确认
    POST/alarm/handle处理闭环(带备注)
    POST/alarm/export导出 Excel

    查询用 REST 名词 + GET;“确认/处理”这类状态流转用动词子路径(/confirm、/handle),比强行 PUT 整个对象更清晰、更安全——避免前端误改其他字段。

    5.2 通用控制器示例

    @RestController
    @RequestMapping("/alarm")
    public class AlarmController {
    
        @Autowired private AlarmService service;
    
        /** 前端轮询:当前所有未恢复告警 */
        @GetMapping("/current")
        public Result> current() {
            return Result.ok(service.listUnfinished());
        }
    
        /** 确认(幂等) */
        @PostMapping("/confirm/{id}")
        public Result confirm(@PathVariable Long id) {
            service.confirm(id, currentUser());
            return Result.ok();
        }
    
        /** 处理闭环 */
        @PostMapping("/handle")
        public Result handle(@RequestParam Long id,
                                   @RequestParam(required = false) String remark) {
            service.handle(id, remark, currentUser());
            return Result.ok();
        }
    }
    

    5.3 权限与审计

    • 每个写接口加权限校验(如 Spring Security @PreAuthorize)。
    • “确认/处理”记录操作人 + 操作时间,形成审计链,责任可追溯。

    六、前端展示层:三种实时推送方案对比

    前端要“实时”感知新告警,有三条技术路线可以选:

    方案原理优点缺点适用
    轮询 PollingsetInterval 定时请求实现最简单、无长连接、兼容强有延迟、有空请求开销秒级实时够用、部署简单
    SSEEventSource 服务端单向推原生断线重连、比 WS 轻单向、老 IE 不支持只需服务端→客户端推送
    WebSocket全双工长连接真正实时、双向需维护连接/心跳/鉴权高频、双向交互

    6.1 轮询(最常用,通用示例)

    class AlarmPoller {
      constructor(fetchFn, { interval = 5000, onNew } = {}) {
        this.fetchFn = fetchFn;      // 返回 Promise
        this.interval = interval;
        this.onNew = onNew;
        this.knownIds = new Set();
        this.timer = null;
      }
    
      start() {
        this.tick();                 // 立即拉一次
        this.timer = setInterval(() => this.tick(), this.interval);
      }
    
      async tick() {
        try {
          const list = await this.fetchFn();
          // 找出本轮"新出现"的告警
          const fresh = list.filter(a => !this.knownIds.has(a.id));
          list.forEach(a => this.knownIds.add(a.id));
          // 清理已恢复的 id,防止 Set 无限膨胀
          const alive = new Set(list.map(a => a.id));
          this.knownIds = new Set([...this.knownIds].filter(id => alive.has(id)));
          if (fresh.length && this.onNew) this.onNew(fresh);
        } catch (e) {
          console.error('轮询告警失败', e);   // 失败不中断下一轮
        }
      }
    
      stop() { clearInterval(this.timer); this.timer = null; }
    }
    
    // 用法
    const poller = new AlarmPoller(() => api.getCurrentAlarms(), {
      interval: 5000,
      onNew: (alarms) => alarms.forEach(a => alarmManager.alarm({
        title: a.deviceName, body: a.alarmName, level: mapLevel(a.alarmLevel),
      })),
    });
    poller.start();
    

    轮询的两个关键技巧:

    1. “新增”判定用 id 集合 diff,不要每次全量弹提醒,否则同一告警会反复响。
    2. 及时清理已恢复 id,避免 Set 内存泄漏。

    6.2 SSE(服务端主动推)

    // 前端
    const es = new EventSource('/alarm/stream');
    es.addEventListener('alarm', (e) => {
      const alarm = JSON.parse(e.data);
      alarmManager.alarm({ title: alarm.deviceName, body: alarm.alarmName });
    });
    es.onerror = () => console.warn('SSE 断开,浏览器将自动重连');
    
    // 后端 Spring MVC
    @GetMapping(value = "/alarm/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter stream() {
        SseEmitter emitter = new SseEmitter(0L);       // 不超时
        emitterRegistry.add(emitter);                  // 存起来,产生告警时广播
        emitter.onCompletion(() -> emitterRegistry.remove(emitter));
        return emitter;
    }
    // 产生新告警时:emitter.send(SseEmitter.event().name("alarm").data(alarm));
    

    6.3 WebSocket(双向)

    const ws = new WebSocket('wss://host/ws/alarm');
    ws.onmessage = (e) => {
      const msg = JSON.parse(e.data);
      if (msg.type === 'ALARM') alarmManager.alarm(msg.payload);
    };
    // 心跳保活
    setInterval(() => ws.readyState === 1 && ws.send('ping'), 30000);

    选型建议:秒级监控大屏优先轮询(最稳、运维成本最低);需要毫秒级或服务端主动推且不想维护重连时用 SSE;有双向指令交互(如页面下发控制命令)才上 WebSocket。

    七、前端提醒层

    新告警到达后,触发“提醒三件套”:

    • Web Audio 蜂鸣:按告警等级播放不同急促度的合成音,无需音频文件。
    • 浏览器 Notification:仅在 document.visibilityState !== 'visible'(用户切走)时弹系统通知,避免前台重复骚扰。
    • 标题 / fa vicon 红点角标:后台时用 document.title 计数 + Canvas 绘制 fa vicon 角标,把用户“拉回来”。

    统一入口示例:

    poller.onNew = (alarms) => {
      alarms.forEach(a => alarmManager.alarm({
        title: a.deviceName,
        body: a.alarmName,
        level: mapLevel(a.alarmLevel),
        tag: 'alarm-' + a.id,        // 去重,防刷屏
      }));
    };
    

    八、闭环处理:确认 / 处理 / 超时

    告警不能只“响”,必须能被人闭环,否则等于噪音。典型状态机:

            产生
    待确认 ───────▶ (用户点确认) ──▶ 已确认 ──▶ (处理完+备注) ──▶ 已处理
       │
       └─(超过N分钟无人确认)──▶ 超时未确认   ← 用于考核值班响应
    

    8.1 确认(幂等)

    public void confirm(Long id, String user) {
        Alarm a = new Alarm();
        a.setId(id);
        a.setHandleStatus(STATUS_CONFIRMED);
        a.setHandleUser(user);
        a.setHandleTime(new Date());
        mapper.updateSelective(a);      // 只更新非空字段
    }
    

    8.2 前端确认交互

    async function confirmAlarm(id) {
      await api.confirm(id);
      this.$message.success('已确认');
      this.refresh();          // 刷新当前告警列表
      alarmManager.clear();    // 清角标/停声音
    }

    幂等性:确认/处理接口要能被重复调用而不出错(重复点、网络重试)。用“设置目标状态”而非“状态+1”即天然幂等。

    九、兜底补偿:僵尸告警与数据自愈

    实时系统一定要考虑异常路径,否则数据会失真:

    9.1 两类典型脏数据

    问题成因后果
    僵尸告警恢复边沿丢失(设备离线、缓存过期、进程重启)stop_time 永远 NULL,大屏一直红
    超时未确认无人值守,告警长期挂“待确认”无法考核响应,告警堆积

    9.2 兜底任务(定时扫描自愈)

    /** 每分钟跑一次,修复未闭合告警 */
    public void fallback() {
        Date now = new Date();
        for (Alarm a : mapper.selectAllUnfinished()) {
            long elapsedMin = (now.getTime() - a.getStartTime().getTime()) / 60000;
    
            // 1) 超时未确认 → 标记
            if (a.getHandleStatus() == STATUS_PENDING && elapsedMin >= TIMEOUT_MIN) {
                mapper.markTimeout(a.getId());
            }
    
            // 2) 僵尸告警 → 若数据源已恢复正常/持续离线超阈值,则强制关闭
            Boolean live = readCurrentState(a);           // 从缓存/实时源读当前状态
            if (Boolean.FALSE.equals(live)) {
                mapper.forceClose(a.getId(), now, "点位已恢复,兜底关闭");
            } else if (live == null && offlineTooLong(a)) {
                mapper.forceClose(a.getId(), now, "设备持续离线,兜底关闭");
            }
        }
    }
    

    9.3 防误关的两个细节

    • 离线要“持续超阈值”才关:用一个 Map 记录,避免瞬时网络抖动误关正常告警。
    • 区分“离线”与“恢复”:数据源读不到(null)= 离线,读到且为正常 = 真恢复,两者处置不同。

    十、关键设计要点汇总

    层要点
    采集/判定用边沿检测而非电平,避免海量重复;判定逻辑与采集解耦
    去重以“数据库是否存在未闭合记录”为状态源,幂等且重启不丢
    生命周期stop_time IS NULL 表示未恢复;闭合时算 total_time
    并发闭合 UPDATE 带 AND stop_time IS NULL 防重复闭合
    等级名称→等级映射表化/字典化,漏配默认从严
    数据库联合索引 (device_id, alarm_name, stop_time) 覆盖写路径
    接口查询用 REST 名词,状态流转用动词子路径;写接口鉴权 + 审计
    推送选型秒级用轮询,单向实时用 SSE,双向用 WebSocket
    前端去重id 集合 diff 判断“新增”,并清理已恢复 id 防内存泄漏
    提醒声音 + 仅后台通知 + 角标;用 tag 去重防刷屏
    闭环确认/处理幂等,记录操作人与时间
    兜底定时扫描修复僵尸告警与超时未确认;防抖动误关
    健壮性轮询/推送失败不中断循环;异常路径必须有兜底

    以上即“实时设备告警”功能从数据源到界面的全链路技术详解。核心思想可提炼为三句话:采集判定用边沿、状态落库带生命周期、异常路径必有兜底;而前端则遵循只读展示 + 幂等闭环 + 恰到好处的提醒。这套模式可以直接迁移到设备监控、服务器运维告警、业务风控预警等任意实时告警场景。

    本文内容来源于网友投稿,如有侵权请联系删除。
    作者最新文章
    编程开发
    相关文章 更多
    PHP递归性能优化技巧与迭代替代方案
    PHP递归性能优化技巧与迭代替代方案

    解析PHP递归函数在树形数据处理中的性能瓶颈,提供预加载数据消除I/O、使用显式栈替代深层递归的实战方案,帮助开发者在代码可读性与执行效率间做出合理取舍。

    Java测试中怎么使用Mockito模拟依赖对象
    Java测试中怎么使用Mockito模拟依赖对象

    详细讲解在Java单元测试中如何使用Mockito模拟依赖对象,包括引入依赖、创建Mock、打桩返回值、行为验证以及Mock与Spy的核心差异和常见陷阱排查。

    链表删除节点的时间复杂度是多少及其详细分析
    链表删除节点的时间复杂度是多少及其详细分析

    详细分析链表删除节点的时间复杂度,深入探讨单链表与双向链表在不同已知前提下的查找与删除开销,并结合完整代码与清晰图解进行对比总结。

    codex如何配置模型参数及文件设置教程
    codex如何配置模型参数及文件设置教程

    想知道如何让AI写出的代码更贴合你的习惯?本文手把手教你在VS Code中调整Codex相关模型参数,通过修改配置文件优化温度值和令牌限制,解决代码建议不准确或响应慢的问题。

    Claude Code AI编程工具实力揭秘与编程助手实测
    Claude Code AI编程工具实力揭秘与编程助手实测

    通过实测展示Claude Code在终端中如何理解自然语言指令、自动修改代码文件并处理复杂编程任务,帮助开发者评估其实际辅助能力。

    winforms教程自学入门与基础开发步骤详解
    winforms教程自学入门与基础开发步骤详解

    本教程详细讲解如何使用Visual Studio创建WinForms项目,通过添加按钮和标签控件并编写点击事件代码,实现一个基础的计数器功能,适合C#初学者快速上手Windows窗体应用开发。

    Cursor自动补全设置教程教你快速开启代码补全功能
    Cursor自动补全设置教程教你快速开启代码补全功能

    详解Cursor编辑器中自动补全功能的开启与优化设置,涵盖Tab触发机制、上下文窗口调整及模型切换,帮助开发者解决补全延迟、干扰大等问题,提升编码流畅度。

    pandas的数据格式怎么转换和设置方法教程
    pandas的数据格式怎么转换和设置方法教程

    详解Pandas中数据格式转换的核心方法,包括astype强制转换、to_numeric容错处理及日期解析技巧,解决常见类型错误并提升数据处理效率。

    VS Code中文设置方法 简体语言包安装与切换教程
    VS Code中文设置方法 简体语言包安装与切换教程

    详细介绍在Visual Studio Code中安装Chinese (Simplified)语言包的方法,包括通过扩展市场搜索、安装及自动重启切换至简体中文界面的完整步骤,帮助开发者快速将编辑器本地化。

    cursor安装过程无法更改安装位置的解决方法
    cursor安装过程无法更改安装位置的解决方法

    针对Cursor安装包默认锁定C盘且无路径选择界面的问题,提供通过手动移动文件并创建目录联结(Symbolic Link)的解决方案,实现将软件安装在其他磁盘分区。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    macOS软件
    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    Mac软件 更多
    photoshop
    photoshop
    Windows、macOS 、 iPad

    Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。

    Blender
    Blender
    Windows、macOS 和 Linux

    Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

    灵活计算器
    灵活计算器
    macOS/iOS/Android

    灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

    WINDOWS 更多
    3dmax(3ds max)
    3dmax(3ds max)
    Windows

    Autodesk 3ds Max 是一款专业的三维建模、动画与渲染软件,广泛应用于建筑可视化、游戏开发、影视动画、广告设计和产品展示等领域。

    photoshop
    photoshop
    Windows、macOS 、 iPad

    Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。

    Blender
    Blender
    Windows、macOS 和 Linux

    Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。