news 2026/10/18 9:55:20

基于SpringBoot+Vue的课外活动管理系统设计与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于SpringBoot+Vue的课外活动管理系统设计与实现

1. 项目整体思路与技术选型

前后端分离已经是现在做课外活动管理系统的主流姿势,但真正从零开始把分支打全、逻辑理清楚,还是要费不少功夫。这套基于Java+SpringBoot+Vue的课外活动管理系统,核心解决的是高校/中职院校里“活动发布—报名—签到—统计”一整条链路的效率问题。以前纸质报名表在班里传来传去,统计人数要靠Excel手工拉,搞一次校园歌手大赛光核对名单就得加两天班。系统的目标很明确:学生能一眼看到所有活动、一键报名,管理员能发布活动、审批报名、到点导出数据,减少信息传递的磨损。

项目整体的技术栈,后端选择SpringBoot,前端选择Vue,数据库用MySQL(可平滑切换其他关系型数据库)。SpringBoot生态成熟,起步快,约定大于配置,特别适合做这类以CRUD为主的管理类系统。很多人纠结要不要用RESTful规范、要不要上Spring Cloud那一套,以这个项目体量来说,直接轻装上阵,老老实实把接口写好、数据库设计合理,反而痛点最少。

前端为什么选Vue而不是模板引擎?道理很简单——用户角色不同,页面职责差异大。学生端要的是清爽、快、手机上能操作,管理端要的是表格、筛选、状态流转。Vue组件化之后,两端页面可以各自维护,互不污染,这也是Vue长于传统JSP和FreeMarker的最重要原因。

技术选型层面,再看一下现实情况:市面上类似的课设和毕设项目里,Python+Flask、Node.js+Express、PHP也都能做,但SpringBoot在类型安全、生态完整度、后续可扩展性上胜出——比如同一套代码未来想接微信小程序、安卓App,只需在controller层加适配接口,逻辑层基本不用动。

项目实现的功能模块: - 用户模块:学生、教师、管理员三种角色,登录鉴权用JWT - 活动模块:发布、编辑、下架、审核、分类归档 - 报名模块:学生报名、取消报名、名额限制、状态流转 - 签到模块:活动当天签到码/手动签到,统计到场率 - 统计模块:参与人数、活跃度、活动类型占比、个人参与记录

这套结构既照顾了后台管理的严谨性,又不牺牲学生端的使用体验,符合当前大多数校园数字化管理系统的建设思路。

2. 核心功能模块拆分与数据库设计

2.1 模块职责与页面映射

课外活动管理系统的页面可以分成三个端来设计,每个端的路由和权限完全隔离:

学生端:首页展示最近上架的活动卡片,活动详情页(时间、地点、主办方、剩余名额),报名/取消报名按钮,个人中心(我的报名、我的签到记录)。

教师端:可以理解为活动发起人的工作台,教师在这里发起新活动、查看自己名下活动的报名列表、一键导出名单、活动结束时批量确认学生参与情况。

管理员端:平台的总控制台,用户管理(禁用/启用)、活动审核(上架/下架)、活动分类维护、全平台报名数据看板。

整个页面的权限控制就是围绕这三种角色做的前后端双重拦截。前端通过路由守卫判断本地token里的角色字段,决定哪些页面可以跳转;后端在controller层用两层保险——第一层是拦截器验token合法性,第二层是关键接口通过注解或手动判断角色,不会因为谁改了前端代码就越权操作。

做一个细节说明:报名模块的状态流转,是这块业务里最容易写乱的地方。我的设计是五个状态:已报名、已取消、已签到、已完成、已拒绝。学生端只看到前两个,教师端能看到全量。每个状态变更都写一条操作日志,避免出现“学生明明取消了,老师那边还显示报名成功”这种扯皮。

2.2 数据表设计的关键要点

数据库设计的核心是“外键适度、索引刚需”。过度外键会让后续统计查询非常痛苦,但完全没有关联关系又会把业务写死。我的办法是逻辑外键:表与表之间不建物理外键约束,但保留关联字段,在查询时通过JOIN或者子查询实现联查。这样既能保证数据灵活性,又不会因为外键校验导致导入数据时频繁报错。

核心表结构大致如下:

用户表(sys_user):id、username、password(BCrypt加密存储)、real_name、role(0学生/1教师/2管理员)、phone、email、status(0禁用/1正常)、create_time。

活动表(activity):id、title、cover、category_id、description、location、start_time、end_time、signup_deadline、capacity(名额上限)、signup_count(当前已报名数)、status(0草稿/1待审核/2审核通过/3已下架/4已结束)、creator_id、create_time。

报名表(activity_signup):id、activity_id、user_id、status(0已报名/1已取消/2已签到/3已完成/4已拒绝)、signup_time、remark。

分类表(activity_category):id、name、sort。

操作日志表(operation_log):id、user_id、action、target_type、target_id、detail、create_time。

建表的时候,有几个坑需要提前规避。第一,capacity字段要设定为20人、50人、100人这种整数,前端报名按钮要根据signup_count和capacity的差值实时判断是否禁用。这个逻辑放在后端也要做一次完整校验,防止并发情况下超员。第二,时间字段统一用datetime,不要用timestamp,一个是时区问题,另一个是timestamp的上限到2038年,虽然看起来遥远,但没必要留这个隐患。第三,所有金额类、统计类的字段类型要确定好,这个系统虽然不涉及钱,但参与人数这种int字段要注意加了索引,尤其是signup_count这个高频查询字段。

数据库层面的实操方案,我是通过一份SQL初始化脚本完成的,里面包含了建库、建表、以及三个角色的测试账号。运维配置里开启了MySQL的严格模式,防止一些隐式类型转换把数据写坏。初始化数据不宜造太多,每个分类放一个活动、三个学生账号即可,细致的数据可以登录系统后在管理端造。

2.3 接口设计规范

接口层采用的路径风格是标准的RESTful变体:列表类接口用GET + query参数,新增用POST,编辑用PUT,删除用DELETE。很多人写毕设时容易犯一个毛病:所有接口都写成POST,后面碰到特殊场景再一点点拆,反而越改越乱。

统一返回结构是配齐接口的第一步:

{ "code": 200, "message": "操作成功", "data": {} }

code非200即视为失败,前端axios封装了一层响应拦截器,统一处理失败弹窗和401跳转登录页的逻辑。返回结构的统一性,决定了前端对接接口时的工作量,如果每个接口一个返回格式,前端得在每个请求里都写一份不同的处理逻辑,后期维护成本直线上升。

核心接口清单如下:

模块接口路径说明
认证POST /api/auth/login登录,返回JWT
用户GET /api/user/profile获取当前用户信息
活动GET /api/activity/page分页查询活动列表
活动POST /api/activity发布活动
活动PUT /api/activity/{id}编辑活动
活动PUT /api/activity/{id}/audit活动审核
报名POST /api/signup学生报名
报名DELETE /api/signup/{id}取消报名
签到POST /api/signup/checkin签到
统计GET /api/statistics/overview平台数据概览

分页查询统一使用PageHelper或者MyBatis-Plus的分页插件,入参是pageNum和pageSize,返回体是总记录数加列表。这个设计在管理端表格组件里几乎是标配。除了列表接口之外,所有写操作接口要求请求头携带token,拦截器里做了动态放行:login接口、前端静态资源接口直接放行,其余接口先验token再验角色。

3. 项目构建与核心实现拆解

3.1 后端环境搭建与关键配置

开发环境以稳定为原则:JDK 1.8、Maven 3.6+、MySQL 5.7+。Windows本机跑的话直接装这些就行,不用纠结用不用Docker。项目构建选择Maven,因为依赖管理在SpringBoot生态里最顺滑——只需在pom.xml里引入SpringBoot父依赖,再按需添加web、mybatis-plus、mysql-connector、jwt、hutool等模块即可。

application.yml的一处关键配置示例:

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/activity_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: mapper-locations: classpath:mapper/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true jwt: secret: your-secret-key expiration: 86400000

jwt密钥要设置成足够长的随机字符串,不要在代码里硬编码,至少从配置中心或环境变量读取,避免将来代码泄露导致token可伪造。expiration按毫秒设置,我配的24小时,学生端如果一周不活跃就会过期,管理员端可以单独配长一些。

后端分层的目录命名建议按业务模块划分,而不是按controller、service、mapper、entity这样一刀切四包。最合理的做法是:外层controller包放接口,service、mapper、entity、dto等目录按业务子模块再建子包。刚开始写的时候两种方案看起来差不多,但项目一复杂,按职责分包的劣势马上显现——查找一段业务要跨四个包看,效率太低了。

MyBatis-Plus的核心价值是那些单表CRUD自带方法。比如BaseMapper接口替你把save、updateById、selectPage全都实现了,你只需要在XML里写多表联查或复杂的统计SQL。很多人一开始习惯手写所有SQL,用上MyBatis-Plus后,单表操作全部走内置方法,代码量至少减三分之一。

登录功能的实现逻辑,我建议把重点放在异常分支判定上:

  1. 用户不存在,返回“用户名或密码错误”
  2. 密码校验失败(用BCryptPasswordEncoder的matches方法比对),返回同一句提示,避免暴露用户是否存在
  3. 用户被禁用(status=0),提示“账号已禁用,请联系管理员”

JWT拦截器的实现方式是写一个Interceptor,实现HandlerInterceptor接口。preHandle方法里从request的Header中取Authorization,去掉Bearer前缀,解析token,把uid和角色信息塞进ThreadLocal,供后续controller取用。这个做法会引入一个问题:并发请求时ThreadLocal在线程池环境下可能串数据,但单体应用里的请求量完全不至于触发这个场景,不用过度设计。

3.2 前端工程搭建与页面环境

前端工程采用Vue3 + Vite + Element Plus组合。很多人可能还在Vue2+webpack的老路子上跑,如果是从头开始做,强烈建议直接用Vue3,生态已经非常稳定。Vite的冷启动和热更新速度比webpack快一个量级,开发体验好太多。

前端目录组织按类型划分,简单明了:

src/ |-- api/ # 按模块拆分的接口调用文件 |-- assets/ # 静态资源 |-- components/ # 通用组件 |-- layout/ # 布局组件(侧边栏+头部+内容区) |-- router/ # 路由配置,含动态路由逻辑 |-- store/ # Pinia状态管理 |-- views/ # 页面组件 |-- utils/ # 工具函数(request封装等)

Axios的二次封装,是每个前端项目都要认真处理的一环。我的做法是:axios实例设置baseURL为/api,请求拦截器里加上token,响应拦截器里统一处理code非200的情况。401统一用窗口提示跳转登录页,其他错误用Element Plus的Message组件直接弹出后端返回的message字段,不用每个页面把错误处理写一遍。

路由守卫的设计分两层。第一层判断是否存在token,无token一律踢回登录页;第二层通过路由meta里的roles字段判断当前用户角色是否具备访问权限,比如/admin下的所有子路由都要求role为管理员或教师。实际开发中,前端守卫只能当作体验优化,后端接口仍要执行角色校验,不能只靠前端藏页面。

活动列表页是流量最大的页面。我的实现思路是:筛选区放分类下拉框和关键词搜索框,主体用el-card卡片列表展示活动信息,卡片下方放报名状态按钮,按钮禁用条件由后端返回的signupStatus和剩余名额共同决定。分页用el-pagination,每次切换页码时携带筛选参数重新拉取接口。

管理端页面尽量使用表格和弹窗的组合:表格里展示字段信息,操作列使用el-button切换不同状态,编辑用el-dialog放表单。不要用复杂的级联组件和自定义模板,管理系统的核心是快、准、稳,不是炫技。

3.3 核心业务代码实现拆解

报名流程的后端控制逻辑,是我觉得全项目最有含金量的一环。报名接口的伪逻辑如下:

@PostMapping("/signup") public Result signup(@RequestBody SignupRequest req, @RequestAttribute Long userId) { Activity activity = activityMapper.selectById(req.getActivityId()); if (activity == null) { return Result.error("活动不存在"); } if (activity.getStatus() != 2) { return Result.error("活动不在报名阶段"); } if (LocalDateTime.now().isAfter(activity.getSignupDeadline())) { return Result.error("报名已截止"); } if (activity.getSignupCount() >= activity.getCapacity()) { return Result.error("名额已满"); } // 检查是否重复报名 Integer count = signupMapper.selectCount(new LambdaQueryWrapper<ActivitySignup>() .eq(ActivitySignup::getActivityId, req.getActivityId()) .eq(ActivitySignup::getUserId, userId) .in(ActivitySignup::getStatus, Arrays.asList(0, 2))); if (count > 0) { return Result.error("您已报名或已签到,无需重复操作"); } // 写入报名记录 + 更新活动报名数 signupMapper.insert(signup); activity.setSignupCount(activity.getSignupCount() + 1); activityMapper.updateById(activity); return Result.success(); }

这里有几个细节容易踩坑。第一,activity状态字段的判断条件写清楚,我定义的2是“审核通过”状态,只有审核通过的活动才允许报名。草稿和已驳回状态的活动,前端虽然不发按钮,后端也要兜底。第二,判断是否重复报名时,注意status集合要包含“已报名(0)”和“已签到(2)”,因为签到状态本质上也占了名额。已经取消(1)和已完成(3)的用户,可以重新报名——这个逻辑要明确,不同需求下可能不同,但在支持重复报名的系统里,Status集合写错了就会出大Bug。

活动审核的流程,在管理端是一个很直观的状态机。教师提交活动之后,活动状态变为1(待审核),管理员在列表中看到待审核的活动,可以点击通过或驳回。驳回时要求填写原因,原因展示在教师端的活动详情页里。这个设计虽然简单,但非常符合校园管理的真实需求——社团自主发布活动,但校方有最终审核权。

统计模块的实现方式,我推荐用SQL聚合而不是把所有数据拉到内存里再算。SQL里写GROUP BY, 再配合几个简单的子查询,效率和可读性都很好:

SELECT category.name AS category_name, COUNT(a.id) AS activity_count FROM activity a LEFT JOIN activity_category category ON a.category_id = category.id WHERE a.status IN (2, 4) GROUP BY category.name

统计的同时要考虑未来扩展的空间。比如现在只做数据概览,后续如果要做“用户参与排行”或者“部门活跃度分析”,SQL这边已经预留了user_id、creator_id等维度字段,扩展时不需要动表结构,只需要加查询逻辑。

Excel导出功能是比较容易被忽略、但实际使用频率非常高的功能。我用的方案是EasyExcel(阿里巴巴开源组件)。核心逻辑是定义实体类,加@ExcelProperty注解指定列名,然后一行代码完成导出:

response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); String fileName = URLEncoder.encode("报名名单", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); EasyExcel.write(response.getOutputStream(), SignupExportVO.class).sheet("报名名单").doWrite(dataList);

导出这里最容易遇到的问题是两个:一是response头设置不对导致下载的文件打不开,二是中文字段导出乱码。第二点用URLEncoder中转一下即可解决。

3.4 源码、文档与部署包的配套价值

这套系统附带的内容,除了完整前后端源码之外,还包括一套从零开始的说明文档和部署视频。说明文档的价值不在于代码注释多详细,而在于把整个业务流程讲顺。文档目录我建议这样组织:系统概述、技术架构、环境准备、数据库初始化、后端启动步骤、前端启动步骤、部署上线、常见问题。整套文档的核心读者是“拿到代码但没跑过类似项目”的同学,所以每一步都要写得足够傻瓜化。

数据库脚本里除了库表和测试数据,还写了三个角色各一个测试账号,方便登录后直接体验三种角色视角。部署视频主要针对“本地能跑但不知道怎么办到服务器上”的人,从购买服务器、装环境、上传代码、打包、配置Nginx反向代理,一路操作到底。

讲解视频这块,我认为重点不是一行一行念代码,而是讲系统设计思路。比如为什么报名状态要设计成五档、为什么JWT要设置过期时间、为什么数据表之间不用建物理外键。只有把这些设计思路讲透了,答辩的时候面对提问才不会慌。

4. 部署上线流程与常见问题排查

4.1 本地启动的完整步骤

拿到源码后在本地把项目跑起来,大概需要走这几个步骤:

  1. 创建数据库activity_db,执行项目里sql目录下的初始化脚本
  2. 改application.yml里的数据库用户名和密码
  3. 命令行或IDE里启动SpringBoot主类
  4. 前端目录下执行npm install,安装依赖
  5. npm run dev启动开发服务,访问localhost:5173(Vite默认端口)

整个流程中,最容易卡住的步骤是npm install。网速慢或者node版本太旧,都会导致依赖装不干净。建议使用pnpm或者cnpm替代默认的npm源。如果node_modules实在装不上,还有一个笨办法:直接在package.json里把依赖版本换低,比如vue-router从4换成3、vuex换回pinia,不过这种方式不推荐,越换越乱。

如果本地已经装了其他项目用的MySQL,要和现有配置对齐端口和密码,避免写死连接信息导致启动失败。

4.2 服务器部署方案实战

生产环境的部署思路,我倾向于“前端静态文件 + Nginx反向代理 + 后端jar包”的组合。这是SpringBoot+Vue项目最常见的部署形态,成本低、稳定性有保障。

  1. 后端在项目根目录下执行mvn clean package,在target目录下面找到jar包
  2. 将jar包上传到服务器的指定目录,例如/opt/activity
  3. 使用挂后台的方式启动:nohup java -jar activity-system.jar > app.log 2>&1 &
  4. 前端执行npm run build,将dist目录上传到nginx的web目录
  5. 配置Nginx:普通请求代理到静态目录,/api开头的请求反代到后端端口

Nginx配置的核心片段:

server { listen 80; server_name your-domain.com; root /opt/activity/dist; index index.html; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location / { try_files $uri $uri/ /index.html; } }

这里最关键的一行是try_files $uri $uri/ /index.html;。如果缺少它,前端路由跳转到/activity/3这种深链时,刷新页面会直接404——因为Nginx找不到对应的静态文件。这是前后端分离项目部署中最经典的坑,每个新手都会遇到。

4.3 常见问题排查速查表

跑项目过程中遇到的报错,大部分都是重复出现的。

现象可能原因解决办法
后端启动报数据库连接失败数据库账号密码不对、驱动版本不匹配核对application.yml配置和pom.xml里的mysql驱动版本
前端npm run dev启动报错Node版本过高或过低切换Node 14/16长期支持版本
登录接口能通,列表接口401token未携带或已过期前端检查request拦截器里是否加Authorization,重新登录
前端请求接口CORS报错后端未配置跨域生产环境用Nginx反向代理同域解决,开发环境后端开启CORS配置
接口返回500,控制台打印SQL异常字段名不对或数据类型不一致打开MyBatis的日志输出,看控制台打印的SQL,逐字段排查
打包后的前端页面刷新404Nginx未配置try_files按上文Nginx配置片段补上
Excel导出文件名乱码编码设置不对使用上面示例中的URLEncoder处理
8080端口被占用本机其他应用占用了端口改server.port或找到占用进程杀掉

每个问题的解决办法,其实都可以在文档的“常见问题”章节里找到对应的操作步骤。我给学生的建议是遇到报错千万别急着查AI或者去论坛发帖,先把控制台最后一段错误日志读完,大部分问题根本不需要问别人。

5. 从个人项目延展到移动端场景

基本上做完Java+SpringBoot+Vue这一套,这个项目已经是一个非常完整的课设或者毕设答辩作品。但如果你想拿它套一个“校园微应用”或“移动端适配”的壳,也同样有合理的延展方案,这也是我在给一些同学做扩展思路讲解时经常提到的方向。

思路一:给现有后端加移动端专用接口。前端项目不变,新增一个接口模块,比如微信小程序的登录方式改成openid换token,列表返回改成更简洁的分页结构。后端结构不需要改,只要在controller里加一套/api/mobile前缀的接口即可。安卓端同理,逻辑层复用,只需要重写一套前端页面。

思路二:把数据统计部分扩展成大屏展示。由于后端统计接口已经是聚合查询,前端页面可以换成ECharts的图表组件,把活动类型占比、每月报名趋势、学院参与排行等做成长图或大屏看板,在展示效果上会非常加分。

思路三:在报名模块上扩展活动反馈与学分/综评体系。这个功能要做,重点是在活动表和报名表上各加几个字段,以及新增一个评价相关的逻辑。在这个基础上做学分累积或评优展示也是顺理成章的。

总的来看,这类系统的技术核心并不复杂,但它的价值在于业务流程闭环:从活动产生、审核、发布、报名、签到到统计,每一步都有据可查。掌握了这个闭环的开发逻辑,未来做一个会议室预约系统、社团管理系统、培训报名平台,无非是换一层外衣。

我在实际完成这个项目的过程中体会最深的一点是:开发前花两小时把数据表关系和状态流转图画清楚,比开发中遇到Bug再回头改表要高效太多。代码写错了可以断点调试,数据库设计错了就要连带前端、接口、测试全部重来。如果你也是从零开始做类似管理系统,建议别急着敲代码,先拿纸笔把角色、流程、权限画一遍,再动手,整个开发体验会顺畅很多。

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

降AI指令实战:大模型调优让论文从机器味变成真人味

1. 为什么论文一出来就一股AI味你要的“大模型调优”&#xff0c;并不是把提示词写得多华丽&#xff0c;而是先理解一件事&#xff1a;机器味不是语法错误&#xff0c;是一种“平均脸”。单看每一句都没毛病&#xff0c;甚至找不到一个错别字&#xff0c;但连成段之后&#xff…

作者头像 李华
网站建设 2026/10/18 9:53:10

Java工程师的Agent工程化实战路径:24周从Spring到智能体系统

1. 这不是转行&#xff0c;是能力栈的结构性升级&#xff1a;一个Java老手的真实Agent工程化路径“Java工程师转型Agent Engineer”这个标题最近在技术社区刷屏&#xff0c;但很多人第一反应是&#xff1a;又一个蹭热点的噱头&#xff1f;我干了十二年Java后端&#xff0c;从Sp…

作者头像 李华
网站建设 2026/10/18 9:52:40

AI Agent核心模块拆解:从聊天机器人到数字员工的落地指南

开篇先聊一个现象&#xff1a;很多人做了大半年对话机器人&#xff0c;发现把模型 API 接上、套一层 Prompt、再挂个前端&#xff0c;得到的顶多是一个“即问即答的嘴巴”。它不会主动查数据、不会跨系统办手续、不会在流程跑偏时拉回来&#xff0c;更不会把一次复杂任务拆成若…

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

Linux常用命令实战指南:从文件操作到系统运维的高频用法

说真的&#xff0c;在图形界面越来越友好的今天&#xff0c;还有人愿意静下心来把玩 Linux 命令&#xff0c;本身就是件挺难得的事。前阵子帮一位刚入行的小兄弟梳理工作流&#xff0c;他问了我一句&#xff1a;“这些东西网上随手一搜就有&#xff0c;为什么还要系统学一遍&am…

作者头像 李华
网站建设 2026/10/18 9:50:43

本地部署视频分析工作流:抽帧、目标检测、OCR与API服务实战

视频分析是一个比“跑通一个模型”更完整的工程场景&#xff1a;要抽帧、要检测、要识别文字、要批量处理长视频&#xff0c;最后还要把结果落到结构化的位置。很多开源项目单看 demo 很漂亮&#xff0c;一上真实视频就暴露问题。这次我们直接从本地部署视角&#xff0c;整理一…

作者头像 李华
网站建设 2026/10/18 9:50:12

实时人脸表情识别系统实战:TensorFlow+OpenCV+PyQt5完整实现

人脸表情识别这个方向&#xff0c;网上资料其实不少&#xff0c;但绝大多数止步于模型训练完、拿到一个准确率数字就结束了。这次我把整个流程做完整&#xff1a;模型训练、摄像头实时捕获、表情分类结果可视化、GUI界面交互&#xff0c;全部串在一起&#xff0c;做成一个「实时…

作者头像 李华