ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringBoot地铁安防管理系统实战:从模块设计到部署答辩全攻略

SpringBoot地铁安防管理系统实战:从模块设计到部署答辩全攻略 地铁安防管理系统这类题目几乎是每年计算机毕业设计里的常青树。但同样一个题目有人做出来像课堂作业有人做出来像能直接交付的工程差别主要在技术选型和建模思路上。我当年选这个题前后对比过SSM、SSH和SpringBoot最后选了SpringBoot。后来参与实际的城市轨道交通安全防控项目时发现当年在毕设里搭出来的模块边界、缓存策略和应急链路居然能直接沿用。这篇文章把我踩过的坑、验证过的方案都整理出来给正在选这个题或者准备拓展成求职项目的同学一个完整的参考。1. 选题时的真实考量为什么地铁安防必须用SpringBoot而不是SSM1.1 地铁安防管理平台要解决的核心问题先别急着写代码想清楚一个关键问题地铁安防和普通的后台管理系统到底差在哪我自己的理解是三多一快——多线路、多站点、多设备事件响应要快。多线路每条线路有起始站、终点站、开通时间后续还要扩展新线路线路和站点之间是天然的一对多关系。多站点每个站点有安检信息、摄像头、巡更点、设备台账数据天然按站点隔离所以后端的权限设计必须支持“数据级隔离”不是光有按钮权限就够。多设备安检门、X光机、闸机、摄像头、巡更点每类设备的字段差异很大设备状态还关系到巡检提醒。响应快从告警上报到启动应急预案最好能分钟级甚至秒级联动这就不是单纯增删改查的问题而是要有清晰的事件状态机和异步通知机制。很多同学把这个题当成“车站信息管理”来做只做线路站点的CRUD那就废了。安防系统的核心是“事件链路”也就是从安检异常、巡更超时、设备故障这些源头事件一路流转到告警、预案、处置、回访的完整闭环。SpringBoot恰恰适合搭这种链路清晰、模块边界分明的系统。1.2 SpringBoot相对SSM在毕设中的优势如果你是2025年还在纠结要不要用SSM做毕设我的建议是别纠结了。SSM不是不能做而是做这个题目时你要把大量精力浪费在配置上Spring核心配置、SpringMVC配置、MyBatis配置、各种xml扫描还没开始写业务逻辑光环境就折腾两三天。SpringBoot把“约定优于配置”做到了极致主要有几个点对毕设特别友好起步依赖Starter机制想用Redis就引spring-boot-starter-data-redis想用消息队列就引starter-activemq依赖是一颗一颗往pom里加糖不需要手动拼版本号。内置Tomcat不用单独配置服务器直接一个java -jar就能跑起来部署到答辩现场的Windows电脑也没问题。自动装配框架自动读取配置并创建Bean开发时只需要关注自定义业务Bean。生态兼容SpringSecurity、MyBatis-Plus、Redis、ES这些地铁安防系统要用的组件都有对应的starter集成成本极低。1.3 自动装配原理毕设答辩时的加分点SpringBoot的自动装配不要求背源码但至少要能说清楚它的机制因为答辩老师大概率会问。核心就三句话SpringBootApplication由SpringBootConfiguration、EnableAutoConfiguration、ComponentScan组合而成。EnableAutoConfiguration会通过SpringFactoriesLoader读取META-INF/spring.factories文件把所有自动配置类先加载出来。每个自动配置类用ConditionalOnClass、ConditionalOnProperty等条件注解做过滤只有classpath里存在对应的类、配置也匹配时才真正生效。举个例子你pom里引入spring-boot-starter-data-redis后classpath会出现RedisTemplate等类RedisAutoConfiguration配置类满足条件于是自动创建RedisTemplate的Bean。如果你没引入依赖这个配置类直接不生效不会报错。这个机制解释了为什么我们这些开发者可以“零配置”地集成中间件——不是框架替我们做了而是它把选择权交给了条件判断。这句话写进论文摘要里整个设计说明的档次都会不一样。2. 系统模块划分与数据表设计先理业务再动手敲代码2.1 六大业务模块的边界划分我见过一堆人一上来就建表建到一半发现数据对不上又回头改表这就是没做模块边界。地铁安防系统建议分成六大模块模块之间通过接口调用而不是直接穿透表模块核心职责代表性的实体基础信息管理线路、站点的增删改查及上下线线路、站点用户与权限用户登录、角色菜单、站点数据范围用户、角色、菜单安检与设备安检信息登记、危险品管理、设备台账安检记录、危险品、设备视频与巡更摄像头管理、巡更点规划、打卡记录摄像头、巡更点、巡更记录告警与应急告警生成分级、预案匹配、事件处置告警、预案、应急事件统计与报表客流趋势、告警排名、安检量统计统计视图模块之间怎么联动我的做法是基础信息模块被其他模块查询引用安检模块发现异常往告警模块扔数据巡更模块超时也往告警模块扔告警模块根据类型匹配应急预案最后统一进入事件闭环。数据流是单向的这样后续加功能不容易乱。2.2 核心数据表与字段设计表结构不追求多但要贴业务。下面是梳理出的核心表字段我按能落地的程度做了精简表名用途核心字段line_info线路信息id, line_code, line_name, start_station, end_station, open_datestation_info站点信息id, station_code, station_name, line_id, address, manager, phonesys_user用户账号id, username, password, real_name, station_id, role_id, phone, statussys_role角色id, role_code, role_name, data_scopesecurity_check_info安检记录id, check_no, station_id, check_date, operator_id, item_name, item_type, danger_level, handling_wayequipment_info设备台账id, eq_code, eq_name, eq_type, station_id, install_date, last_maintain_date, maint_cyclepatrol_point巡更点id, point_code, point_name, station_id, location_desc, qr_code_urlpatrol_record巡更打卡记录id, record_no, point_id, user_id, patrol_time, result, remark, photo_urlalarm_info告警信息id, alarm_no, alarm_type, station_id, source, level, content, status, create_time, deal_time, deal_resultemergency_plan应急预案id, plan_code, plan_name, plan_type, level, content, task_templateemergency_event应急事件id, event_no, plan_id, station_id, event_type, level, description, status, start_time, end_timecamera_info摄像头id, cam_code, cam_name, station_id, rtmp_url, status, area_type这里要注意一个很多人容易忽略的点所有业务表建议统一加create_time、update_time、deleted逻辑删除三个审计字段。毕设阶段不要用物理删除因为演示的时候你想恢复某条数据物理删除后悔都来不及。2.3 表关系与外键策略性能与规范怎么平衡表之间的关系很清晰线路一对多站点站点一对多设备/摄像头/巡更点用户关联站点告警关联站点。但在物理表上我的建议是不建外键约束只保留逻辑外键即普通索引字段。原因有两点性能地铁安防系统在演示时数据量不大但答辩问答环节如果聊到扩展外键约束会影响大批量导入和删除数据的效率。灵活性逻辑外键可以控制在service层做关联校验代码可读性和维护性都更好。但记住一个底线不建外键不代表不校验。比如删除一个站点时必须先检查该站点下有没有设备、摄像头、巡更点有的话就给出提示不然会出现孤儿数据。这个检查逻辑写在service层写完这部分可以当作答辩的一个业务亮点。3. 核心功能实现安防领域最容易卡壳的五个环节3.1 基于Spring Security JWT的权限控制地铁安防系统涉及的角色很典型超级管理员、站点管理员、安检员、巡更员、指挥中心值班员。不同角色能看的站点范围不同能点的菜单也不同所以我直接放弃了传统拦截器方案改用Spring Security JWT。为什么要用JWT而不是Session因为前后端分离已经成为标配前端Vue和后端SpringBoot分开部署PDA扫码端、巡检App也要调用接口。如果Session存储要么引入Redis做Session共享要么处理跨域Cookie的复杂问题。JWT的Token机制天然适合这种多端场景。核心逻辑有三层登录接口校验用户名密码通过后用io.jsonwebtoken.JJWT生成Token把用户ID、角色、站点数据权限编码进去。自定义OncePerRequestFilter过滤器解析请求头中的Token把用户信息放入SpringSecurity的SecurityContextHolder。SecurityConfig里配置接口权限规则/api/auth/login放行/api/alarm/**需要对应角色其余默认需要认证。Configuration EnableWebSecurity public class SecurityConfig { Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeHttpRequests() .antMatchers(/api/auth/login).permitAll() .antMatchers(/api/alarm/**).hasAnyRole(ADMIN, DISPATCHER) .anyRequest().authenticated(); http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } }这里有个容易踩的坑SpringSecurity 5.x的antMatchers在2.7.x还能用但到SpringBoot 3.x对应的是SpringSecurity 6.x全改成requestMatchers了。后面第5章会细讲版本选择先记住这个区别。3.2 危险品登记与安检台账不只是表单提交安检记录听起来像一张普通表单但地铁安防场景里有个特殊要求当安检员登记管制刀具等危险品时系统要自动产生告警并通知值班员。也就是说安检模块和告警模块之间存在业务联动。我的实现方式是在SecurityCheckService.add()方法里提交记录后判断dangerLevel如果级别为HIGH就调用AlarmService.generateAlarm()创建一条告警同时向ActiveMQ发送一条异步通知消息。这样用一张表记录业务另一张表产生事件后面统计报表也有的放矢。public void addCheck(SecurityCheckInfo info) { checkMapper.insert(info); if (DangerLevel.HIGH.equals(info.getDangerLevel())) { AlarmInfo alarm new AlarmInfo(); alarm.setAlarmType(SECURITY_CHECK); alarm.setStationId(info.getStationId()); alarm.setLevel(HIGH); alarm.setContent(安检发现高危物品 info.getItemName()); alarmService.generateAlarm(alarm); } }高危险品处置方式建议做成枚举没收、移交公安、登记放行等。这比简单的文本框更专业答辩时也能强调这是业务规则的落地。3.3 视频监控管理中的数据流设计视频监控模块要避免一个误区不要试图用Java后端做视频解码。真实项目里摄像头输出RTSP流前端Vue播放器并不直接支持RTSP协议所以主流做法是接入流媒体服务转换协议比如用ZLMediaKit把RTSP转成HTTP-FLV或HLS然后前端用flv.js或video.js播放。毕设阶段怎么体现这个模块我的做法是摄像头表存设备编码、安装站点、所属区域以及rtmp_url字段。做一个视频播放页面选择站点后展示该站点的摄像头列表点击摄像头播放对应视频流。如果演示现场不方便接真实摄像头准备几个公开的RTSP测试流地址或者用本地视频文件循环播放充当视频源。实训录像是加分项给camera_info表加一个record_file字段存录像文件路径前端按时间轴选择录像。这个模块看起来技术含量高但真实实现并不复杂关键是把数据表和播放地址的关系设计清楚。3.4 应急预案执行与事件上报链路应急指挥是标题里的核心词也是拉开档次的功能。我把应急事件设计成一个状态机待处理 → 执行中 → 已结束 → 已复盘。每个事件都来自告警在执行过程中可以分配处置人、上传处置说明。public void startEvent(EmergencyEvent event) { // 1. 根据告警类型和级别匹配预案 EmergencyPlan plan planService.matchPlan(event.getEventType(), event.getLevel()); // 2. 从预案的task_template解析出任务清单 ListString tasks planService.parseTasks(plan.getTaskTemplate()); // 3. 生成事件并进入执行状态 event.setPlanId(plan.getId()); event.setStatus(EXECUTING); eventMapper.insert(event); }预案里最重要的字段是task_template我用JSON数组存任务模板比如[{task:站内广播通知,owner:值班站长},{task:启动安检升级,owner:安检组长}]。事件启动后按任务清单逐项推进每完成一项打卡记录。这个设计比单纯传一段预案文字要更“系统化”答辩时可以说“把预案拆成了可执行的任务单元”。3.5 巡更和设备点的二维码打卡逻辑巡更管理的核心功能是“扫码打卡”。实现方式巡更点表里存一个二维码内容可以是随机生成的授权码巡检员用PDA或手机扫二维码请求后端接口记录打卡。需要考虑三个实际场景防重复打卡同一个人同一个巡更点在5分钟内不能重复打卡用patrol_record表上的唯一索引配合时间判断。离线兜底地铁站台信号不一定好所以打卡接口支持先记录本地时间上传时以服务器时间为准。超时未巡更自动告警用Scheduled定时任务每10分钟扫描一次巡更点如果当前时间超过计划巡更时间30分钟还没有记录自动生成一条巡更异常告警。Scheduled(cron 0 */10 * * * ?) public void checkOvertimePatrol() { ListPatrolPoint points patrolPointMapper.selectAll(); for (PatrolPoint point : points) { PatrolRecord last patrolRecordMapper.selectLatestByPoint(point.getId()); if (last null || Duration.between(last.getPatrolTime(), LocalDateTime.now()).toMinutes() 30) { alarmService.generateAlarm(PatrolOvertimeAlarmBuilder.build(point)); } } }定时任务这部分内容放进论文里几乎是送分题因为很多同学的毕设根本没有“主动触发”的功能全是靠人点击按钮。你有了定时扫描系统就活起来了。4. 中间件组合Redis、ActiveMQ、Elasticsearch、MinIO在地铁场景的正确用法4.1 Redis会话共享和热点客流的缓存Redis在地铁安防系统里主要有三件事验证码缓存、Token黑名单、热点客流统计。验证码登录页的图形验证码存到Redis设置expire时间为120秒防止暴力尝试。Token黑名单用户修改密码或退出登录后把Token加入Redis黑名单过期时间跟Token一致。虽然JWT本身是无状态的但配合黑名单可以解决“被踢用户还能访问系统”的问题。客流统计每个站点的进站客流用Redis的INCR命令计数定期同步到MySQL。用Hash结构存当天各小时段的客流数字前端展示曲线图非常流畅。spring: redis: host: localhost port: 6379 database: 0 lettuce: pool: max-active: 8 max-idle: 8一个容易忽略的小技巧Redis的Key一定要设计前缀比如metro:captcha:{uuid}、metro:token:blacklist:{token}、metro:stationflow:{stationId}:{yyyyMMdd}。前缀相当于命名空间后面加新业务不会乱也方便用SCAN命令批量清理。4.2 ActiveMQ告警通知的异步解耦当系统产生海量告警时如果每条告警都同步发短信、推消息接口响应会被拖跨。ActiveMQ在这里做的是削峰填谷告警产生后先入队再让消息消费者慢慢处理通知动作。我集成ActiveMQ的步骤引入spring-boot-starter-activemq依赖。在yml里配置broker地址生产环境用failover协议做高可用。定义队列名称常量比如queue.alarm.notify。生产者发送消息消费者用JmsListener监听并处理。Component public class AlarmNotifier { JmsListener(destination queue.alarm.notify) public void onAlarm(String alarmNo) { // 调用短信网关、生成站内通知、推送大屏 } }用MQ的另一个好处是方便扩展。比如后续要接入微信告警通知只需要新增一个消费者监听同一个队列不用改生产端代码。我在论文里把这段话写上老师基本不会追问细节。4.3 Elasticsearch HanLP告警日志的快速检索与中文分词为什么告警查询要用ES因为alarm_info表数据增长快而且需要按“报警内容”“物品名称”做模糊搜索。MySQL的LIKE %管%刀%只能用左模糊匹配性能差。ES的倒排索引则能秒级返回结果。HanLP在这里解决的是中文分词问题。比如用户搜索“管制刀具”ES分词器默认对中文是按单字拆的导致“管制”和“刀具”被拆散。引入HanLP分词器可以把“管制刀具”识别为一个完整词条搜索结果更准确。dependency groupIdcom.hankcs/groupId artifactIdhanlp/artifactId versionportable-1.8.4/version /dependencyListString words HanLP.segment(地铁站查获管制刀具); // 输出地铁/站/查获/管制刀具如果觉得集成ES太复杂毕设阶段可以用一个折中方案用ES索引告警数据但查询只做简单的match查询不强行优化分词器。毕竟数据量就那么点ES已经比MySQL快一个维度了。关键是证明你理解为什么需要ES而不是真的做TB级压测。4.4 MinIO摄像头抓拍图片与视频片段存储图片和视频不能直接存数据库更不能堆在本地磁盘。我选择MinIO作为对象存储理由很简单它兼容S3协议部署轻量而且有漂亮的Web控制台演示时很加分。Autowired private MinioClient minioClient; public void uploadFile(String bucketName, InputStream in, String objectName) { boolean exists minioClient.bucketExists(BucketExistsArgs.builder() .bucket(bucketName).build()); if (!exists) { minioClient.makeBucket(MakeBucketArgs.builder() .bucket(bucketName).build()); } minioClient.putObject(PutObjectArgs.builder() .bucket(bucketName) .object(objectName) .stream(in, in.available(), -1) .build()); }实践建议开两个Bucket一个是security-images存安检抓拍图片一个是video-clips存摄像头录制的报警片段。对象名用日期和摄像头编码做前缀比如2025/06/12/cam004_143015.mp4检索和清理都方便。这个环节放到答辩演示里比单纯展示数据表有说服力得多。5. 部署前的那些坑版本选择、配置细节和没有源码时的排查办法5.1 SpringBoot版本选择为什么闭眼用3.x会翻车先说结论如果是普通毕设我强烈建议用SpringBoot 2.7.x不要一上来就选最新的3.x。原因很现实——SpringBoot 3.x要求JDK17很多学校的毕设机器还停留在JDK8涉及环境重装不说MyBatis-Plus、Springdoc等一堆依赖都要换成适配版本。我实际遇到过的问题用SpringBoot 3.2.5 MyBatis-Plus 3.5.x启动报ClassNotFoundException: javax.annotation.PostConstruct。原因是JDK17里javax.annotation被移除了得引入jakarta.annotation-api依赖。SpringSecurity 6.x把WebSecurityConfigurerAdapter彻底废弃原来的antMatchers配置全改成requestMatchers旧教程里的写法直接编译不过。高版本SpringBoot对spring.factories自动装配的兼容性不同部分第三方starter没升级的话条件注解不生效。所以选版本的正确姿势是先去Maven仓库看依赖的兼容性矩阵确定2.7.x能搭配的组件版本再决定用哪个JDK。我最终用的是SpringBoot 2.7.18 JDK8 MySQL8整套组合非常稳。5.2 多环境配置结构和随机端口的调试技巧很多同学的毕设只有一个application.yml开发、测试、演示全用它这是隐患。推荐多环境配置# application.yml spring: profiles: active: dev # application-dev.yml server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/metro_security?useUnicodetruecharacterEncodingutf8 username: root password: root # application-prod.yml server: port: 8080 spring: datasource: url: jdbc:mysql://10.0.0.5:3306/metro_security username: metro password: ${MYSQL_PASSWORD}启动时用--spring.profiles.activeprod区分环境。答辩现场最怕两种问题一是数据库地址不对连不上二是端口被占用。随机端口能缓解后者server: port: ${PORT:0}这样每次启动会分配一个随机端口适合本地同时启多个实例做调试。但演示时别用随机端口不然前端配置的系统地址对不上。我一般演示固定8080本地多开用随机端口。还有个小知识点如果引入了Springdoc不想让接口文档在演示时暴露可以显式关闭springdoc: api-docs: enabled: false5.3 只有一个jar包时怎么找回业务逻辑这个坑我是在帮一个学弟调试时遇到的他的毕业论文是某培训机构给的里面只有打包好的demo.jar源码丢了。想改需求却发现无从下手。这种场景下反编译就成了排查问题的合理手段。注意我这里说的是排查自己合法持有的项目不是让你去破解别人的商业系统。在毕设交接、代码丢失这类场景里反编译用于找回自己的代码逻辑是有实际价值的。常用工具是JD-GUI和IDEA自带的Java Decompiler插件。步骤是用解压软件打开jar包把BOOT-INF/classes下的class文件解压出来。打开JD-GUI把class文件拖进去会还原出大致可读的Java源码。配置文件在BOOT-INF/classes/application.yml里可以直接看到数据库地址和中间件配置。SpringBoot打包的jar里依赖都在BOOT-INF/lib下想确认框架版本看lib目录下的jar文件名就行。反编译出来的代码一般缺少注释、变量名混乱但它能帮你快速搞清楚“哪个接口调用了哪些Service”。在毕业设计这种以自己学习为主的场景里这个方法比瞎猜高效得多。把这段经历写进博客也算是对“代码丢失”这种突发情况的一种应急预案。5.4 前后端联调的那些奇怪问题SpringBoot Vue前后端分离的项目联调阶段的坑比后端开发阶段还多我整理三个高频的跨域问题前端请求被浏览器拦截。解决方式是写一个CorsConfig允许指定的前端地址访问不要用*允许所有来源。安全起见allowedOriginPatterns配置成具体的前端域名。时间格式错乱后端返回LocalDateTime默认是一串数组前端显示成“[2025,6,12,10,30,0]”。解决方式是加Jackson配置统一格式为yyyy-MM-dd HH:mm:ss。文件上传大小限制SpringBoot默认允许上传文件大小为1MB安检图片经常超限。需要在yml里配置spring: servlet: multipart: max-file-size: 20MB max-request-size: 50MB这些坑不踩一遍答辩演示当天绝对手忙脚乱。我把联调的检查点做成清单每次启动前后端都要过一遍。6. 上线与答辩从本地到Docker的平滑迁移6.1 Dockerfile和docker-compose编排毕设能跑起来只是及格能用Docker部署是加分。特别是最后答辩如果有现场演示环节Docker可以保证环境一致性——你上午在实验室调好的样子下午在答辩机器上一点不差。我用多阶段构建写DockerfileFROM maven:3.8-openjdk-8 AS build COPY . /app WORKDIR /app RUN mvn clean package -DskipTests FROM openjdk:8-jre COPY --frombuild /app/target/metro-security.jar /app/metro-security.jar EXPOSE 8080 ENTRYPOINT [java, -jar, /app/metro-security.jar, --spring.profiles.activeprod]配套的docker-compose.yml可以一次性把MySQL、Redis、MinIO和后端服务编排起来version: 3.8 services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: metro_security ports: - 3306:3306 volumes: - mysql-data:/var/lib/mysql redis: image: redis:7 ports: - 6379:6379 backend: build: . ports: - 8080:8080 depends_on: - mysql - redis volumes: mysql-data:注意depends_on不代表等待MySQL完全启动。稳妥的做法是在后端启动命令里加个等待脚本或者用healthcheck。毕设演示时可以先手动docker compose up后等十几秒再访问问题不大。6.2 答辩演示前必须自测的流程答辩现场讲的不是所有功能而是“系统能解决一个完整问题”。我建议把演示过程设计成一条主链路大约5分钟能讲完登录展示图形验证码和JWT认证过程说明用户角色的权限差异。浏览客流统计打开一个站点的客流曲线图指出数据来自Redis缓存。新增一条危险品安检记录界面弹出告警提示此时后台自动生成了告警。进入告警中心找到刚才生成的告警点击“启动应急预案”系统解析出任务清单。模拟巡更超时等待定时任务扫描生成告警展示主动告警能力。打开统计报表展示一条趋势曲线。演示前重点检查三件事一是演示用的数据库里有没有足够的、能证明趋势的数据二是定时任务的触发时间要提前算好不要演示现场等5分钟才出告警三是前端页面不要出现接口报错弹窗提前把后端日志级别调成info不要打印一堆乱码。6.3 演示数据怎么准备才显得真实准备演示数据是这个项目最耗时也最容易被低估的一步。我的做法是写一个DataGenerator类在系统启动时检测数据库的告警表记录数如果少于阈值就自动插入过去30天的模拟数据每天每个站点生成几十条安检记录物品名称从“管制刀具”“易燃易爆品”“普通可疑物”里按比例随机。每天生成几条告警时间分布在客流高峰时段。客流数据按小时生成早高峰7-9点和晚高峰17-19点数值高其他时段低。巡更记录保证每个巡更点每天至少有两三次打卡但故意留一两个站点在最近两天有超时未巡更的情况方便演示定时告警。这30天模拟数据一进去报表页面的曲线立刻真实了。很多同学演示时数据库里只有演示当场建出来的三五条记录曲线图一眼就能看出是造假的。最后再分享一个小技巧演示时把数据库备份文件放在U盘里万一答辩机器上的MySQL被搞得乱七八糟直接恢复备份。我当年答辩前靠这一手避免了一次翻车——现场机器上的MySQL字符集不对中文全变问号我恢复了自己的备份后一切正常。这个系统做完之后也可以往两个方向扩展前端加一个大屏驾驶舱展示客流热力图和告警分布后端接入更完整的视频分析模型做异常行为识别。地铁安防这个题目的上限基本取决于你愿意在业务深度上走多远。
返回列表