
这是一个让我这类做内部系统的开发者特别有共鸣的项目——80%的企业网管工作都不是靠所谓的高深技术堆出来的而是靠把“查设备”“查IP”“查告警”这些琐事管清楚。市面上确实不缺Zabbix、Cacti这类重量级监控平台但真落到一个只有两三百台设备、没有专职运维团队的公司配置成本和使用门槛反而成了负担。所以我一直想找一套“小而全”的方案最后干脆决定自己动手用SpringBoot Vue MyBatis MySQL这套经典组合做一套企业内部小型网络管理系统。整套源码包含完整的设备管理、IP地址池管理、告警推送、工单处理和权限控制模块前后端分离但又能合并部署拿过来改改数据库连接和Logo就能直接用。这篇文章我把这套系统的完整设计思路、核心代码逻辑、数据库表结构还有部署过程中真实踩过的坑全部写出来。适合两类人看一类是公司里负责内部IT系统维护、想快速交付一个网络管理后台的开发者另一类是准备做毕业设计或者个人项目、想学习SpringBoot Vue全栈落地经验的同学。我会尽量把每个模块为什么这样设计讲明白而不只是贴代码。1. 先拆解需求企业内部网络管理到底要管什么1.1 小规模网络管理的真实痛点很多人一听“网络管理系统”就觉得是大型网管平台其实企业内部那种一两百台设备、两三个网段的规模需求非常具体。我接到这个需求时和运维同事聊了几轮发现真正高频的痛点是这几个设备台账混乱。交换机、路由器、防火墙、服务器、打印机散落在各个办公室和机房型号、IP、位置、维保日期全靠Excel表格设备一变更表格就过期。IP地址管理靠猜。哪些IP被占了、哪些是空闲的、有没有人私自改IP导致冲突完全没有实时视图。出了问题只能拿命令行逐台ping。告警靠人肉发现。某台服务器宕机、交换机端口异常往往是业务部门先发现IT部门后知道。故障处理没有闭环。报修消息散落在微信群谁在处理、处理到哪一步、最后怎么解决的没人记录。所以这套系统的核心不是做一个花哨的大平台而是把“台账、地址、告警、工单”这四件事管清楚而且操作要足够傻瓜——因为使用者很可能就是两三个兼职管网的同事。1.2 市面开源方案的取舍与不满我也研究过几个当下主流的选择。Zabbix功能绝对强大能监控到非常细的指标但它的架构对小型环境来说偏重需要独立的数据库、独立的采集器模板和告警规则配置曲线很陡。很多网络设备厂商自带的网管软件如Cisco Prime、H3C iMC又只能管自家设备在小品牌混合组网的现场基本失灵。更关键的一点是市面方案的数据模型和权限体系很难和公司内部的组织架构打通。比如我希望“部门负责人只能看到自己部门的设备”“运维主管可以看到全局告警”这类业务规则在通用平台里配置起来非常痛苦。综合考虑后我决定自研一套技术栈锁定在SpringBoot Vue MyBatis MySQL。原因很直接这套组合在Java技术圈人才储备最多遇到问题网上资料最全而且前后端分离开发效率高后期让同事接手也不至于看不懂。2. 技术选型不是拍脑袋四件套背后的具体理由2.1 SpringBoot为什么不用SSH或者Spring Cloud项目背景决定了没必要上微服务。一个内部系统单机部署就够核心诉求是快速开发、稳定运行、方便维护。SpringBoot对比传统的SSHSpring Struts Hibernate结构优势非常明显内置Tomcat打包成可执行jar直接跑自动配置机制省掉了一大堆XML配置起步依赖把常用库都整合好了。选择SpringBoot而不是Spring Cloud是因为业务规模决定了分布式带来的复杂度远大于收益。哪怕以后设备数量翻几倍单台服务器加个配置也完全能扛住。我在实际开发中最爽的一点是spring-boot-starter-web和spring-boot-starter-validation两个依赖就把Web层和参数校验全部搞定不需要额外写配置类。2.2 MyBatis与JPA之争查询可控性才是命门ORM选型上我坚定选了MyBatis。网上关于MyBatis和JPA的争论很多我的判断标准很简单内部管理系统的报表和统计查询非常复杂动不动就是多表关联、条件拼接、按时间分组。MyBatis的XML里写SQL完全可控SQL怎么执行我心里有数不像JPA在某些复杂场景下生成的SQL性能不可预测。比如设备列表的过滤查询需要根据设备类型、所属部门、IP网段、关键字做动态组合用MyBatis的动态SQL节点写起来非常直观。而且MyBatis对数据库优化友好DBA接手后可以直接拿走SQL做调优。2.3 Vue渐进式框架带来的开发效率前端选Vue而非React一个原因是团队技术栈偏向Vue另一个是Vue的渐进式特性让后端出身的同事也能快速上手。Vue的单文件组件、响应式数据绑定、计算属性写起表单和列表页面比原生JavaScript高出好几个效率等级。版本上我选了Vue 3 Element Plus。Vue 3的组合式API让逻辑复用更顺手比如设备列表的分页、筛选、批量操作逻辑可以抽成一个useDeviceTable组合函数。Element Plus的表格、表单、对话框组件足够干净基本覆盖了后台管理系统九成的界面需求。2.4 MySQL 5.7还是8.0务实选择数据库我用了MySQL 5.7。理由挺务实这套系统的数据量级在万条以内5.7和8.0的性能差异根本体现不出来5.7稳定版本时间久各种工具链兼容性最好很多云数据库和容器镜像默认还是5.7。如果从零开始且服务器环境允许选8.0也没问题。但在这个项目中5.7足够稳定查询优化器对现有SQL执行计划非常成熟运维成本更低。3. 系统模块与整体架构先把边界画清楚再动手3.1 功能模块全景图整个系统按业务域拆成六个模块模块核心功能关键数据组织架构部门、岗位、员工管理部门树、岗位列表、员工信息设备管理设备台账、类型分类、生命周期设备信息表、设备变更记录IP管理IP地址池、分配/回收、冲突检测IP地址表、分配记录监控告警在线状态轮询、端口状态、异常告警告警记录表、监控规则表工单管理故障申报、派单、处理进度工单表、工单流转记录系统管理用户、角色、权限、操作日志用户表、角色表、菜单权限表每个模块不是孤立的。比如设备管理里的设备IP会关联到IP管理模块的地址池记录设备掉线产生的告警能一键生成工单工单处理结束自动更新设备状态。所以数据库设计阶段就要把这些关联关系梳理清楚。3.2 后端分层Controller/Service/Mapper的责任边界代码层面我保持了经典的三层结构但每层职责做了明确约定Controller层只做参数接收、格式转换、统一响应封装。不在Controller里写任何SQL相关逻辑。Service层承载业务规则。比如IP分配时要检查地址池状态、设备是否已存在这些判断全部集中在Service。Mapper层只做数据访问。一个Mapper方法对应一条SQL没有复杂逻辑。关于事务我习惯在Service层的业务方法上加Transactional。比如工单派单操作里要同时更新工单状态、新增操作记录、通知处理人三步任何一个失败都应该回滚这种一致性靠数据库事务来保证最可靠。3.3 RBAC权限模型内部系统里怎么实现才不啰嗦权限设计我没有过度设计采用经典的RBAC模型用户→角色→菜单权限。一张用户表、一张角色表、一张菜单表、两张关联表。用户登录后查询出所有关联的菜单权限存到Redis里做缓存每次接口请求通过拦截器验证权限标识。比较实用的一个点是按钮级权限。同一个设备列表页面普通员工只能看部门主管能导出运维管理员能编辑和删除。实现方式就是给菜单表加permission_code字段前端拿到用户的权限码集合后通过自定义指令v-permission控制按钮的显隐。后端同样在接口上做二次校验防止直接请求绕过前端。3.4 核心数据库表设计思路表设计遵循第三范式但个别查询频繁的报表场景做了适当的冗余。举例说明设备表会同时冗余设备所在的部门名称而不是只存部门ID。原因就是列表页展示时需要频繁关联部门表不如在写入设备时就把名称带一份查询快很多。设备信息表的字段设计上不仅包含基础型号、序列号、维保日期还特意加了两个字段monitor_flag是否纳入在线监控和snmp_communitySNMP团体名。这两个字段决定了设备是否会被后台任务自动轮询以及能否通过SNMP采集到更详细的端口和流量数据。4. 关键功能模块的实现细节与实战笔记4.1 设备发现与指纹识别怎么把网络里的设备“捞”出来系统里最核心的功能之一就是设备发现因为台账录入如果全靠手工这套系统的价值就少了一半。我实现了两种发现机制第一种是网段扫描。后台任务定时对配置的网段做Ping扫描在线的主机通过ARP表把MAC地址对应起来再结合主机名识别出设备类型。这个方法的优点是速度快、不需要目标设备配合缺点是只能拿到在线状态和很基础的指纹信息。第二种是SNMP扫描。对开启了SNMP的交换机、路由器、打印机通过读取系统的OID信息识别设备类型和厂商。比如读取1.3.6.1.2.1.1.1.0拿到系统描述通过1.3.6.1.2.1.1.5.0拿到设备名称再配合厂商OID库做模糊匹配。实际效果很理想一套小型网络有百分之七八十的设备能被自动发现剩余的手工补录就好。关键技巧是扫描任务的并发度控制太大会把交换机CPU打满导致网络卡顿我最终设置为每个网段同时扫描20个IP。4.2 IP地址池管理从“翻记事本”到状态机自动流转IP管理模块我做得比较细致。每个IP地址都有状态流转空闲→已分配→使用中→冲突→回收。系统启动后后台会周期性地轮询地址池结合ARP表判断每个IP实际是否被占用如果分配的IP实际没人用就自动标记为“空闲但保留”供管理员确认是否回收。对外提供一个IP申请接口员工提交申请后走审批流程审批通过自动从空闲池里分配一个IP同时给申请人推送通知。这个流程非常实用尤其解决了开发环境和测试环境经常因为IP乱配导致的环境冲突。4.3 WebSocket实时告警推送不让服务器“静悄悄”死掉监控告警的即时性是系统的体验关键我用WebSocket实现服务器到浏览器的实时推送。后端使用Spring的WebSocketHandler建立长连接前端订阅后只要后台的告警任务发现异常就会将告警记录写入数据库并发送JSON消息到所有在线的连接。告警规则的实现同样用了任务调度框架定时执行各类检查ICMP检测核心设备Ping不通、SNMP读取设备接口的错误包数量、HTTP请求检测业务系统状态码。每次检查结果都会和上一次状态对比只有状态发生翻转才产生告警避免一直重复推送同一条消息。4.4 Excel导入导出内部系统绕不开的工程能力这类管理系统有个隐藏需求就是旧有Excel台账的迁移以及各类报表的导出。我引入了工具库简化开发一张设备表格的导出只需要写一个实体类来映射表头声明列名和字段的对应关系剩下的工作就是查询数据并调用API。导入则必须处理错误容错每一条导入记录如果校验不通过要记录具体的行号和失败原因最后一次性汇总给用户。这个细节很重要因为实际操作中不可能要求对方提供的Excel完全是干净数据容错设计能避免导入一半程序报错的尴尬场景。4.5 登录与操作日志的完整实现思路安全审计这块我用AOP切面统一搞定。自定义一个OperationLog注解标注在需要记录审计日志的Controller方法上通过切面在方法执行后获取用户信息、请求参数、耗时和返回值状态写入操作日志表。登录安全上做了一层强化连续输入5次错误密码锁定账号15分钟。这个逻辑在登录Service里实现用Redis记录失败次数和锁定时间戳。另外所有管理端的登录操作都会记录IP地址和请求头里的User-Agent作为审计信息方便出问题时追溯。5. 部署交付与踩坑实录从源码到手把手跑起来5.1 环境准备版本匹配是首要问题首先要说明一个反复遇到的环境问题SpringBoot 2.7.x与SpringBoot 3.x在Java版本上有硬性要求。如果你用的JDK 8就必须选择SpringBoot 2.7.x版本线因为3.x官方要求JDK 17及以上。这套源码基于SpringBoot 2.7.x开发JDK 8运行没有任何问题但如果直接换成3.x版本不少依赖API需要调整。Node环境的坑也值得提醒。Vue 3项目建议使用Node 16以上的LTS版本npm安装依赖时如果出现ERESOLVE错误优先检查Node版本而不是急着用--force参数强行安装。我在本地用Node 14安装时就碰到过依赖解析失败换成Node 16后一切正常。5.2 前端打包放进SpringBoot的推荐方式部署方式我试过两种一种是前端单独部署Nginx后端单独运行jar通过反向代理解决跨域。这种方式灵活前端和后端可以独立升级适合分团队维护的场景。但随之而来的跨域配置和两个进程的部署成本需要接受。另一种方式就是把前端产物直接塞进SpringBoot的静态资源目录整体打包成一个jar文件单进程运行。具体步骤就是前端npm run build生成了dist目录直接把dist下所有文件复制到后端src/main/resources/static目录然后重新打包。只要不配置路由的history模式改写规则这种方式通常非常省心。我用的是后一种原因是内部系统用户量小不需要考虑前后端独立扩容。5.3 我踩过的五个坑每个都是真实教训第一个坑是MyBatis分页插件版本兼容问题。一开始引入了过新版本的分页插件但在SpringBoot 2.7下一直报Page参数无法解析异常。原因是插件的拦截器与旧版MyBatis的版本匹配不上。排查方式很直接把分页插件回退到与MyBatis版本对应的稳定版本问题立刻消失。这个教训是分页插件的版本必须配套不能只看插件自身的最新版本。第二个坑是Java 8时间类型的JSON序列化。默认的Jackson配置下LocalDateTime类型会被序列化成数组而不是字符串前端拿到的日期格式非常古怪。解决办法是配置Jackson的统一时间格式化并在对应字段上标注JsonFormat。第三个坑是跨域问题。开发环境中前端跑在8080端口后端跑在8081端口前后端联调时浏览器的跨域拦截导致Ajax请求全部失败。虽然最终部署方案合并成了一个端口但开发期的跨域配置最好一开始就做好一个WebMvcConfigurer的全局配置类就能搞定。第四个坑是数据库连接池的配置。系统刚上线时经常出现偶尔的数据库连接超时后来排查发现是连接池的maxActive配置过小高并发扫描任务把连接耗尽。优化了一下连接池参数把maxActive从10调到30同时增加了testWhileIdle的保活配置这个问题再没出现。第五个坑是文件上传大小限制。默认的SpringBoot上传限制是1MB设备巡检时上传截图和附件经常超过这个大小导致上传失败。需要在配置里手动调大multipart.max-file-size。5.4 导入数据库与初始化数据的要点源码包里附带的SQL脚本包含建表语句和基础数据比如内置管理员账号、演示部门信息和菜单权限数据。导入数据库时注意以下几点数据库字符集建议使用utf8mb4因为某些设备型号描述里会包含 emoji 表情字符默认的utf8字符集会报错导入前建议先确认脚本中数据库名的定义如果脚本里写死了数据库名而你的环境不一致需要做相应的替换初始化数据中的管理员密码是经过BCrypt加密的密文不用尝试直接明文修改数据库正确方式是通过系统管理界面重置密码。注意如果自己的环境中需要调整数据库连接重点检查配置文件里的连接地址、用户名、密码三个参数。连接地址的格式是jdbc:mysql://localhost:3306/数据库名?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiserverTimezone参数不能省否则时间字段的读写会报时区异常。6. 从开发完成到正式使用我对这套系统的复盘与建议系统上线运行到现在效果比我预期的要好。网络设备台账从以前的Excel“僵尸表”变成了实时更新的资产库新增的设备通过自动扫描识别人工只需要补充供应商和维保信息。IP地址的利用率也清晰了很多空闲池和已分配列表一目了然申请和分配流程不再依赖翻聊天记录。最让我满意的是告警模块的实际效果。有一次夜里一台核心交换机端口异常系统监测到错误包数量暴涨后立刻推送了告警值班同事第二天看到记录提前联系设备供应商处理避免了上班时间业务中断的风险。工单模块让IT支持不再混乱每一条故障从申报、派单到关闭都有完整时间线月度报表也能直接统计出响应时长和解决时长。如果看到这篇文章的你也打算做一套类似的系统我的建议集中在三点。第一先花足够时间理清业务流程设备、IP、工单之间的关系想清楚了再写代码否则后期返工成本很高第二技术栈没有最好只有最适配SpringBoot Vue MyBatis MySQL这套组合在内部管理类系统里是性价比很高的方案第三一定要预留好接口的扩展位哪怕现在用不到比如设备数据上行对接API、告警回调Webhook这些设计将来都会派上用场。最后分享一个写这类系统时我坚持的小习惯每个核心模块都留下一个简单的导出功能。内部系统的用户永远比你更清楚他想拿数据去做什么一个合适的导出按钮往往能省掉你被要求反复更改逻辑的大量麻烦。