news 2026/10/16 3:23:12

Spring Boot后台管理系统实战:JWT认证、RBAC权限与二次开发指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot后台管理系统实战:JWT认证、RBAC权限与二次开发指南

简介:SpringBoot通用后台管理系统源码包,面向Java开发者和SpringBoot框架学习者,提供一个完整的后台管理项目示例。项目覆盖自动配置、Spring Data JPA/Hibernate数据持久化、MySQL数据库脚本、Spring Security权限控制、Thymeleaf页面模板以及Swagger接口文档等典型技术实践,同时涉及前后端分离、Docker容器化部署等主流应用思路,既可作为课堂教学配套案例,也能作为企业级后台快速开发的参考脚手架。压缩包共152个文件,大小约623KB,其中包含129个Java源码文件,以及xml映射配置、properties全局配置、gradle构建脚本、sql初始化脚本、jar依赖包、docx设计文档、png图片资源和README说明等;源码中可见用户管理、文件服务、图片处理等业务模块,结合文档可梳理模块划分与调用关系。当前已有109人学习,适合需要提升SpringBoot实战能力、深入理解后台系统分层架构的中级开发者。

1. 一个 Spring Boot 后台管理系统的活资源:从登录到权限控制,拿来就能改的业务底座

网上打包好的 Spring Boot 后台管理系统不少,但真正能让人在半天内跑通、一周内改完接入自己业务的并不多。这套通用后台管理系统压缩包,价值不在于代码量,而在于它把后台系统最绕不开的几件事串成了一条完整链路:用户如何登录、Token 如何签发与校验、接口如何按角色放行、菜单如何动态渲染、每一步操作怎么留痕。如果你正在给某个内部项目凑后台底座,或者刚开始接触企业级开发里的权限模型,这套系统的代码结构和配置方式,正好是能直接上手拆着学的参考对象。

2. 通用后台系统的骨架:技术选型、分层结构和应用配置

2.1 技术选型:Spring Boot + Spring Security + MyBatis-Plus + Redis

后台管理系统说白了就是一堆数据表的增删改查,外面套一个安全外壳。它的压力通常不高,并发有限,真正的复杂度在权限模型和接口规范上。这套系统的基础框架是 Spring Boot,认证授权走 Spring Security,数据访问用 MyBatis-Plus,MySQL 做主存储,Redis 用于缓存验证码和登录 Token。

选这套组合的理由很现实。Spring Security 虽然概念多、配置繁,但它对认证过滤器链和权限表达式的支持是 Spring 生态里最完整的;MyBatis-Plus 相比原生 MyBatis 省掉了大量单表 CRUD 的 XML 编写量,内置分页插件和字段自动填充,对后台管理系统这种典型场景非常顺手。Redis 在这里不是绝对必须,但把它放进去以后,验证码临时存储、登录状态主动失效都不需要动数据库,对多实例部署很友好。

值得强调的是,这套资源里的安全配置走的是 JWT 无状态方案,而不是传统 Session 方案。两者核心区别在服务端是否保存登录状态。JWT 方案把用户身份和过期时间编码进 Token,服务端只负责验签,天然适合前后端分离和多实例横向扩展;代价是 Token 一旦签发,短时间内无法主动撤销,所以系统里需要配合一个 Redis 黑名单或 Token 版本号来解决退出登录、改密码后的失效问题。这一点在后续章节会专门展开。

2.2 项目分层与目录结构:代码该放哪里,边界在哪

打开压缩包,映入眼帘的是标准 Maven 布局。单模块结构,按包名做功能切分,这是我比较推荐阅读顺序的资源类型,因为它没有多模块间的跳转负担,适合先建立整体印象。我在拆包时会先看整体目录,再看 security 包和 config 包,最后才看业务代码。

典型目录结构如下:

src/main/java/com/example/admin ├── common # 通用类:统一返回结果、全局异常处理、常量 ├── config # 配置类:Security、Redis、MyBatis-Plus、跨域 ├── controller # 接口层:接收请求、参数校验、返回统一结果 ├── service # 业务层:认证、用户、角色、菜单、日志 │ └── impl ├── mapper # 数据访问层:MyBatis-Plus 的 Mapper 接口 ├── entity # 数据库实体映射 ├── dto / vo # 入参对象与出参对象 ├── security # JWT 过滤器、Token 生成与校验、用户详情实现 ├── aspect # AOP 切面:操作日志、接口限流 └── utils # 工具类:加密、JWT、日期等 src/main/resources ├── mapper # 复杂 SQL 的 XML 文件 ├── sql # 数据库初始化脚本 ├── application.yml └── application-dev.yml / application-prod.yml

分层的核心原则是单向依赖:controller 调用 service,service 调 mapper,entity 只在 mapper 和 service 层之间透传,dto 和 vo 负责与外层交互。单向依赖的价值在于,后续要换存储、换安全框架或者做单元测试,每一层都有明确的替换边界。我拿到资源时最先看 security 包,因为权限认证是理解整套系统的钥匙,只要看懂 JWT 过滤器链条,后续所有接口权限配置都能顺出来。

2.3 配置文件与应用启动参数:多环境拆分和数据库初始化

application.yml 是所有环境的公共配置,环境差异放到 application-dev.yml 和 application-prod.yml。启动时通过--spring.profiles.active指定环境,这也是标准做法。

spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/admin_system?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: "改成你自己的密码" redis: host: localhost port: 6379 database: 0 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml type-aliases-package: com.example.admin.entity configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl server: port: 8080 servlet: context-path: /api jwt: secret: "这里是一段至少32位的签名密钥,务必换成自己的" expiration: 86400000 header: Authorization prefix: "Bearer "

这段配置里有几个关键点。第一个是 MySQL 连接串,useUnicode=true&characterEncoding=utf8这两个参数缺一不可,漏掉后中文写入会乱码;serverTimezone=Asia/Shanghai解决时区差八小时的问题。第二个是 MyBatis-Plus 的map-underscore-to-camel-case,开启后数据库下划线字段自动映射为驼峰属性,实体类里就不用写一堆 @TableField。第三个是jwt.secret,这套系统里所有 Token 都由它签名,长度建议至少 32 位,部署到生产环境必须换掉默认值,不然别人拿到源码就能仿造你的 Token。

数据库初始化涉及 SQL 脚本,资源包的sql目录下一般有init.sql和data.sql,前者建表,后者插入初始数据。首次导入时建议两个都执行,然后立刻改掉默认管理员密码。

3. 部署与验证:从 SQL 脚本到浏览器登录的完整路径

3.1 环境清单与版本匹配

在跑这套系统之前,先确认本机环境。JDK 建议 1.8 或 11,MySQL 用 5.7 或 8.0,Redis 3.2 以上,Maven 3.6 以上。前端如果用了 Vue,还需要 Node.js 14 以上。

版本不匹配是很常见的翻车点。比如 MySQL 8.0 的驱动类名变成了com.mysql.cj.jdbc.Driver,老项目里写的是com.mysql.jdbc.Driver,后者在新驱动下会直接启动失败。再比如 Spring Boot 2.6 之后,默认禁止了循环依赖,如果项目里有循环依赖的 Bean,启动时会报错“The dependencies of some of the beans in the application context form a cycle”,这种通常要去掉 @Autowired 改构造器注入。先把环境版本和 pom.xml 里依赖版本对齐,能省下大半个晚上的排查时间。

3.2 数据库初始化:SQL 脚本导入与初始账号定位

SQL 脚本在resources/sql目录下。按顺序执行,先建库,再导入表结构和基础数据。命令行方式如下:

mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS admin_system DEFAULT CHARACTER SET utf8mb4;" mysql -u root -p admin_system < sql/init.sql mysql -u root -p admin_system < sql/data.sql

三个命令分别完成建库、建表、插初始数据。注意utf8mb4和utf8的差别,utf8mb4 能存完整的 Unicode 字符,包括 emoji 表情和一些特殊符号,后台系统只要涉及用户输入内容,都建议用 utf8mb4。

导入完成后看表结构,这类通用后台系统至少会有这几张核心表:用户表、角色表、菜单表、用户角色关联表、角色菜单关联表、操作日志表。初始账号一般写在 data.sql 里,常见的是admin / admin123,也有的是admin / 123456。登录后第一件事是去用户管理里改密码,这个习惯能避免很多安全问题。如果 data.sql 执行后登录不进去,先检查是不是 SQL 脚本里的密码字段是加密密文,和系统使用 BCrypt 还是 MD5 加密的算法不匹配。

3.3 后端启动验证与前端路由联动

数据库就绪后,用 Maven 打包启动后端:

mvn clean package -DskipTests java -jar target/admin-system-1.0.0.jar --spring.profiles.active=dev

--spring.profiles.active=dev指加载 application-dev.yml 里的配置。启动日志中出现“Started Application in X seconds”表示成功。随后验证接口:

curl -X POST http://localhost:8080/api/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"admin123"}'

登录接口会返回包含 Token 的 JSON。拿到 Token 以后,调用一个需要登录的接口测试:

curl -X GET http://localhost:8080/api/user/list \ -H "Authorization: Bearer <上一步拿到的token>"

如果返回业务数据而不是 401,说明认证链路已经通了。很多这类系统内置了 Swagger 或 Knife4j 接口文档,启动后访问/swagger-ui.html或/doc.html就能看到所有接口清单和参数定义,这是理解系统功能最快的方式。

前端部分如果是独立 Vue 工程,则在web或frontend目录执行npm install然后npm run dev。注意前端代码里配置了代理转发,比如/api开头的请求会被转发到http://localhost:8080,这个代理配置如果没生效,前端页面会报请求跨域或者 404。优先排查 Vite 或 webpack 的 proxy 配置,而不是去后端改 CORS。

4. 核心实现解读:认证、授权与日志的落地细节

4.1 JWT 登录认证流程:Token 签发、校验与过滤器链

Spring Security 本身有一套复杂的过滤器链,JWT 方案的接入点是在 UsernamePasswordAuthenticationFilter 之前插入一个自定义过滤器,负责从请求头里解析 Token 并创建认证对象。核心逻辑大概是这样:

public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtTokenProvider tokenProvider; private final UserDetailsService userDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { String token = resolveToken(request); if (token != null && tokenProvider.validateToken(token)) { String username = tokenProvider.getUsernameFromToken(token); UserDetails userDetails = userDetailsService.loadUserByUsername(username); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } chain.doFilter(request, response); } private String resolveToken(HttpServletRequest request) { String bearer = request.getHeader("Authorization"); if (StringUtils.hasText(bearer) && bearer.startsWith("Bearer ")) { return bearer.substring(7); } return null; } }

这段代码的要点在三个地方。OncePerRequestFilter保证每个请求只过滤一次,避免重复执行。resolveToken从请求头中取出 Token 并去掉 "Bearer " 前缀,前缀约定在配置文件的jwt.prefix里。最关键的是SecurityContextHolder.getContext().setAuthentication(...),这一步把认证对象放进安全上下文,后续的 @PreAuthorize 注解才能拿到用户角色信息做判断。

登录接口负责签发 Token,流程包括验证码校验、用户名密码校验、Token 生成和返回。密码校验这块,这类系统普遍用 BCrypt 加密存储,校验时passwordEncoder.matches(rawPassword, encodedPassword)返回 true 才放行。不用 MD5 的原因是 BCrypt 自带盐值,同样的明文每次加密结果不同,能有效对抗彩虹表攻击。

4.2 接口级权限控制:注解式鉴权与动态权限点

这套系统最实用的部分是权限控制。它采用 RBAC 模型,用户关联角色,角色关联菜单和权限点,接口层通过注解控制访问范围。比如用户管理接口:

@PreAuthorize("hasRole('ADMIN')") @GetMapping("/user/list") public Result pageUsers(@RequestParam Integer page, @RequestParam Integer size) { return Result.success(userService.page(page, size)); } @PreAuthorize("hasAuthority('system:user:delete')") @DeleteMapping("/user/{id}") public Result deleteUser(@PathVariable Long id) { userService.deleteById(id); return Result.success(); }

hasRole('ADMIN')和hasAuthority('system:user:delete')的差别值得说清楚。hasRole 要求用户拥有角色,并且 Spring Security 会自动给角色名加上ROLE_前缀,数据库里的角色编码也要对应写ROLE_ADMIN;hasAuthority 则直接匹配权限点字符串,粒度更细。比如一个运营角色能查看用户列表但不能删除用户,就可以给它配置system:user:list权限而不配置system:user:delete权限。

实际项目里,权限点不是写死的,而是从数据库动态加载。用户登录时,系统把该用户所有角色对应的菜单权限点查出来,组装成一个权限集合放进认证对象;接口被访问时,注解里的权限字符串和这个集合做比对。我一般会重点看菜单表里perms字段的取值规则,它决定了前端按钮权限的动态渲染粒度。

4.3 操作日志的 AOP 实现:埋点、参数解析与异步落库

后台管理系统的审计需求一般靠操作日志解决。这套系统用 AOP 切面实现日志记录,不侵入业务代码,做法是在自定义注解上挂切面:

@Aspect @Component public class OperationLogAspect { @Around("@annotation(operationLog)") public Object record(ProceedingJoinPoint pjp, OperationLog operationLog) throws Throwable { long start = System.currentTimeMillis(); Object result = pjp.proceed(); long elapsed = System.currentTimeMillis() - start; // 从 SecurityContextHolder 获取当前操作人 // 从 RequestContextHolder 获取请求 IP 和访问路径 // 拼装日志对象,写入 sys_operation_log 表 return result; } }

这个切面的设计思路是透明拦截。业务代码关注自己的逻辑,日志记录完全由切面完成。日志字段一般包括操作人、操作模块、操作类型、请求方法、请求路径、参数摘要、耗时和执行结果。参数摘要这里有个坑,不要把完整的密码参数打印进日志,这类资源一般会对敏感字段做脱敏处理,比如只保留账号前几位。

异步落库是这类日志模块的另一个重点。如果每记录一条日志都在请求线程里同步写库,等于给每个接口增加了额外延迟,高并发下会拖慢业务响应。常见做法是使用 Spring 的 @Async 注解把日志写入放到独立线程池里执行,或者先塞进 BlockingQueue 再定时批量落库。配置线程池时要关注队列容量和拒绝策略,队列满了以后是丢弃日志、调用方执行还是覆盖旧日志,决定了系统在极端情况下的行为。

5. 避坑实录:从环境到权限链路上最容易翻车的四个检查点

5.1 检查点一:数据库连接串少了参数,中文全变问号

之前一次部署中,厂商把数据库连接串简写成了jdbc:mysql://localhost:3306/admin_system,结果系统跑起来后所有录入的中文都变成问号。排查了半天,发现字符集连接的参数characterEncoding=utf8没带。数据库本身是 utf8mb4,但客户端连接时指定的字符集不对,写入自然就是乱码。

解决方式是把连接串补全:jdbc:mysql://localhost:3306/admin_system?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai。这里的useSSL=false也很重要,MySQL 8.0 默认开启 SSL 校验,本地环境没有配置证书时会报连接超时或者 SSL 握手失败。从这个坑之后,每次初始化环境我都先跑一条插入中文数据的 SQL,确认字符集没问题再继续。

5.2 检查点二:JWT 过滤器抛异常导致接口全部 401

一次联调中,前端反馈所有需要 Token 的接口突然全部返回 401,但登录接口本身是正常的。打开后端日志,发现错误堆栈是“JWT signature does not match”。排查后发现是运维在服务器上改了application-prod.yml里的jwt.secret,而前端本地调用的后端实例加载的还是旧配置文件,两个实例签出来的 Token 互相不能验证。

解决方式是统一配置管理,把 JWT 密钥集中放到配置中心或环境变量里,保证所有实例读到的是同一个值。另外要注意,改动jwt.secret后,所有在线用户手里的旧 Token 都会失效,这是预期行为,但要在变更通知里说清楚,让用户重新登录而不是当作故障处理。从那以后,密钥变更这类操作每次都要走配置变更评审流程。

5.3 检查点三:权限注解不生效,接口被匿名访问

在某个新写的控制器接口上加了@PreAuthorize("hasRole('ADMIN')"),但测试时发现普通用户也能正常访问。原因在于 @EnableGlobalMethodSecurity 注解没有打开。Spring Security 默认不处理方法级安全注解,必须在配置类上显式声明:

@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig { // 相关配置... }

prePostEnabled = true表示启用 @PreAuthorize 和 @PostAuthorize 系列注解。另一个原因是如果配置类上同时启用了 Spring AOP 和 CGLIB 代理,而注解方法所在的 Bean 创建了代理,权限判断被代理类拦截,但某些情况下代理没有生效。尤其是当你在同一个类内部调用带注解的方法,比如this.someMethod(),注解是不会被处理的,因为内部调用绕过了代理对象。

之所以说这个坑值得记录,是因为它的现象很隐蔽:系统一切正常,只是某个接口的权限控制悄悄失效了。排查时先看配置类有没有开启注解鉴权,再看调用链是不是经过代理对象。

5.4 检查点四:MyBatis-Plus 分页失效,查询返回全部数据

分页是后台系统的刚需,但 MyBatis-Plus 的分页需要注册分页插件,否则Page对象传进去,查询结果仍然是全表数据。常见场景是资源包里自带了一个MybatisPlusConfig配置类,但开发者把@Configuration注解误删了,或者类没有被 Spring 扫描到。

@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }

没有这个 Bean,selectPage实际上执行的是全量查询,然后把内存中的一部分返回给你,数据量大了以后内存和耗时都会出问题。排查方法是打开 MyBatis 的 SQL 日志,看执行语句里有没有LIMIT关键字;如果连 SQL 条件都带了但没 LIMIT,基本可以确定分页插件没注册。

6. 二次开发技巧:把它改成自己的业务底座,防住四个常见扩展问题

拿到资源之后,最关键的并不是看懂代码,而是知道自己要改哪些地方才能把它变成自己的系统。我按自己的经验总结一个固定流程,每接入一个新业务模块都走一遍。

第一个是加数据库表和对应实体。直接在 SQL 脚本里追加建表语句,然后在entity包下建实体类,mapper包下建 Mapper 接口。注意实体继承 BaseEntity 或按资源包既有的公共字段规则来写,这类系统通常会在 BaseEntity 里定义创建人、创建时间、更新人、更新时间和逻辑删除标记,这些字段由 MyBatis-Plus 自动填充,不需要在业务代码里手动赋值。加 Mapper 接口时,单表查询直接在接口里定义方法,加对应 XML 只处理多表关联查询。

第二个是加菜单和权限点。新增菜单要到菜单表里插数据,菜单编码、父级编码、路由路径、排序字段都不能空。权限点要和接口的@PreAuthorize("hasAuthority('xxx')")保持一致,否则前端配置了按钮权限后后端不认,或者后端要求权限但菜单里没配,接口会直接 403。菜单表的数据结构通常分为目录、菜单、按钮三级,按钮权限挂在菜单级别之下的perms字段里。

第三个是前端动态菜单的联动。这类系统的菜单大多是动态渲染的,前端根据登录接口返回的菜单树生成侧边栏。如果你新增了菜单但前端没有路由与之对应,点击菜单会跳转到空白页或 404。解决方法有两种:一种是后端返回的菜单 JSON 里包含前端路由的path和component字段,前端用map动态注册路由;另一种是在前端路由表里预先写好所有业务路由,后端只决定菜单的显示和隐藏。两种方案各有取舍,动态注册路由灵活但排错困难,预注册路由代码量多但直观。我倾向于后者,除非业务模块化程度非常高。

第四个是接口返回值格式的统一。这套系统的所有接口都返回Result结构,约定code = 200表示成功,其他表示业务失败,HTTP 状态码只反映请求是否被处理。在这个约定下,前端拦截器就可以统一处理错误提示和登录失效。千万不要在一个新加的接口里直接返回一个 Map 或者裸对象,这会让前端联调时多写一堆特殊判断。

我在一次交付中吃过这个亏,新增了一个导出接口,返回的是二进制流,没有走 Result 结构,前端鉴权拦截器拿不到 code 就不知道登录是否过期,结果导出临时失效时出现了一个很隐蔽的“弹窗不提示、接口静默失败”的问题。从那以后,我每次新增接口都强制要求走统一的返回封装,导出类接口也必须附一个错误时的 JSON 响应,把这个约定写进了团队的接口规范里。

如果这套通用后台系统是你第一次接触 JWT 认证,建议你先别急着改业务,把登录接口完整跑一遍,再看 JwtAuthenticationFilter 里的每个方法打印了什么日志,最后再动手加业务模块。理解认证链路对后续权限排查的帮助,远比你多写一个 CRUD 接口的价值大。希望这套系统能帮你省下搭底座的时间,把精力留在真正有业务逻辑的地方。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 3:23:11

Java千万级CSV导出内存溢出?流式查询+缓冲写入解法

简介&#xff1a;面向中高级Java开发者&#xff0c;这份资源围绕千万级数据量的CSV导出场景&#xff0c;针对一次性加载导致的内存溢出与性能瓶颈&#xff0c;提供了完整的优化方案与可直接运行的示例代码。压缩包共十个文件&#xff0c;其中九个Java源文件覆盖分批处理、多线程…

作者头像 李华
网站建设 2026/10/16 3:22:18

Lombok编译期魔法:注解处理器如何修改Java语法树

简介&#xff1a;这份资源围绕 Lombok 的实现原理展开&#xff0c;面向希望深入理解注解处理器与编译期字节码增强机制的 Java 开发者&#xff0c;尤其适合已能熟练使用 Data、Getter 等注解、想进一步探究其底层运作方式的中高级工程师。压缩包共 40 个文件&#xff0c;约 88K…

作者头像 李华
网站建设 2026/10/16 3:22:11

CrystalReport VCL 11 报表控件安装与老系统维护实践

简介&#xff1a;面向使用 Delphi/BCB XE 的开发者&#xff0c;这份 CrystalReport 水晶报表 11 R2 版 VCL 控件资源&#xff0c;主要解决在 RAD Studio 工程中集成报表设计、数据绑定、预览与打印输出的需求。压缩包共 710 个文件&#xff0c;以 pas 源码、dcu 编译单元、dfm …

作者头像 李华
网站建设 2026/10/16 3:22:07

双目立体标定与极线校正全链路实战指南

简介&#xff1a;本资源是一套基于OpenCV 3.0与Visual Studio 2013实现的双目视觉立体标定与校正完整工程&#xff0c;面向计算机视觉初学者、机器人感知方向学习者及三维重建实践者&#xff0c;解决双目相机系统参数标定、极线校正等核心问题&#xff0c;为后续立体匹配与深度…

作者头像 李华
网站建设 2026/10/16 3:22:06

PyTorch深度学习实战:CNN、RNN到GAN的完整源码解析

简介&#xff1a;面向深度学习初学者的PyTorch实战教程配套资料&#xff0c;汇集视频课程中的全部源代码和PPT讲义&#xff0c;覆盖卷积神经网络、循环神经网络、生成对抗网络及图卷积网络等核心模型主题&#xff0c;并提供Cifar10与ResNet18图像分类实战任务。资源共142个文件…

作者头像 李华
网站建设 2026/10/16 3:21:49

VRRP报文交互全解析:从通告机制到主备切换的工程实践

1. 从一个"主备切换慢半拍"的现场说起最早接触VRRP&#xff0c;是在一个园区网的改造项目里。核心交换机做了双机热备&#xff0c;按设计文档的说法&#xff0c;主设备一挂&#xff0c;备设备应该在秒级内接管网关&#xff0c;终端用户几乎无感知。结果上线第一天就出…

作者头像 李华