ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

公交线路查询系统毕设实战:SpringBoot2+Vue3前后端分离完整实现

公交线路查询系统毕设实战:SpringBoot2+Vue3前后端分离完整实现 如果你也在做 Java Web 方向的毕业设计或综合项目练手公交线路查询系统绝对是个高频选项。最近我又帮一个学弟把 SpringBoot2 Vue3 MyBatis-Plus MySQL8.0 这套公交线路查询系统源码完整跑通顺手整理了一份从选型、数据库设计、前后端联调到答辩文档准备的实操笔记。这篇文章不搞虚的把这类系统从 0 到 1 的真实过程写清楚尤其适合准备做 Web 开发方向毕设、或者想拿一个完整项目锻炼自己前后端能力的人。很多同学看到“公交线路查询系统”这个名字第一反应是“不就是个增删改查吗”真动手写的时候才发现线路和站点是多对多关系线路有上下行方向站点有先后顺序换乘方案还得动脑筋。如果这些细节没想清楚代码越写越乱。这篇博客我会按实际开发顺序走一遍把每个环节的取舍逻辑和值得注意的坑都说明白你可以直接对照着改。1. 公交线路查询系统毕业设计里的“熟面孔”却是翻车重灾区1.1 这个系统到底要解决什么问题公交线路查询系统看起来是个典型的“信息管理 信息查询”类项目但它的业务场景比普通 CRUD 更贴近真实生活。乘客想知道从 A 站到 B 站坐哪条线路、能不能直达、如果不能直达需要换乘几次、早班车晚班车分别是什么时候、票价多少。管理员则关心线路信息怎么维护、站点怎么维护、某条线路经过哪些站点、站点顺序怎么调整。这两类需求叠加在一起项目就有了两条明确的主线一是给乘客用的查询界面二是给管理员用的后台维护界面。很多同学只做了后者也就是说只有“线路表的新增、编辑、删除、列表”却把最核心的“换乘查询”“站站搜索”扔掉了这样答辩时很容易被老师一句话问住“你这系统公交公司内部管数据可以乘客用它干嘛”所以做需求分析的时候一定要把角色分清楚。乘客端至少要有线路查询、站点查询、换乘方案、线路详情管理员端要有线路管理、站点管理、线路站点绑定维护、用户登录。只有把这两条线都放进系统这个项目才算完整也才有话可讲。1.2 功能模块怎么划分最合理根据我做过多个类似项目的习惯建议把整个系统拆成下面几个模块前端页面也按模块去组织。用户模块管理员登录、修改密码简单用 Spring Security 或拦截器做一下权限控制就够了。线路管理线路的增删改查包含线路名称、起点站、终点站、首末班时间、票价、状态。站点管理站点的增删改查包含站点名称、所属区域、经纬度、状态。线路站点维护给指定线路绑定站点维护站点顺序和上下行方向这是核心功能。乘客查询线路查询、站点经过线路查询、换乘方案查询、线路详情查看。功能不在多而在每一项都能讲清楚“为什么这么设计”。比如线路站点维护为什么要单独做一张关联表而不是在站点表里加一个线路字段这个我放到数据库部分详细说它是整个系统能不能正常工作的关键。1.3 常见误区只做 “查线路” 的 CRUD答辩必被追问我见过不少直接把代码贴上来的同学系统一跑起来就是个“线路管理后台”页面左侧菜单全是管理功能唯独没有乘客查询入口。严格来说这也能交差但课程设计或毕业设计通常要求“系统的现实应用价值”没有乘客视角就等于没有应用场景。还有一个误区是忽略上下行。真实公交线路往往“去程”和“回程”站点不完全一致即使一致顺序也可能不同。如果数据库里只有一个站点顺序答辩老师只要举一条线路反问“这趟车回程也经过这个站吗顺序一样吗”直接就把方案问倒了。所以我在后面的数据库设计里专门强调了 direction 字段哪怕你的示例数据故意做得上下行完全一致也要让表结构具备这个能力这是业务敏感度的问题。2. 技术选型不是拍脑袋这套组合赢在哪也有哪些雷2.1 SpringBoot2 为什么是“稳妥牌”选 SpringBoot2 而不是 SpringBoot3最现实的原因是生态兼容性和学习资料丰富度。截至现在大量教学视频、博客、开源项目仍然基于 SpringBoot2 编写MyBatis-Plus 官方文档对 SpringBoot2 的支持也最稳定。更关键的是 SpringBoot2 通常搭配 JDK8而 JDK8 是大多数学校机房、学生本机的默认环境不用折腾新版本的兼容问题。SpringBoot2 带来的好处还体现在开发效率上。内嵌 Tomcat 让应用可以直接打成 jar 包运行不需要单独装 Tomcat 再部署 war 包自动配置减少了大量 XML配合 Lombok、MyBatis-Plus写实体类和 Mapper 的速度很快。对毕设这种“时间紧、要快速看到效果”的场景来说这是最稳妥的组合。2.2 Vue3 组合式 API 对开发组织方式的影响Vue3 最值得用的是组合式 API。以前用 Vue2 写页面数据、计算属性、方法分开放代码一长就得上下反复滚Vue3 的 setup 语法把某个业务相关的数据和方法放一起逻辑内聚度高很多。以公交查询页面为例从站点选择、线路列表、换乘结果到加载状态都可以写进一个 composable 函数里页面组件只负责调用和渲染。这样代码量并没有减少但可读性、扩展性明显改善答辩时也更好解释。Vue3 脚手架建议直接用 Vite启动速度快配置文件直观。虽然 Vue CLI 也能用但 Vite 是当前主流和 Vue3 的配合更顺手。2.3 MyBatis-Plus 到底解决了什么痛点传统 MyBatis 写单表 CRUD 需要手写大量 XML特别繁琐。MyBatis-Plus 做了增强单表操作基本不需要写 SQL只用 LambdaQueryWrapper 就能完成条件查询、排序、分页。对于公交线路查询系统这种“单表查询多、多表查询集中在少数几个业务点”的项目MyBatis-Plus 非常合适。当然多表关联依然需要自定义 SQL比如“查询经过某个站点的所有线路”这种语句我建议直接用 Select 注解写在 Mapper 接口里。这样既保持了 MyBatis-Plus 的快速开发优势又对核心查询保持了 SQL 的可控性。2.4 MySQL8.0 的版本细节别忽视MySQL8.0 默认字符集已经是 utf8mb4但建库时最好还是显式指定字符集防止中文乱码。另一个高频坑是时区配置JDBC 连接串必须带上 serverTimezoneAsia/Shanghai否则数据库连接会报错或者时间相差 8 小时。MySQL8.0 对 SQL 语法要求也更严格比如 GROUP BY 默认启用了 only_full_group_by。如果后面写统计类 SQL 时查询字段不在分组里就会直接报错。遇到这种情况不用慌要么调整 SQL要么在配置里关掉该模式但说实话毕业设计阶段尽量不要靠改全局配置绕过去规范写 SQL 对答辩更有利。下面用一个表格总结这套组合的选型理由方便你写文档时直接参考。组成部分选型理由注意点SpringBoot2生态成熟、资料多、内嵌Tomcat配合JDK8最稳别盲目升级Vue3组合式API、Vite构建、前后端分离学习门槛略高于Vue2但值得MyBatis-Plus单表CRUD免写SQL、分页方便多表查询仍需自定义SQLMySQL8.0性能好、默认utf8mb4注意时区和SQL模式3. 数据库设计线路、站点、线路站点关联三张表撑起核心业务3.1 核心表结构设计公交线路查询系统的数据模型不复杂但必须把关系建模建对。最核心的点是线路和站点是多对多关系。一条线路经过多个站点一个站点可能有多条线路经过。如果直接在站点表里加线路ID字段只能保存一对多数据会大量冗余维护时还会出现修改一条线路要改很多行的情况。标准做法是引入一张关联表例如 bus_line_station专门记录“某条线路的某个方向按什么顺序经过哪个站点”。这样线路表、站点表、关联表三张表一组合所有查询需求都能支撑起来。下面是线路表和站点表和关联表的核心字段建议可以参考这种风格来设计。CREATE TABLE bus_line ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 线路ID, line_name VARCHAR(50) NOT NULL COMMENT 线路名称, start_station VARCHAR(100) NOT NULL COMMENT 起点站, end_station VARCHAR(100) NOT NULL COMMENT 终点站, fare DECIMAL(5,2) DEFAULT 2.00 COMMENT 票价, first_bus_time TIME COMMENT 首班时间, last_bus_time TIME COMMENT 末班时间, distance VARCHAR(20) COMMENT 运营里程, status TINYINT DEFAULT 1 COMMENT 状态 1启用 0停用, create_time DATETIME, update_time DATETIME ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT公交线路表; CREATE TABLE bus_station ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 站点ID, station_name VARCHAR(100) NOT NULL COMMENT 站点名称, area VARCHAR(50) COMMENT 所属区域, longitude DECIMAL(10,6) COMMENT 经度, latitude DECIMAL(10,6) COMMENT 纬度, status TINYINT DEFAULT 1 COMMENT 状态 1启用 0停用, create_time DATETIME, update_time DATETIME ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT公交站点表; CREATE TABLE bus_line_station ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键ID, line_id BIGINT NOT NULL COMMENT 线路ID, station_id BIGINT NOT NULL COMMENT 站点ID, direction TINYINT NOT NULL COMMENT 方向 0上行 1下行, station_order INT NOT NULL COMMENT 站点顺序从1开始, create_time DATETIME ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT线路站点关联表;字段设计上有一点要专门说线路表里冗余了 start_station 和 end_station表面上看起来多余因为通过关联表按 station_order 排序也能查到起点和终点。但保留冗余字段的好处是在列表页展示线路时不用每次去关联表计算查询性能更好管理端维护也直观。代价是需要保证冗余字段和关联表数据的一致性这个在新增或编辑线路时手动维护即可毕业设计阶段完全够用。3.2 上下行方向与站点顺序怎么建模公交线路的经典难题是上下行站点可能不同。比如上行方向走 A-B-C-D下行方向可能是 D-C-B-A甚至有一侧绕行 E 站。所以关联表必须同时记录 direction 和 station_order。查询某条线路的详情时先按 line_id 和 direction 过滤再按 station_order 排序就能得到正确顺序的站点列表。我建议在公共常量里定义两种方向前端展示用“去程 / 回程”避免给用户解释“上行下行”的歧义。管理员维护线路时可以分两个 Tab 分别编辑上行和下行方向后端接口按 direction 字段区分数据上互不干扰。这样设计示例数据哪怕只填一个方向代码逻辑也已经为完整场景做好了准备。3.3 索引设计直接关系查询效率这类系统查询最多的场景是线路关键词查询、站点名称查询、按照站点查线路、按线路查站点。索引至少要覆盖下面几条关键路径。bus_line 表的 line_name 字段建立普通索引支持 LIKE 模糊查询。bus_station 表的 station_name 字段建立普通索引。bus_line_station 表建立联合索引 (line_id, direction, station_order)用于线路详情排序。bus_line_station 表再为 station_id 建立普通索引用于“经过某站点的所有线路”查询。数据量小的时候这些索引看起来无所谓但论文里和答辩时能说出“索引设计思路”比单纯贴建表语句强得多。索引是毕设考察中比较容易加分的点不要忽略。4. 后端 SpringBoot2 实现统一返回、条件查询、分页、换乘算法4.1 统一返回结构是先要做好的“地基”后端接口如果每个方法返回不同类型的对象前端解析会非常痛苦。我一般会先定义一个统一返回类 Result包含 code、message、data 三个字段再提供 success 和 error 两个静态方法。Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(操作成功); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }再配合一个全局异常处理器把业务异常和未知异常统一转换成 Result 返回。这样前端 axios 拦截器只需要统一判断 code 即可弹错误提示、跳登录页这些逻辑只写一遍。4.2 MyBatis-Plus 的 LambdaQueryWrapper 与分页配置用 MyBatis-Plus 做列表查询是非常顺手的。线路管理的分页查询可以这样写注意这里用 lambda 表达式构建条件能避免硬编码数据库字段名安全性也更好。public PageResultBusLine queryBusLinePage(String keyword, Integer status, int page, int size) { PageBusLine p new Page(page, size); LambdaQueryWrapperBusLine wrapper new LambdaQueryWrapper(); if (StringUtils.hasText(keyword)) { wrapper.like(BusLine::getLineName, keyword); } if (status ! null) { wrapper.eq(BusLine::getStatus, status); } wrapper.orderByDesc(BusLine::getUpdateTime); busLineMapper.selectPage(p, wrapper); return PageResult.of(p.getRecords(), p.getTotal()); }分页插件配置要注意使用新版写法。旧版本的 PaginationInterceptor 在新版 MyBatis-Plus 里已经废弃如果你照抄老博客会出现“分页不生效、查出全部数据”的问题。正确配置是使用 MybatisPlusInterceptor并把 PaginationInnerInterceptor 加进去。Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }4.3 换乘方案一次换乘与最少换乘的算法实现换乘查询是整个项目里最有技术含量、也最值得在答辩时展开讲的部分。我建议先实现一次换乘再考虑最少换乘难度梯度很清晰。一次换乘的思路非常朴素从起点站出发先找到所有经过起点站的线路从终点站出发再找到所有经过终点站的线路如果两个线路集合存在交集说明可以搭乘其中一个交集线路的一段然后在某个中间站换乘到另一条线路。用集合操作来描述就是起点线路集合与终点线路集合求交集交集非空即可一次换乘。这个过程的 SQL 本质是“通过站点反查线路”Mapper 方法可以这样定义。Select(SELECT DISTINCT line_id FROM bus_line_station WHERE station_id #{stationId}) ListLong selectLineIdsByStationId(Long stationId);最少换乘则可以用广度优先搜索。把每条线路看成图中的一个节点两条线路如果有共同的站点就在这两个节点之间连一条边。从“经过起点站的线路集合”出发一层层往外扩展直到遇到“经过终点站的线路集合”中包含的线路节点。这条路径上的换乘次数就是最少换乘次数相邻两条线路的交集站点就是换乘点。public int getMinTransferCount(Long startStationId, Long endStationId) { // 1. 查出经过起点站的线路ID集合 // 2. 查出经过终点站的线路ID集合 // 3. 以线路ID为节点链路关系为两线路有共同站点则连通 // 4. BFS 从起点线路集合到终点线路集合的最短层数减1 }这里不建议一上来就引入 Dijkstra、A* 之类更复杂的算法公交系统的“换乘最少”本质就是无权图最短路径BFS 够用且容易讲清楚。答辩时只要能把“把线路当节点、共同站点当边”这个转化思路说清楚老师基本不会再深挖。4.4 事务控制别忘了涉及多条数据修改的操作必须加事务。比如管理员调整某条线路的站点顺序往往要先删除旧的关联记录再插入新的关联记录。如果第二步失败而第一步成功线路就变成空线路了。直接在 Service 方法上加 Transactional 就能解决。Transactional(rollbackFor Exception.class) public boolean updateLineStations(Long lineId, Integer direction, ListLong stationIds) { // 删除该线路该方向旧记录 // 按顺序插入新记录并计算 station_order }另外还要注意站点绑定操作接收的是一个有序集合前端传数据时要按站点顺序传入接口侧按列表下标生成 station_order不要把排序逻辑交给前端做。5. 前端 Vue3 实现从乘客页面到管理后台的落地细节5.1 项目初始化和依赖安装前端用 Vite 创建工程最省心Node.js 建议使用 18 以上版本否则部分依赖可能安装失败。创建好项目后安装运行时依赖。npm create vitelatest bus-front -- --template vue cd bus-front npm install npm install vue-router4 pinia axios element-plusElement Plus 是我个人比较常用的组件库表格、弹窗、表单联动都有现成组件能节省大量写样式的时间。页面布局用它的 Container 布局加上菜单栏和内容区就能搭出一个后台管理的基本框架。5.2 页面与组件怎么拆分页面层面分成两部分乘客查询端和管理后台端。乘客查询端建议做成独立的简洁页面不要和管理后台混在一起。三个核心页面分别是线路查询、站站搜索、换乘查询。线路查询页展示线路卡片列表点击查看线路详情站站搜索输入站点名称展示经过该站点的所有线路换乘查询输入起点和终点展示直达或换乘方案列表。管理后台端则包含登录页、线路管理页、站点管理页、线路站点绑定页。绑定页是核心我建议做成左右结构左侧选择线路和方向右侧用可拖拽排序的列表维护站点顺序。Element Plus 的 el-transfer 或 vuedraggable 都能实现拖拽毕设用 el-transfer 足够但 vuedraggable 的体验更好。组件层面可以把站点选择器封装成一个公共组件因为乘客端和后台都频繁用到站点选择。5.3 请求封装与 Vite 代理配置前后端分离开发时最省事的联调方式是用 Vite 代理把 /api 请求转发到后端 8080 端口。这样前端代码里请求地址统一写 /api/xxx浏览器就不存在跨域问题。// vite.config.js export default { server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: path path.replace(/^\/api/, ) } } } }axios 封装时设置 baseURL 为 /api再在请求拦截器里带上 token响应拦截器里统一处理 code 非 200 的情况。这样后端返回 Result 结构后前端每个页面只需要关心业务数据不需要重复处理错误弹窗。import axios from axios; const service axios.create({ baseURL: /api, timeout: 10000 }); service.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers[Authorization] token; } return config; }); service.interceptors.response.use(response { const res response.data; if (res.code ! 200) { return Promise.reject(new Error(res.message)); } return res.data; });5.4 权限控制和动态菜单这个系统的角色可以只做管理员一种但登录和 token 校验还是要有的。后端使用拦截器对 /admin/** 路径做校验前端则根据登录状态控制页面路由。可以把需要登录才能访问的页面统一放到一个外层路由下面路由元信息里加 requiresAuth 标记配合全局前置守卫判断。router.beforeEach((to) { const token localStorage.getItem(token); if (to.meta.requiresAuth !token) { return /login; } return true; });如果后端接口没传有效 token统一返回 401前端响应拦截器检测到 401 后清除本地登录信息并跳转登录页。这里的逻辑不算复杂但能体现出完整的权限控制意识。6. 这一路最容易踩的五个坑从 MySQL 连接到前后端联调6.1 MySQL8.0 连接报错与驱动配置很多同学第一次跑这个项目就栽在数据库连接上。使用 MySQL8.0 时JDBC 驱动类要写 com.mysql.cj.jdbc.Driver连接串必须带上时区并且要允许公钥检索。spring.datasource.urljdbc:mysql://localhost:3306/bus_system?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltruecharacterEncodingutf8 spring.datasource.usernameroot spring.datasource.password123456 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver如果少写了 allowPublicKeyRetrievaltrue新版 MySQL 连接时可能会报 “Public Key Retrieval is not allow” 错误。useSSL 建议设为 false本地开发根本不需要 SSL 加密减少不必要的潜在问题。6.2 MyBatis-Plus 分页插件不生效分页插件不生效的典型表现是传入 Page 对象后SQL 没有拼接 LIMIT查出来所有数据。原因通常是配置方式写错或者配置类没有被扫描。新版 MyBatis-Plus 必须使用 MybatisPlusInterceptor 加 PaginationInnerInterceptor这一点前面已经给了完整配置。配置类上一定要加 Configuration并且确保它在 SpringBoot 启动类能扫描到的包路径下。6.3 跨域问题前端 5173 调后端 8080如果不用 Vite 代理直接在 axios 里写 http://localhost:8080浏览器会被 CORS 拦下。解决办法有两个一是在后端写一个 WebMvcConfigurer 配置类允许跨域另一种是使用 Vite 代理两者选一个就行。我自己的经验是优先用 Vite 代理因为代理模式下前端请求地址和环境无关后期部署到服务器只要调整代理配置即可。如果两种方案同时开启某些情况下会出现重复请求头导致的小问题所以建议选一种用到底。6.4 LocalDateTime 序列化格式问题使用 SpringBoot2 默认 Jackson 序列化时LocalDateTime 会被输出成数组格式前端拿不到 “2025-02-14 12:00:00” 这样的标准字符串。解决办法是在 application.yml 里配置统一格式。spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8注意仅是配置 date-format 对 LocalDateTime 不一定生效还需要引入 jackson-datatype-jsr310 模块不过 SpringBoot 默认已经包含。实际测试如果还不对可以在 LocalDateTime 字段上直接加 JsonFormat(pattern “yyyy-MM-dd HH:mm:ss”) 注解这种最稳妥。6.5 Node 版本和 Vite 版本的兼容问题安装前端依赖时如果报错 “Error: Cannot find module”先检查 Node 版本。Vite 4 以上版本对 Node 版本有要求至少需要 Node 18。还有同学使用的是 Vite 5需要更高的 Node 版本。装依赖前建议看一下 package.json 里的 engines 字段或者直接用 nvm 切换到 Node 18 长期支持版。前端依赖安装失败还有一个隐蔽原因npm 镜像源不稳定。可以临时切换为国内镜像加快下载但这不是必须项因为每个学校网络环境不一样我不做具体推荐网络策略合规安装即可。把上面这些常见问题整理成一张表排查时可以直接对照。现象根本原因解决办法数据库连接超时或拒绝驱动名、时区、SSL配置不对按 6.1 统一修改连接串分页查询返回全部数据MyBatis-Plus 分页插件配置过时使用 MybatisPlusInterceptor PaginationInnerInterceptor前端请求被跨域拦截前后端端口不同使用 Vite 代理或后端 CORS 配置时间字段变成数组LocalDateTime 序列化未配置字段加 JsonFormat 或全局配置前端依赖安装失败Node 版本过旧升级到 Node 18 及以上7. 源码交付和答辩文档让项目看起来“完整”的四个关键材料7.1 任务书与需求分析怎么写“基于 Java Web 的公交线路查询系统设计与实现”这个题目任务书通常要求写清楚项目背景、目的、功能需求、非功能需求和技术路线。背景不建议写太长突出“城市公共交通信息查询需求大”“传统查询方式效率低”即可。功能需求用用例说明的方式展示比如乘客查询线路、管理员维护线路、系统管理员维护数据。这里分享一个小技巧任务书里的“技术路线”一定要和最终实现一致。如果你题目里写了 Java Web但只放了 Vue 单独打包后的文件没有说明前后端分离架构答辩时容易被质疑。建议在技术路线里明确提出“前后端分离架构后端 SpringBoot2 MyBatis-Plus前端 Vue3 Vite”。7.2 数据库设计文档数据库设计文档是整个项目文档里含金量比较高的部分也是比较容易扩展篇幅的部分。建议包含下面几块内容。E-R 图用绘图工具画出用户、线路、站点、线路站点关联几个实体及关系。表结构说明每张表的字段、类型、注释、约束。关系描述线路与站点是多对多关系通过 bus_line_station 关联表实现。索引设计说明针对高频查询建立的索引。写数据库文档时我建议直接把建表 SQL 中的 COMMENT 写全这样导出的表结构说明可以直接复制到 Word 里能节省大量时间。7.3 测试用例与运行截图测试部分不要只写“系统通过测试”要给出典型的测试用例和结果。比如线路查询用例输入不存在的线路名称期望返回无数据输入 “1路” 期望返回包含该关键字的线路列表。换乘查询用例输入“火车站”到“汽车站”期望返回一次换乘方案输入相同站点期望提示起点终点不能相同。运行截图建议覆盖登录、线路管理列表、站点管理、线路站点绑定、乘客查询页面、换乘结果页面。如果你做了前后端分离最好把前端页面和后端接口返回值各截一张证明前后端确实联调通过。7.4 答辩高频问题准备根据我的经验答辩老师最喜欢在公交查询系统上追问这几类问题。为什么用 MyBatis-Plus和 MyBatis 有什么区别换乘算法怎么实现的能不能处理一次换乘和多次换乘上下行站点不一致怎么处理删除线路线路时关联表的数据怎么处理系统有没有做权限控制普通用户能不能访问后台接口这些问题的答案其实在本文前面都已经提到了你可以整理成一句话版本多对多用关联表上下行用 direction 字段区分换乘先用线路集合求交集再考虑 BFS删除线路时在事务里同步删除关联记录后台接口通过拦截器校验 token。每一条都要能落到你自己的项目代码里不要背通用答案。关于文档还要说一点源码包里的 README 一定要能让人按步骤跑起来。把 MySQL 脚本、后端启动步骤、前端依赖安装命令、默认账号密码写清楚。我之前见过不少项目代码本身没问题但 README 里的端口和路径写错了这种细节直接拉低项目完成度的印象分。如果你时间紧张至少把启动流程自己照着跑两遍再补上每页截图答辩通过率会高很多。
返回列表