☰
在线教育系统微服务架构:SpringCloud拆解与部署避坑指南
2026/10/2 11:15:38 网站建设 项目流程

简介:在线教育系统是一套面向Java开发者的微服务架构实战项目,整体分为前台用户网站与后台运营管理平台,业务模块包含课程、问答、文章三大核心部分。后端采用SpringBoot、SpringCloud、MyBatis-Plus等主流技术栈,集成Redis缓存、ActiveMQ消息队列、阿里云OSS对象存储与视频点播服务,使用JWT实现分布式单点登录,并利用POI完成用户信息的批量上传和注册功能;前端基于Node.js与Vue.js构建,配合ECharts制作统计图表,通过Swagger自动生成接口文档。项目还实践了微服务分库设计、Docker容器化部署以及Maven多模块管理,整体工程化程度较高。资源压缩包为zip格式,约198KB,已有1154人学习/下载,围绕真实在线教育业务展开,覆盖前台学习互动、后台运营管理等典型场景。通过学习这个项目,能够系统梳理在线教育系统的技术选型、模块拆分和前后端协作方式,对毕业设计、课程实训以及微服务入门都具有较高参考价值。

1. 从单体到微服务:在线教育系统拆开之后长什么样

拿到这套在线教育系统时,我下意识想找本地服务直接启动试试。结果发现前台和后台是两套完全不同的工程,前台是 Vue.js 做的用户端,后台是运营平台,中间撑着 SpringCloud 微服务。换句话说,这是典型的分布式教育项目,课程、问答、文章三块业务都走独立的微服务模块,而不是一个大包里塞满所有代码。

这种拆法带来的好处很实际:课程模块流量大,可以单独扩实例;问答模块迭代频繁,不影响课程发布;文章模块相对独立,甚至可以整体挂掉也不拖垮前台下单流程。坏处也直接,如果你想把整套系统跑起来,必须同时搞定 Redis、ActiveMQ、MySQL、Docker 这些中间件,顺序错了,光依赖注入的坑就能耗掉一下午。这套资源适合两类人:刚做完单体项目想学微服务落地的 Java 后端,以及准备做毕业设计或课程设计、想要一个前台后台都齐全的完整案例的人。我这里会把启动顺序、改哪些配置、哪里最容易翻车,一次性给你理清楚。

2. 微服务后台跑通:从 SpringCloud 模块拆分到服务启动顺序

2.1 前台、后台两套系统的边界在哪里

项目标题里写得很清楚,前端是 Node.js + Vue.js,后端是 SpringBoot + SpringCloud。你需要先弄明白,前后台是两个独立的前端工程,各自对接不同的后端服务。前台用户系统给学员用,课程列表、问答帖子、文章展示都在这边;后台运营平台给管理员用,负责课程上下架、问答审核、文章发布。

我第一次看这种工程结构时,容易犯的错是:直接打开 root 目录,找不到一个叫"主项目"的东西就开始慌。其实目录里应该有两套前端目录——比如edu-front-boot和edu-admin-boot,前者是用户端,后者是运营端。后端则是若干微服务模块,通常是按业务拆的:课程服务、问答服务、文章服务、用户服务,再配一个网关、一个注册中心。

在动手启动之前,先把模块之间的关系确认好。你会用到 SpringCloud 的注册中心(比如 Nacos 或 Eureka)、网关(Gateway),以及各业务微服务。标题里提到的是 SpringBoot + SpringCloud + MyBatis-Plus + HttpClient + MySQL + Docker + Maven,实际跑起来通常还要配合 Redis 和 ActiveMQ。启动顺序上,我一般按注册中心 → 配置中心 → 网关 → 基础服务 → 业务服务的顺序来排,因为业务服务启动时要向注册中心注册,也经常要拉取配置,基础服务没起来,业务服务会一直重试连接然后启动失败。

2.2 启动阶段要修改的 Maven 与配置参数清单

先把 Nacos 或 Eureka、Redis、MySQL 这些外部依赖准备好,再启动后端微服务。下面这份参数清单是我从实践里提取出来的,你对照自己的环境微调:

配置项推荐值说明
server.port每个服务不要冲突建议 8001 开始递增,避免和本地端口打架
spring.datasource.urljdbc:mysql://localhost:3306/edu?useSSL=false&serverTimezone=Asia/Shanghai去掉 SSL 能减少连接报错概率
spring.redis.hostlocalhostRedis 默认端口 6379
spring.activemq.broker-urltcp://localhost:61616ActiveMQ 默认端口,别改
spring.cloud.nacos.discovery.server-addr127.0.0.1:8848注册中心地址,如果换成 Nacos 需要先启动它
mybatis-plus.mapper-locationsclasspath*:mapper/**/*.xml别写成classpath:,否则多模块下扫描不到 XML

第一次启动时,建议在 IDEA 里用clean package -DskipTests先整体构建一次,确认所有模块都能编译通过,再逐个启动服务。如果直接spring-boot:run,服务启动顺序错了,在日志里看到Connection refused之类的内容是很常见的。你可以在每个服务的启动类上加@EnableDiscoveryClient,确保它能注册到注册中心去,否则网关路由找不到目标服务。

2.3 用 Nacos 或 Eureka 做注册中心的前置条件

我在跑这套项目时,默认先启动 Nacos,再去调整业务服务的bootstrap.yml。Nacos 的好处是除了服务注册和发现,它还兼任配置中心。不过,如果你的工程里用的是 Eureka,那就会简单不少,只需要在启动类加@EnableEurekaServer,在业务服务加@EnableDiscoveryClient即可。

有一点值得注意:这套项目里的很多微服务模块,依赖同一个基础模块或公共模块(比如统一返回结果、统一异常处理、JWT 工具类)。你在导入工程后,先不要急着改业务代码,而是先让所有模块都能compile通过。如果模块之间有依赖关系——比如课程服务依赖了用户服务提供的 API,那么要先启动被依赖方,否则你会看到 FeignClient 报 404 或连接失败。

启动后验证注册中心是否正常的标准做法是打开 Nacos 控制台,看服务列表里有没有注册上来的服务名。如果服务列表是空的,优先检查spring.application.name是否配置,这个不配,服务名会变成unknown,网关就不知道把请求转发到谁那去了。

2.4 HttpClient 在微服务间如何承担调用职责

这套项目里用的是 HttpClient 做服务间调用。也许有人会问,微服务之间不是应该用 Feign 吗?但在实际项目里,HttpClient 仍然有它的存在意义:它轻,不引入额外的 Spring Cloud 依赖,适合服务之间偶尔调用的场景。当你只是想从文章服务里去取一个用户头像,完全没必要走一套完整 Feign+Ribbon 的链路。

使用 HttpClient 时,我建议你把你写的调用逻辑封装到一个公共模块里,比如一个HttpClientUtil类,统一设置连接超时和读取超时。线上环境遇到过这样的问题:服务 A 调服务 B 时,因为 A 没有设置超时时间,默认可能等很久,一旦服务 B 响应慢,A 的线程就会被拖死。所以,只要是 HttpClient 调用,都建议显式设置connectTimeout和readTimeout。在资源自带的代码里,如果发现这两个时间没设置,建议你立刻补上。

2.5 Docker 化部署的改动边界

标题里提到了 Docker,但你要清楚,这个项目里的 Docker 通常指的是把各个微服务打成镜像、再用容器跑起来,而不是说本地开发就必须全程用 Docker。我常用的做法是:本地开发连本地的 MySQL 和 Redis,测试或部署时才用 Docker 编排,推荐在根目录放一个docker-compose.yml,把 MySQL、Redis、ActiveMQ 和各个服务作为服务编排进去。

写 Dockerfile 时注意两点。第一,基础镜像要用openjdk:8-jdk-alpine或openjdk:8-jre-alpine,不要直接用java镜像,这个镜像已经过时且很大。第二,JVM 参数要预留容器内存,比如容器限制 512M,那-Xmx就给 256M 或 300M,别让 JVM 觉得自己能随便用。否则容器一跑起来,内存就超了,直接被 137 错误杀掉。日志里看到 137,第一反应是 OOM Killer 而不是你的代码出了问题。

3. ActiveMQ、Redis 与 POI:业务链路上的隐患

3.1 哪些业务走了消息队列,哪些走了缓存

项目标题里点到了 ActiveMQ,说明部分业务是异步处理的。教育系统里最常见的异步场景是:用户购买课程后发送通知、上传视频后触发转码、问答帖被回复后通知楼主。在代码里找@EventListener或JmsTemplate这样的关键词,就能定位到 ActiveMQ 的入口。

Redis 在这套系统里承担的是缓存职责。课程详情页访问量极大,如果每次都查 MySQL,数据库压力会非常大。常见的处理是:第一次查询时把课程详情写进 Redis,并设置过期时间,后续请求从 Redis 取数据。修改课程信息后,手动删掉对应 key,让下一次请求自动回源。这样虽然简单,但对于教育系统这种读多写少的业务场景,能明显扛住前台压力。

我在看资源代码时,会比较注意 Redis key 的设计。如果 key 里没有带上课程 ID,那热点数据就不好缓存了。比如course:detail:{id}这种设计就比较合理。如果代码里发现直接用课程标题作为 key,最好提前改掉,否则历史遗留数据会影响后期的维护。

3.2 ActiveMQ 消费端如何做到不丢消息

ActiveMQ 是这套系统异步消息的中转站。消息生产者把任务丢进消息队列,消费端再异步处理。这个过程里最容易出现的故障,是消费端接收消息后,在处理逻辑完成之前就提前提交了确认。比如:

@JmsListener(destination = "course.order.queue") public void handleOrder(String orderId) { // 发送短信通知 sendSms(orderId); // 这里如果抛异常,默认ack还是会被确认,消息就丢了 }

如果业务代码里用的是AUTO_ACKNOWLEDGE模式,消息被消费时就会自动确认,后面哪怕你的业务逻辑抛异常,消息也不会重新进入队列,用户的订单通知就悄悄丢了。我接这个项目时,会优先检查监听容器设置的 acknowledge 模式,并建议改成CLIENT_ACKNOWLEDGE或使用手动确认。也就是说,消费端在处理完业务后才调用message.acknowledge(),这样一旦sendSms失败,消息还在队列里等待重试。

另外一点要注意:ActiveMQ 默认是异步发送的,failover协议要谨慎配置。有些线上故障,就是生产者把消息塞给一个已经不存在的 broker,导致消息一直积压。如果你的场景对消息可靠性要求高,可以考虑同步发送,或者在代码里开启useAsyncSend的开关并配合持久化。

3.3 Redis 缓存穿透与过期策略的调整位置

课程详情的缓存,一般会做一个「查缓存 → 没命中 → 查数据库 → 回填缓存」的标准流程。但恰恰这个流程如果没做好,极容易发生缓存穿透。比如有恶意请求,不断刷一个不存在的课程 ID,每次都会绕过 Redis,打到底层数据库。我一般会在缓存里对这个查询结果做特殊处理:查不到该课程时,也往 Redis 写一个空值并设置过期时间(比如 60 秒),这样后面同样的请求就只走 Redis,不会压到数据库。

系统里设置过期时间的地方,用的是 RedisTemplate,需要找到opsForValue().set(key, value, timeout, TimeUnit.SECONDS)这样的代码。如果项目里很多地方都是直接set不带过期时间,那么线上会积累大量永不失效的 key,时间一长内存就满了。

3.4 POI 导入导出时的内存溢出处理

后台运营平台里用 POI 操作 Excel 表格,比如批量导入课程信息、导出学生成绩等。POI 的HSSFWorkbook在操作大 Excel 时,会一次性把数据全部加载到内存里,稍微大一点的文件直接 OOM。这里的常见做法是:导入用WorkbookFactory.create而不是new XSSFWorkbook,导出时用SXSSFWorkbook来控制内存占用。

SXSSFWorkbook是 POI 提供的流式 Excel 写入方式,它允许只保留最近 N 行在内存里,其他地方写到临时文件。用法大概是:

SXSSFWorkbook workbook = new SXSSFWorkbook(200); // 保留最近200行在内存 Sheet sheet = workbook.createSheet("课程列表"); Row row = sheet.createRow(i); Cell cell = row.createCell(j); cell.setCellValue(course.getName()); // 写完后释放: workbook.dispose();

这是处理 Excel 内存溢出的标准做法。如果你在资源代码里看到new XSSFWorkbook(file)并且文件量级还不小,建议先替换成SXSSFWorkbook或WorkbookFactory.create再上线。

3.5 视频点播和阿里云 OSS 接入的可变点

视频和图片文件,项目里是通过阿里云 OSS 做存储的,视频点播则单独接入了视频点播服务。这里需要你注意:OSS 的密钥不应该硬编码在代码里,资源给的代码里往往会有一个application.yml配置区,专门存放accessKeyId和accessKeySecret,你在本地复现时,需要把它们替换成你自己的密钥,并注意不要提交到公开仓库。

视频点播的接入逻辑,通常包含上传视频、获取播放凭证、播放器初始化。后端在处理播放凭证时,会请求阿里的 OpenAPI。这里容易踩到一个坑:本地调试时,阿里云 SDK 默认读环境变量里的密钥。如果你根本没配,启动服务时不会报错,一旦触发获取播放凭证的功能,就会报InvalidAccessKeyId.NotFound。遇到这个问题,优先检查环境变量和代码中读取密钥的优先级,不要只盯着控制台的日志。

前端拿到播放凭证后,在 Vue 里通过阿里云提供的播放器初始化:

new Aliplayer({ id: 'J_prismPlayer', source: '<播放地址>', encryptType: 1, playauth: '<播放凭证>', width: '100%', height: '100%' }, function(player) { console.log('播放器创建成功'); });

这套逻辑里,最容易出问题的是encryptType和播放凭证的匹配关系,加密视频和不加密视频的取值不一样,改错就会出现播放器加载完黑屏。

4. 前台用户系统:Node.js 与 Vue.js 的工程落地

4.1 两个前端工程如何分别对接后端

前台用户系统和后台运营平台虽然都属于 Vue.js 技术栈,但它们在代码里是独立工程,有各自的package.json、各自的构建脚本、各自的接口调用封装。前台的接口基础路径通常指向网关,比如http://localhost:8000,后台运营系统的接口基础路径指向另外一个网关端口或同一个网关不同前缀。

在本地复现时,你需要用 npm 安装依赖。Node.js 版本建议保持在 14 到 18 之间,版本太低,webpack 起不来;版本太高,有的原生依赖编译会报错。装了依赖后,本地访问 Vue 页面是通过 webpack-dev-server 起的,默认端口一般是 9528 或 8080,但前端代码里会配一个代理转发,比如下面这段:

// vue.config.js module.exports = { devServer: { port: 9528, proxy: { '/api': { target: 'http://localhost:8000', changeOrigin: true, pathRewrite: { '^/api': '' } } } } };

这段代理配置的意思是:前端请求/api/course时,dev-server 会把它转发到后端的http://localhost:8000/course,并且把/api前缀去掉。新手常犯的错误是,后端服务地址配错了,比如后端口变成 8001,前端还在找 8000,跳转登录时频繁报跨域,第一步就该排查这个代理 target 是否和后端实际端口一致。

后台运营端同样有这样的代理配置。如果你装了 Nginx,也可以把前端构建产物dist目录发布到 Nginx 下,再配置一个/api前缀的转发到后端网关。这样前端代码里就不需要写死后端地址了。

4.2 课程、问答、文章三块业务的页面与接口

从资源里的路由可以看出,前台的课程部分包含课程列表、课程详情、课程视频播放页。问答部分包含问题列表、问题详情、发布问题。文章部分相对简单,主要是列表和详情。每一部分都对应一套 API 调用,通常以/api/edu/course、/api/edu/question、/api/edu/article这样的前缀区分。

我在排查接口问题时,习惯先做一件简单但高效的事:打开浏览器开发者工具,看 Network 面板里,某个接口是否返回了 401 或 403。如果出现,先去找后端的登录拦截器或网关的鉴权配置,排查 JWT token 是否无效或过期。教育系统前台,很多接口允许匿名访问,比如课程列表;但查看视频详情时,个别接口可能是需要登录的。

这些接口的拦截路径,可以在后端的网关配置里找到。网关的application.yml里一般有一组whitelist白名单,名单里放的是不需要 token 的路径。如果你的通用前缀改了名字,记得同步更新白名单,别让前端跳转时平白多出登录跳转。

4.3 ElementUI 组件与 ECharts 图表数据的组装

后台运营平台大量使用 ElementUI,比如表格、表单、日期选择器。这套资源里的 ECharts 图表,一般出现在运营平台的统计页面,展示课程销量、用户增长趋势等。ECharts 的数据一般来自后端聚合统计,比如按月返回订单数量,前端再填充进图表配置。

如果你改了后端的统计接口,却发现图表不更新,大概率是字段对不上。ECharts 的series.data是一个数组,要求每个元素是数值,而 Java 后端的聚合查询常把数据封成 Map,字段名可能叫data也可能叫value。你看资源代码时,需要注意后端返回字段和前端图表配置是否一致,如果不一致,可以在前端做一个数据映射,不要轻易去改动后端统一返回结构。

前端代码里比较常见的写法:

this.$http.get('/api/edu/statistics/course').then(res => { const list = res.data.data; this.chartOption.series[0].data = list.map(item => item.value); this.chartOption.xAxis.data = list.map(item => item.month); });

这里最需要注意的:res.data.data是两个 data 叠在一起。第一个data是 Axios 的响应结构,第二个data是后端统一返回结构里的业务数据。很多模板项目都是这样的三层结构,但不同项目这三层的字段名可能不同。在看资源代码时,先找到后端的统一返回类,确认它用的字段是data还是result,再对着前端调用改,会省很多时间。

4.4 后端 CORS 跨域与前端联调的边界

前后端分离开发,跨域问题绕不开。这套系统里,网关层一般会做一次 CORS 全局配置,放行指定的来源域名。本地联调时,你需要确认网关放行的来源是否包含你的前端地址,比如http://localhost:9528。如果没包含,前端请求就会报跨域错误。

有一种情况容易误判:后端接口明明可以访问,但浏览器报跨域。这种情况通常是预检请求OPTIONS没通过。你需要先在后端加过滤器,对OPTIONS请求直接返回 200,不要进入后续的业务拦截器。如果网关是 SpringCloud Gateway,可以在配置里加入全局 CORS 过滤器,同时注意:某些浏览器版本对携带凭证的跨域请求有额外要求,需要设置allowCredentials(true),并且此时allowedOrigins不能使用*,必须是具体的域名。

5. 避坑篇:运行这套项目的常见翻车点

5.1 Docker Desktop 启动失败:Virtualization support not detected

不少人在 Windows 上安装 Docker Desktop 后,启动时遇到报错,提示virtualization support not detected,这和系统虚拟化没开启或没有正确开启有关。

现象:安装 Docker Desktop 后,启动直接弹出红框告知虚拟化未开启,或者装了之后服务一直处在 starting 状态,反复横跳。解决:先到控制面板的“启用或关闭 Windows 功能”里开启 Hyper-V 和“虚拟机平台”。开启后重启电脑。如果已经开启仍然报错,可能是电脑 BIOS 里的虚拟化被关掉,进入 BIOS 把 Intel Virtualization Technology 或 AMD SVM Mode 设为 Enabled。有些低版本 Windows 10 家庭版对 Hyper-V 支持不完整,这种情况下我一般建议换用 WSL2 后端,在 Docker Desktop 的 Settings 里把 Engine 切到 WSL2。但这么做的前提是系统本身已经装好了 WSL2,并且运行wsl --set-default-version 2确保默认版本为 2。

5.2 MySQL 启动失败:error 2002(HY000)与 socket 连接问题

现象:启动项目后,日志里报ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock',所有服务都因数据库连不上而反复退出。原因:MySQL 服务进程没起来,或者端口被占用,也有可能是 socket 路径和配置不一致。解决:先确认 MySQL 服务状态,检查3306端口是否被占用,若被占用则结束占用进程或修改项目的数据库端口。如果是 Linux 环境下缺少/tmp/mysql.sock,常见做法是直接使用 TCP 方式连接,把application.yml或bootstrap.yml的 JDBC URL 改成jdbc:mysql://localhost:3306/edu?useSSL=false,确认参数里不要出现socket相关的写法。Windows 下也可以直接改localhost为127.0.0.1,避开 socket 解析上的细微差异。

5.3 MySQL 连接报错 e0434352 或 SSL 连接错误

现象:服务启动时日志报e0434352这样的错误码,或者出现SSL connection error。原因:MySQL 8.x 默认启用 caching_sha2_password 认证,旧版本驱动或连接串未关闭 SSL 时容易触发不兼容行为。解决:在 JDBC 连接串上追加useSSL=false&allowPublicKeyRetrieval=true。这是在 MySQL 8.x 场景下的标准组合:关闭 SSL 可以减少握手失败率,打开allowPublicKeyRetrieval则是为了支持 caching_sha2_password 的 RSA 公钥获取,否则会出现 authentication plugin 相关报错。

如果项目里用的是 MySQL 5.7,这条可以忽略。但如果数据库是 8.0,代码里又没有这些参数,那它早晚会以各种玄学的方式骚扰你。我一般会直接检查资源的配置文件,看到连接串里没有allowPublicKeyRetrieval就手动补上,免得日志在部署环境里才暴露问题。

5.4 前后端联调时跨域或登录态丢失

现象:前端页面能打开,但登录接口调用成功后,下一个需要带 token 的接口又返回 401。前端明明在请求拦截器里塞了 token,后端却像失忆了一样。原因:跨域时前端没有把 token 放在请求头里,或 token 存储 key 前后端不一致;也可能是 axios 默认没有携带凭证,产生了跨域 cookie 丢失。解决:在 axios 的withCredentials打开之前,先确认后端网关是否允许凭证跨域。如果后端已经设置了allowCredentials(true),我就要求前端请求都走统一的拦截器,把Authorization头塞进去:

service.interceptors.request.use(config => { const token = localStorage.getItem('edu_token'); if (token) { config.headers['Authorization'] = token; } return config; });

项目里如果登录后把 token 存到了 sessionStorage,而请求拦截器读的是 localStorage,那逻辑就会一直在空白里转圈。这条排查起来,十分钟就能解决,但如果不看代码,靠猜会浪费很久。建议收到资源后,先全局搜localStorage、sessionStorage、getItem这几个关键词,统一确认存储的 key 名和读取位置。

5.5 端口占用与服务启动超时

现象:某个微服务启动时日志显示端口被占用,服务启动之后又反复重启,或者网关启动后无法路由到任何服务。原因:多个服务配置了相同端口,或者某个服务启动较慢,网关启动时还没有发现服务。解决:如果服务注册到 Nacos,但网关暂时没有路由,建议等待几秒再刷新,不要频繁重启网关。如果是端口冲突,改掉其中一个服务的server.port,重新构建启动。如果发现某个服务一直处于注册成功但下线反复横跳的状态,重点检查健康检查配置和内存设置,常见原因是服务启动太慢,注册中心几次探测不通过后把它判定为异常。

6. 让这套资源真正变成你自己的项目:从替换密钥到改业务名

前面几章做的是"跑起来",这一章聊"改得动"。拿到资源后,第一件事不是看代码细节,而是全局替换项目的业务标识。项目里有很多硬编码的字符串,比如在线教育、online_edu以及一些默认的别名。把这些占位符替换成你自己的项目名,能减少后续排查日志时的困惑。

替换时不要用 IDE 的全局替换一把梭。先搜索edu开头的包路径,比如com.online.edu,改成你自己的域名前缀,比如com.example.school。注意同步修改application.yml里的spring.application.name,这个值在注册中心和网关路由中会用到。如果你改成跟网关里写死的路由前缀不一致,路由就失效了。所以改完服务名之后,务必去网关配置里检查对应的Path断言,比如将/edu-course/**改成/school-course/**。

接着处理密钥和外部依赖。阿里云 OSS 的accessKeyId和accessKeySecret、视频点播的凭证,还有 MySQL、Redis、ActiveMQ 的连接密码,都集中在配置中心或各个服务的application.yml里。建议把敏感信息抽到一个不被提交的application-local.yml中,本地启动时用spring.profiles.active=local指定,部署时再替换环境配置。

数据初始化这块,资源通常会附带 SQL 初始化脚本。脚本里可能包含预设的管理员账号和测试数据。我建议导入后,先把管理员密码用 MD5 加密过一次的值替换掉,避免默认密码留在线上。课程、问答、文章里的测试数据可留可改,不影响系统运行,但展示在自己项目里时,最好替换成你实际要用的业务数据。

代码层面,如果你打算把前台界面改成自己的风格,重点看 Vue 工程里的src/views目录,课程列表、课程详情、问答页和文章页都按功能模块分好了。常见的 UI 调整包括:首页轮播图、课程封面图、网站头部信息。ElementUI 的组件可以灵活替换,样式文件在assets目录里,全局主色可以通过修改变量或覆盖 CSS 实现。

后端方面,需要改业务逻辑的话,从 Controller 层进入。部分接口的数据权限,要找@PreAuthorize注解或 gateway 的过滤器。如果你要加深对整套架构的理解,可以试着新增一个简单模块,比如 "讲师风采" 或 "资料下载",完整走一遍建表、实体、Mapper、Service、Controller、Vue 页面,这样比看十遍代码都有效。我个人的习惯是,每接手一套新项目资源,都会强制自己从里到外走一遍:"启动 → 跑通关键链路 → 替换密钥 → 改名 → 新增一个小功能"这条完整流程。这套流程走完,项目才算真正接入了你的能力圈,而不是只停留在它原本的代码里。希望这篇拆解能帮你把这个在线教育系统跑顺,如果你在启动过程中遇到某个具体报错,拿日志里的关键字去定位,基本都能在配置层面找到答案。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询