SpringBoot+Vue+AI大模型:智慧校园新生报到系统设计与实现

发布时间:2026/9/1 5:42:46
SpringBoot+Vue+AI大模型:智慧校园新生报到系统设计与实现 市面上校园管理系统类的毕业设计一抓一大把。从“学生信息管理”到“课程表查询”技术栈清一色 SpringBoot Vue MySQL页面千篇一律功能大同小异。说实话这类题目放在三年前还能让人眼前一亮放到今天如果没有一点差异化的东西答辩时老师问一句“你的系统相比普通管理系统创新点在哪里”很容易陷入被动。这篇文章要聊的就是如何在一个经典的校园业务系统之上引入 AI 大模型能力做一个“会对话、能引导、主动服务”的新生报到系统。它不是那种花架子而是在真实业务场景里用大模型把“寻路、问答、报到流程提醒、在线咨询”这些学生高频需求接住。项目技术栈仍然是 SpringBoot Vue MySQL但多了一层 AI 能力的接入。读完这篇文章你能得到几条切实可用的东西一个完整的智慧校园新生报到系统功能规划与表结构设计思路SpringBoot 后端如何设计 RESTful 接口如何对接 AI 大模型而不是把模型调用散落在各个业务代码里Vue 前端如何实现报到引导页面和 AI 对话组件在毕业设计或实际项目中AI 功能怎么做得有说服力而不是生硬地塞一个“智能问答”按钮。整体来看这篇文章的核心判断是AI 大模型在校园系统里的价值不在于生成一段漂亮的文案而在于把“信息查找”升级为“服务办理”。新生不需要在一堆菜单里找“宿舍分配在哪”“体检几点排队”直接问一句就能得到答案这才是“智慧校园”体验上的关键跃迁。1. 系统定位与核心问题拆解1.1 为什么选择新生报到这个场景新生报到是高校教务和学工系统里最混乱的几天之一。对于学校来说涉及教务处、宿管中心、财务处、校医院、院系辅导员多个部门对于学生来说要在短时间内完成信息核验、缴费确认、宿舍分配、校园卡领取、体检预约等一堆流程。传统做法是学校在官网发布一份 PDF 报到指南然后学生自己对着流程跑遇到问题就找志愿者或者去现场咨询台排队。这个场景非常适合做成系统原因也很直接流程相对固定角色清晰数据边界明确而且 AI 能力有天然的落地空间。新生的问题高度集中比如“学费在哪里交”“宿舍在哪里查”“报到需要带什么材料”“体检几点结束”。这些问题的背后是结构化程度极高的业务数据。把这些问题交给大模型去理解再通过后端接口去查询真实数据就比做一个“关键字搜索”或者“规则匹配”体验好很多。1.2 系统要解决的三个核心问题第一个问题是信息分散。学校各职能部门的数据口径不统一学生和辅导员缺少一个集中入口。系统至少需要把学生信息、报到批次、缴费记录、宿舍分配、体检状态这些数据整合到同一个平台。第二个问题是流程引导不智能。很多校园系统的“报到功能”只是记录一个状态比如学生点击“确认报到”按钮系统存一下时间就结束了。但这没有解决“下一步该做什么”的问题。一个完善的报到系统应该能根据学生当前状态自动计算并提示他下一步怎么做比如“你的学费已缴清还需要完成宿舍确认”。第三个问题是咨询问题重复度高。新生群和咨询台每天要回答大量重复问题。用传统关键词检索做 FAQ 效果一般因为学生的提问方式太口语化了。而大模型对于口语化表达的理解能力天然适合做这种非结构化问题到结构化业务信息的转换。1.3 目标用户与角色划分系统面向的角色很清晰这里要提前定义好后面做权限设计和功能拆分才能不乱。角色核心诉求主要操作新生快速完成报到少跑冤枉路查看报到流程、填写信息、查询宿舍、向 AI 提问辅导员掌握本学院报到进度审核学生信息、查看报到统计、处理异常管理员维护基础数据与系统配置管理院系、专业、班级、楼栋、管理员账号AI 助手理解自然语言返回业务数据解答常见问题查询报到状态引导流程2. 技术选型与架构设计2.1 后端为什么选 SpringBoot对于校园管理类系统SpringBoot 依然是这个阶段最稳的选择。原因不是“大家都用它”而是它解决的实际问题足够多。新生报到系统的核心业务是增删改查、流程状态流转、文件上传、权限管理这些在 Spring Boot 里都有非常成熟的生态支撑。更重要的是SpringBoot 的自动装配机制可以帮助团队减少大量配置代码让开发者把精力集中在业务逻辑上。还有一个很现实的因素很多高校的服务器环境比较保守技术栈越主流越容易部署出问题也越容易找到资料。如果选一个比较小众的框架虽然在技术上显得“新”但从交付稳定性来看不一定划算。版本方面本文示例以 Spring Boot 2.7.x 为主Java 8 或 Java 11 都可以运行如果团队想用 Spring Boot 3.x需要注意 javax 到 jakarta 命名空间的迁移这个后面会提到。2.2 前端为什么选 Vue 而不是小程序虽然很多毕业设计标题里习惯带“微信小程序”但本文的场景用 Vue 做 Web 端管理平台原因在于系统需要同时服务新生和校内管理人员。新生在报到现场要快速打开页面直接用手机浏览器访问一个响应式页面比先扫码进入小程序、再授权登录要快得多。而管理员端需要处理大量表格和统计信息在 PC 浏览器上操作更高效。此外Vue 配合 Element UI 组件库能在较短时间内构建出界面规整的管理后台这对工期有限的毕业设计或课程项目非常重要。考虑到“多端展示”在答辩时是一个加分项也可以在小程序里做一个轻量版查询入口。但核心业务能力不要放在小程序里因为涉及账号绑定、审核、发布流程周期较长。正确的做法是Web 端负责完整业务小程序端做一个信息查询和 AI 问答的精简入口。2.3 整体架构分层从部署角度看系统按经典的前后端分离架构拆分浏览器Vue3 Element Plus ↓ HTTP/JSON Spring Boot 后端Controller / Service / Mapper ↓ MySQL 数据库业务数据 ↓ AI 大模型接口HTTP 调用用于意图识别与问答生成整个系统被划分为前端展示层、后端接口层、业务服务层、数据存储层、外部 AI 能力层。这样的分层带来的好处是AI 功能被隔离在独立的 Service 中不影响核心报到流程。如果大模型接口不可用报到的核心链路仍然可以正常运转这是生产级系统必须考虑的容错设计。3. 数据库设计3.1 核心表结构规划新生报到系统涉及的数据实体不算复杂但关联关系较多。这里给出一个可落地的核心表设计覆盖学生、院系、专业、班级、宿舍、报到记录、咨询记录等实体。-- 文件路径sql/schema.sql CREATE DATABASE IF NOT EXISTS campus_checkin DEFAULT CHARACTER SET utf8mb4; USE campus_checkin; -- 院系表 CREATE TABLE tbl_department ( id BIGINT PRIMARY KEY AUTO_INCREMENT, dept_name VARCHAR(100) NOT NULL COMMENT 院系名称, dept_code VARCHAR(50) NOT NULL UNIQUE COMMENT 院系编码, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) COMMENT院系表; -- 专业表 CREATE TABLE tbl_major ( id BIGINT PRIMARY KEY AUTO_INCREMENT, major_name VARCHAR(100) NOT NULL COMMENT 专业名称, major_code VARCHAR(50) NOT NULL UNIQUE COMMENT 专业编码, dept_id BIGINT NOT NULL COMMENT 所属院系ID ) COMMENT专业表; -- 班级表 CREATE TABLE tbl_class ( id BIGINT PRIMARY KEY AUTO_INCREMENT, class_name VARCHAR(100) NOT NULL COMMENT 班级名称, class_code VARCHAR(50) NOT NULL UNIQUE COMMENT 班级编码, major_id BIGINT NOT NULL COMMENT 所属专业ID ) COMMENT班级表; -- 宿舍楼栋表 CREATE TABLE tbl_dormitory ( id BIGINT PRIMARY KEY AUTO_INCREMENT, dorm_name VARCHAR(100) NOT NULL COMMENT 楼栋名称, dorm_address VARCHAR(255) COMMENT 楼栋位置, total_beds INT DEFAULT 0 COMMENT 总床位数, used_beds INT DEFAULT 0 COMMENT 已用床位数 ) COMMENT宿舍楼栋表; -- 学生表 CREATE TABLE tbl_student ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(50) NOT NULL UNIQUE COMMENT 学号, student_name VARCHAR(50) NOT NULL COMMENT 姓名, gender TINYINT DEFAULT 1 COMMENT 性别 1男 2女, id_card VARCHAR(30) COMMENT 身份证号, phone VARCHAR(20) COMMENT 手机号, dept_id BIGINT NOT NULL COMMENT 院系ID, major_id BIGINT NOT NULL COMMENT 专业ID, class_id BIGINT NOT NULL COMMENT 班级ID, dorm_id BIGINT COMMENT 宿舍楼栋ID, room_no VARCHAR(20) COMMENT 房间号, status TINYINT DEFAULT 0 COMMENT 报到状态 0未报到 1已报到, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) COMMENT学生表; -- 缴费记录表 CREATE TABLE tbl_payment ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL COMMENT 学生ID, amount DECIMAL(10,2) NOT NULL COMMENT 缴费金额, pay_status TINYINT DEFAULT 0 COMMENT 缴费状态 0未缴 1已缴, pay_time DATETIME COMMENT 缴费时间, remark VARCHAR(255) COMMENT 备注 ) COMMENT缴费记录表; -- 报到记录表 CREATE TABLE tbl_checkin_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL COMMENT 学生ID, step_code VARCHAR(50) NOT NULL COMMENT 步骤编码, step_name VARCHAR(100) NOT NULL COMMENT 步骤名称, status TINYINT DEFAULT 0 COMMENT 步骤状态 0未完成 1已完成, finish_time DATETIME COMMENT 完成时间 ) COMMENT报到步骤记录表; -- 咨询记录表 CREATE TABLE tbl_consult ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL COMMENT 学生ID, question TEXT NOT NULL COMMENT 用户提问, answer TEXT COMMENT AI回答, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) COMMENTAI咨询记录表;这里特别说明两点。第一点报到状态不只在学生表里用一个字段标识还通过tbl_checkin_record记录每个流程步骤的完成情况。这样设计的好处是可以很清楚地看到“这个学生卡在哪个环节”对辅导员做线下干预非常有帮助。第二点设计tbl_consult表来保存大模型的问答记录不要小看这张表。它不仅是业务留痕也是后续做模型效果分析的数据基础。比如如果大量学生问“宿舍怎么走”说明系统缺少宿舍导航功能如果问“学费能退吗”说明财务相关规则展示得不够清楚。这些分析对系统迭代非常有价值。3.2 索引与数据一致性设计查询频率最高的场景是“根据学号查报到状态”和“根据学生ID查步骤进度”所以tbl_student.student_no需要唯一索引tbl_checkin_record.student_id需要普通索引。缴费记录与学生表建议在应用层保证一致性不推荐在数据库层面做跨表事务因为校园网环境下的真实支付往往对接第三方平台支付结果的确认依赖回调而不是本地事务。这一点在答辩时如果被问到可以明确解释。4. SpringBoot 后端核心实现4.1 项目初始化与依赖引入创建一个 Spring Boot 项目核心依赖包括Spring Web、MyBatis-Plus、MySQL Driver、Lombok。如果对接 AI 模型建议使用OkHttp或Spring RestTemplate作为 HTTP 客户端。下面给出pom.xml的关键依赖。!-- 文件路径pom.xml -- dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.8.18/version /dependency /dependencies这里使用 MyBatis-Plus 而不使用原生 MyBatis主要考虑到项目中的 CRUD 操作占比较高。MyBatis-Plus 提供的 BaseMapper 可以省去大量 XML 编写同时保留自定义 SQL 的能力适合快速交付。application.yml里配置好数据源信息和 MyBatis-Plus 的日志输出# 文件路径src/main/resources/application.yml server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/campus_checkin?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: root servlet: multipart: max-file-size: 20MB mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 04.2 登录鉴权与 JWT 设计校园系统不需要像互联网产品那样做复杂的 OAuth 授权但必要的登录鉴权不能省。推荐使用 JWT 做无状态登录实现简单也方便在答辩时讲清楚“无状态扩展”的价值。先定义一个 JWT 工具类负责生成和解析 Token// 文件路径src/main/java/com/campus/util/JwtUtil.java package com.campus.util; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.util.Date; import java.util.HashMap; import java.util.Map; public class JwtUtil { private static final String SECRET campus-checkin-secret-key; private static final long EXPIRE_TIME 24 * 60 * 60 * 1000; public static String generateToken(Long userId, String role) { MapString, Object claims new HashMap(); claims.put(userId, userId); claims.put(role, role); Date now new Date(); Date expireDate new Date(now.getTime() EXPIRE_TIME); return Jwts.builder() .setClaims(claims) .setIssuedAt(now) .setExpiration(expireDate) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); } public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token) .getBody(); } }实际生产环境中SECRET 不能硬编码在代码里应该放到配置中心或环境变量。毕业设计项目可以把细节写进论文但代码里尽量做到“看起来知道如何改进”。在此基础上可以写一个简单的拦截器来校验登录状态。这里不再展开完整拦截器代码但在章节 7 的常见问题里会说明如果漏掉拦截器会有什么后果。4.3 AI 大模型服务封装从架构上看AI 能力应该被封装成一个独立的 Service让 Controller 层不直接感知模型调用的细节。先定义一个大模型接口的响应对象再写一个AiChatService统一处理请求参数和结果解析。假设我们对接的是 OpenAI 兼容格式的 HTTP 接口比如国内很多大模型平台都提供/chat/completions风格接口。核心代码如下// 文件路径src/main/java/com/campus/service/AiChatService.java package com.campus.service; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; Service public class AiChatService { Value(${ai.api-url}) private String apiUrl; Value(${ai.api-key}) private String apiKey; Value(${ai.model-name}) private String modelName; public String chat(String systemPrompt, String userContent) { JSONObject payload new JSONObject(); payload.set(model, modelName); JSONArray messages new JSONArray(); JSONObject systemMessage new JSONObject(); systemMessage.set(role, system); systemMessage.set(content, systemPrompt); messages.add(systemMessage); JSONObject userMessage new JSONObject(); userMessage.set(role, user); userMessage.set(content, userContent); messages.add(userMessage); payload.set(messages, messages); payload.set(temperature, 0.3); HttpResponse response HttpRequest.post(apiUrl) .header(Authorization, Bearer apiKey) .header(Content-Type, application/json) .body(payload.toString()) .timeout(15000) .execute(); if (response.getStatus() ! 200) { return 抱歉AI 服务暂时不可用请稍后再试。; } JSONObject result JSONUtil.parseObj(response.body()); JSONArray choices result.getJSONArray(choices); if (choices null || choices.isEmpty()) { return 抱歉AI 服务返回结果异常。; } return choices.getJSONObject(0) .getJSONObject(message) .getStr(content); } }这里用 Hutool 的 HTTP 工具类完成请求主要是为了减少代码量。temperature设置成 0.3让模型尽量输出确定的答案而不是发散性的文本。对于业务咨询场景低温度更合适。这里的ai.api-url、ai.api-key、ai.model-name需要配置在application.yml中。4.4 结合业务数据的 AI 提示词设计这是整个系统里最有技术含量的部分也是很多项目做得不到位的地方只不过是用大模型举例并没有真正把业务数据接入进去。如果你只是把学生问题直接转发给大模型它回答的都是“通用常识”对校园系统没有意义。正确的做法是设计一个系统提示词让模型知道它的身份是“校园新生报到助手”同时在每次用户提问之前把“上下文数据”拼接进去。比如学生问“我宿舍在哪里”模型并不知道这个学生的宿舍在哪因此系统要先根据登录态拿到学生的宿舍信息再带着这个数据去问模型。更聪明的做法是两步走第一步用模型做“意图识别”判断学生想问什么第二步根据意图去数据库查询结果把查询结果交给模型生成回答。示意代码如下// 文件路径src/main/java/com/campus/service/ConsultService.java package com.campus.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.campus.entity.Student; import com.campus.entity.Dormitory; import com.campus.mapper.StudentMapper; import com.campus.mapper.DormitoryMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; Service public class ConsultService { Autowired private StudentMapper studentMapper; Autowired private DormitoryMapper dormitoryMapper; Autowired private AiChatService aiChatService; public String handleQuestion(Long studentId, String question) { Student student studentMapper.selectById(studentId); StringBuilder systemPrompt new StringBuilder(); systemPrompt.append(你是校园新生报到智能助手。请根据以下学生信息和业务上下文); systemPrompt.append(用简洁、友好的中文回答用户问题。如果问题涉及数据查询请优先使用下方提供的数据。); systemPrompt.append(如果数据中没有相关信息请如实回答“数据暂未更新”或“请联系辅导员”。\n\n); // 拼接业务上下文 systemPrompt.append(【学生信息】\n); systemPrompt.append(姓名).append(student.getStudentName()).append(\n); systemPrompt.append(学号).append(student.getStudentNo()).append(\n); systemPrompt.append(院系ID).append(student.getDeptId()).append(\n); systemPrompt.append(专业ID).append(student.getMajorId()).append(\n); systemPrompt.append(报到状态).append(student.getStatus() 1 ? 已报到 : 未报到).append(\n); // 查宿舍信息 if (student.getDormId() ! null) { Dormitory dorm dormitoryMapper.selectById(student.getDormId()); systemPrompt.append(【宿舍信息】\n); systemPrompt.append(楼栋).append(dorm.getDormName()).append(\n); systemPrompt.append(房间号).append(student.getRoomNo()).append(\n); } // 查缴费状态 QueryWrapperPayment paymentWrapper new QueryWrapper(); paymentWrapper.eq(student_id, studentId); paymentWrapper.orderByDesc(id).last(limit 1); Payment payment paymentMapper.selectOne(paymentWrapper); if (payment ! null) { systemPrompt.append(【缴费状态】\n); systemPrompt.append(payment.getPayStatus() 1 ? 已缴费 : 未缴费).append(\n); } return aiChatService.chat(systemPrompt.toString(), question); } }这种“先查数据再让模型组织语言”的方式比单纯让模型自由发挥要可靠得多。它把大模型定位成“表达层”不承担数据真实性的责任数据真实性由后端数据库保障。这也是当前大模型应用开发中一个重要的设计模式业务数据不可由模型编造模型只负责理解意图、组织输出、提升对话体验。4.5 报到流程接口设计报到流程的接口设计建议按照资源维度拆分为学生端和管理端两套。学生端核心接口方法路径功能POST/api/auth/login学生登录返回 JWTGET/api/student/checkin-status查询当前学生的所有报到步骤状态POST/api/student/checkin/{stepCode}完成指定报到步骤GET/api/student/dormitory查询当前学生的宿舍分配信息POST/api/consult/ask向 AI 助手提问报到步骤的完成接口需要在后端做防重复提交处理。使用 Redis 或数据库乐观锁都可以这里给出一个基于状态校验的简单版本// 文件路径src/main/java/com/campus/controller/StudentCheckinController.java package com.campus.controller; import com.campus.common.Result; import com.campus.entity.CheckinRecord; import com.campus.service.CheckinService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/api/student) public class StudentCheckinController { Autowired private CheckinService checkinService; GetMapping(/checkin-status) public Result getCheckinStatus(RequestAttribute(userId) Long userId) { return Result.success(checkinService.getCheckinStatus(userId)); } PostMapping(/checkin/{stepCode}) public Result finishStep(RequestAttribute(userId) Long userId, PathVariable(stepCode) String stepCode) { checkinService.finishStep(userId, stepCode); return Result.success(); } }在业务层finishStep要做三件事第一步校验该步骤是否已经完成如果完成则直接返回第二步更新tbl_checkin_record的步骤状态第三步判断所有步骤是否都已完成如果完成则把tbl_student.status置为 1。这三步中第一步和第二步之间可能存在并发问题但校园报到场景的峰值并发远没有达到需要分布式锁的程度数据库唯一索引加上状态校验足以应对。5. Vue 前端核心实现5.1 项目初始化与路由设计前端基于 Vue 3 Vite Element Plus 构建。使用npm create vitelatest创建项目后安装依赖npm install vue-router4 axios element-plus element-plus/icons-vue路由设计分为两个区域/register是新生报到首页展示报到流程和 AI 对话入口/admin是管理后台包含学生管理、报到统计、数据概览。// 文件路径src/router/index.js import { createRouter, createWebHistory } from vue-router const routes [ { path: /, redirect: /checkin }, { path: /checkin, name: Checkin, component: () import(../views/CheckinView.vue), meta: { requiresAuth: true } }, { path: /login, name: Login, component: () import(../views/LoginView.vue) }, { path: /admin, name: Admin, component: () import(../views/admin/AdminLayout.vue), meta: { requiresAuth: true, role: admin }, children: [ { path: students, component: () import(../views/admin/StudentManage.vue) }, { path: statistics, component: () import(../views/admin/CheckinStatistics.vue) } ] } ] const router createRouter({ history: createWebHistory(), routes }) router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.meta.requiresAuth !token) { next(/login) } else { next() } }) export default router5.2 报到进度页面报到进度页的核心逻辑很简单从后端拿到当前学生的步骤列表用 Element Plus 的Steps组件展示。关键代码!-- 文件路径src/views/CheckinView.vue -- template div classcheckin-container el-card classwelcome-card h2欢迎你{{ studentInfo.studentName }}/h2 p你的学号{{ studentInfo.studentNo }}/p p所在班级{{ studentInfo.className }}/p /el-card el-card classprocess-card template #header报到流程/template el-steps directionvertical :activeactiveStep el-step v-forstep in checkinSteps :keystep.stepCode :titlestep.stepName :descriptionstep.description / /el-steps /el-card AiChatPanel :student-idstudentInfo.id / /div /templateAI 对话面板单独封装成一个组件方便在不同页面复用。对话面板的核心要点是用户每问一个问题把后端返回的答案追加到消息列表并保存到本地状态里。下面是组件代码的骨架!-- 文件路径src/components/AiChatPanel.vue -- template el-card classai-chat template #header校园智能助手/template div classchat-messages refmessageBox div v-for(msg, index) in messages :keyindex :class[chat-msg, msg.role] span{{ msg.content }}/span /div /div div classchat-input el-input v-modelinputText placeholder例如我的宿舍在哪里 keyup.entersendMessage / el-button typeprimary clicksendMessage发送/el-button /div /el-card /template script setup import { ref, nextTick } from vue import axios from axios const props defineProps({ studentId: { type: Number, required: true } }) const messages ref([ { role: ai, content: 你好我是校园智能助手。你可以问我报到流程、宿舍信息、缴费状态等问题。 } ]) const inputText ref() const messageBox ref(null) async function sendMessage() { const question inputText.value.trim() if (!question) return messages.value.push({ role: user, content: question }) inputText.value try { const res await axios.post(/api/consult/ask, { question }) messages.value.push({ role: ai, content: res.data.data }) } catch (e) { messages.value.push({ role: ai, content: AI 服务暂时不可用请稍后再试。 }) } nextTick(() { messageBox.value.scrollTop messageBox.value.scrollHeight }) } /script style scoped .chat-messages { height: 400px; overflow-y: auto; border: 1px solid #eee; padding: 12px; margin-bottom: 12px; } .chat-msg { margin-bottom: 10px; } .chat-msg.user { text-align: right; } .chat-msg.ai { text-align: left; } /style这里需要强调的是前端展示 AI 回答时建议做一个markdown渲染因为大模型的回答往往包含列表、加粗等格式直接以纯文本展示体验会差一些。可以用markdown-it这样的小工具库来做渲染。5.3 管理端数据看板管理端的价值在于让辅导员和管理员实时掌握报到进度。页面核心包括总报到人数、各院系报到率、按小时统计的报到趋势、未报到学生列表。这些数据全部来自后端聚合接口前端只负责图表展示。图表建议使用 ECharts它对于柱状图、折线图、饼图的支持非常成熟而且很容易接入 Vue。npm install echarts如果是毕业设计答辩建议在统计页面中做一个“报到率 TOP5 院系”横向柱状图同时在旁边标注“报到率最低的院系”名单。这个组合非常容易成为答辩时的讨论点也体现你对业务数据的理解。6. 项目部署与运行验证6.1 后端启动确保本机已安装 JDK 8 和 Maven 3.6并已创建好数据库campus_checkin执行sql/schema.sql完成建表。然后执行cd campus-checkin-server mvn spring-boot:run启动成功后控制台会输出 Spring Boot 的启动日志和端口号。可以测试登录接口curl -X POST http://localhost:8080/api/auth/login \ -H Content-Type: application/json \ -d {username:2024001,password:123456}正常会返回一个包含token字段的 JSON 响应。如果登录返回 401优先检查用户表数据是否存在、密码使用 MD5 还是 BCrypt 加密前后端是否使用了相同的加密方式。6.2 前端启动cd campus-checkin-web npm install npm run devVite 默认端口是 5173浏览器访问http://localhost:5173。如果前端请求后端接口报跨域错误有两种处理方式一种是在后端配置 CORS 全局跨域另一种是在 Vite 配置 devServer 中的 proxy 代理。推荐使用第二种更接近生产环境的部署方式。// 文件路径vite.config.js import { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })6.3 功能验证清单拿到系统后建议按照下面的清单逐项验证形成自己的测试记录这对写毕业论文很有帮助功能模块测试步骤预期结果学生登录使用测试学号登录返回 Token进入报到首页查询报到状态查看步骤列表显示未完成/已完成步骤完成步骤点击“确认到校”步骤变为已完成宿舍查询进入宿舍信息页显示楼栋与房间号AI 问答输入“我的宿舍在哪里”AI 回复具体楼栋与房间号管理员统计登录管理端查看统计显示总人数、各院系报到率7. 常见问题与排查方法7.1 AI 接口调用超时大模型接口的响应时间通常在 2 到 8 秒之间如果网络不稳定超时概率会明显上升。解决方案是在前端把请求超时时间调长到 15 到 20 秒在后端设置合理的 HTTP 超时时间同时考虑把“慢响应”情况下的降级文案返回给前端而不是直接报错。另外AIGC 类接口最好在服务层做日志记录方便排查是网络问题、模型问题还是提示词问题。问题现象可能原因排查方式解决方案前端提示跨域没有配置代理或 CORS查看浏览器控制台网络请求配置 Vite proxy 或后端 CORS登录后无法访问接口JWT 拦截器未放行查看后端日志是否报 401检查拦截器路径配置AI 回答内容不准确提示词缺少业务上下文检查 systemPrompt 是否拼接学生数据先查数据库再让模型组织答案数据库中文乱码建表字符集错误查看表字符集配置统一使用 utf8mb4AI 接口超时模型响应慢查看后端调用日志超时时间调长返回降级文案7.2 报错“Invalid bound statement”这是 MyBatis 项目常见的错误。如果使用了 MyBatis-Plus发生这个错误的常见原因是 Mapper 接口没有扫描到或 XML 文件路径配置不对。确保启动类上有MapperScan注解并且在application.yml中配置了mapper-locations。mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml7.3 Spring Boot 3.x 版本迁移问题如果你的项目用的是 Spring Boot 3.x需要注意javax.servlet已经迁移为jakarta.servlet。老项目中的import javax.servlet.*都需要改为import jakarta.servlet.*。同时 MyBatis-Plus 需要选择支持 Spring Boot 3 的版本比如 3.5.3.2 及以上。建议新项目直接使用 Spring Boot 2.7.x学习资料最丰富遇到的坑也最少。8. 最佳实践与工程建议8.1 AI 功能与核心业务解耦在整个系统中最值得强调的设计原则是AI 是一个表现层能力不是一个业务依赖。换言之即使大模型接口不可用学生依然可以完成报到的核心流程。这要求前后端在页面设计上做明显的容错处理AI 对话组件只是一个辅助模块而不是必经之路。实际项目中这个问题可以通过把 AI 请求放入独立的 Service并且在异常时 catch 住返回兜底提示来实现。8.2 提示词版本管理很多人忽略提示词的管理。一个实际的经验是提示词改动一次效果可能天差地别。建议在项目里单独维护一个prompt/目录把不同场景的提示词写成独立的文本或配置项不要直接写在代码里。这样后续调优时可以对照历史版本快速定位是数据上下文变化还是提示词变化导致的回答差异。8.3 数据脱敏与安全边界学生信息属于个人敏感数据。登录接口返回的 JWT 中不要放入身份证号、手机号等完整信息。管理端的接口要校验角色权限至少做到普通学生只能查询自己的数据辅导员只能查看本学院的数据管理员拥有全部权限。这是安全上的底线要求也是答辩时老师比较关注的点。8.4 答辩时的表达建议做这类系统答辩时要明确“技术创新点”不是“我用了大模型”而是“我把大模型对接到结构化业务数据中解决了重复咨询和流程引导问题”。建议准备一张架构图说明 AI 助手是如何通过意图理解、数据查询、答案生成三步骤来回答问题的。同时准备一个现场演示案例比如输入“我还没交学费怎么报到”展示 AI 如何根据该学生的真实缴费状态给出个性化建议。这个过程能够非常直观地展示系统价值和你的工程能力。9. 总结与后续改进方向整个系统从功能规划到代码落地走完的是一条非常典型的“SpringBoot Vue MySQL AI 接口”的项目路线。如果用一句话概括这个项目的核心经验就是AI 大模型让系统的交互方式产生了质的变化但系统可靠性的根基仍然在业务建模、数据一致性和接口容错上。不要把大模型当成一个“万能答案生成器”挂在页面上而是把它嵌入到具体服务流程里让它在合适的位置发挥语言理解和生成能力。如果你打算在这个系统上继续深入有三条值得探索的路线一是把 AI 助手升级成“主动式服务”比如根据学生的报到步骤进度主动推送“你还有体检未完成请在 17:00 前到校医院”这样的提醒二是接入地图服务让学生可以直接通过 AI 对话获取从当前楼栋到目标地点的步行路线三是把学生的咨询记录做文本聚类分析找出高频问题反向优化学校的业务流程和信息展示方式。这三点都是低成本、高价值的迭代方向。