ARTICLE DETAIL

资讯详情

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

SpringBoot+Vue+MySQL在线招投标系统毕业设计实战指南

SpringBoot+Vue+MySQL在线招投标系统毕业设计实战指南 简介本资源面向计算机相关专业毕业生与课程设计开发者提供一套基于SpringBootVueMySQL的在线招投标系统完整实现方案涵盖源码、数据库脚本、毕业论文与视频演示适合作为毕业设计选题或企业级B/S项目练手参考。压缩包共820个文件约40.46MB以114个Java后端源码、44个Vue组件、155个JavaScript脚本、46个CSS样式及43个HTML页面为主体另含1个SQL数据库文件、3份Word论文文档、1个MP4演示视频及若干配置与构建脚本前后端分离结构清晰。系统围绕管理员、招标人、投标人、评标人四类角色展开覆盖招标信息发布、投标提交、评标打分与中标结果管理等核心业务模块并配有个人中心与系统管理功能。目前已有147人学习下载可帮助读者快速理解招投标业务流程、掌握SpringBoot与Vue整合开发思路并借助论文与录屏完成从环境搭建到功能演示的完整闭环。1. 在线招投标系统从一份毕业设计到能跑起来的技术选型每年毕业季计算机专业的学生都会面对同一个问题选一个能体现技术栈、又能在一两个月内做完的题目。在线招投标系统是这几年出现频率很高的选题原因很直接——它天然包含用户角色分离、流程状态流转、数据权限控制这几个后端面试必问的点同时前端页面数量适中不会像电商那样复杂到做不完。这套基于 SpringBoot Vue MySQL 的方案核心要解决的是招标方发布项目、投标方提交标书、评标方查看结果这条主链路适合作为本科毕业设计也适合想补一个完整 CRUD 权限项目练手的开发者。我见过太多人卡在第一步环境装不上、依赖拉不下来、数据库连不上最后代码还没写就先放弃了。所以这篇笔记不聊虚的从环境搭建到核心表设计、从接口联调到打包部署把每个环节的坑都摊开讲。你跟着走一遍至少能拿到一个能演示、能答辩、能继续改的系统。2. 环境搭建SpringBoot、Vue、MySQL 三件套怎么装才不翻车2.1 JDK 与 Maven 的版本对齐SpringBoot 对 JDK 版本有硬性要求。如果你用的是 SpringBoot 2.7.xJDK 选 8 或 11 都行如果上了 SpringBoot 3.xJDK 必须 17 起步。很多教程没提这一点结果新手拿着 JDK 8 去跑 3.x 的项目启动直接报Unsupported class file major version这就是典型的版本不匹配。我一般建议毕业设计锁在 SpringBoot 2.7.x JDK 8 这个组合原因是网上资料最多遇到问题搜得到答案。Maven 用 3.6 以上即可装完后在settings.xml里把阿里云镜像配上否则拉依赖能等到你怀疑人生。!-- Maven settings.xml 中 mirror 配置 -- mirror idaliyunmaven/id mirrorOf*/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror这段配置的作用是把 Maven 中央仓库的请求转发到国内镜像mirrorOf设为*表示拦截所有仓库请求。配完之后在命令行执行mvn help:effective-settings可以验证是否生效。注意别把mirrorOf写成central那样只拦截中央仓库有些第三方仓库还是会走国外。2.2 Vue 环境与 Node 版本选择Vue 这边分 Vue 2 和 Vue 3 两条路。毕业设计里 Vue 2 Element UI 的组合最稳因为组件库成熟、示例多。Vue 3 Element Plus 也可以但有些老教程的代码直接抄会报错。Node 版本建议用 14.x 或 16.x别用最新的 20.x某些依赖包在 Node 18 以上会有兼容问题。安装步骤很直接# 查看 node 和 npm 版本 node -v npm -v # 安装 Vue CLIVue 2 项目用这个 npm install -g vue/cli # 创建项目 vue create bidding-frontend # 进入目录安装依赖 cd bidding-frontend npm installvue create会交互式问你选预设选Manually select features然后勾上 Router、Vuex、Axios 相关的选项。创建完成后npm run serve启动默认跑在 8080 端口。如果 8080 被占用改vue.config.js里的devServer.port。提示npm 安装慢的话执行npm config set registry https://registry.npmmirror.com切换镜像源别用 cnpm那个坑更多。2.3 MySQL 安装与建库建用户MySQL 推荐 5.7 或 8.0。5.7 的好处是语法宽松8.0 默认开启了caching_sha2_password认证插件老版本的 JDBC 驱动连不上会报Unable to load authentication plugin。如果你用 8.0要么升级驱动到 8.x要么把用户认证方式改回mysql_native_password。-- 创建数据库字符集用 utf8mb4 支持 emoji CREATE DATABASE bidding_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 创建专用用户别用 root 跑应用 CREATE USER biddinglocalhost IDENTIFIED BY Bidding2024; -- 授权 GRANT ALL PRIVILEGES ON bidding_system.* TO biddinglocalhost; FLUSH PRIVILEGES;字符集一定要用utf8mb4招标公告里经常有特殊符号用utf8存进去会变问号。用户单独建而不是用 root是为了养成权限最小化的习惯答辩时老师问起来也是加分项。FLUSH PRIVILEGES是刷新权限表改完用户权限必须执行否则不生效。3. 数据库设计招投标业务的核心表与状态流转3.1 五张核心表撑起主流程招投标系统的表不用多但关系要理清。核心是五张用户表、招标项目表、投标记录表、评标结果表、附件表。用户表存三种角色——招标方、投标方、评标专家用role字段区分。招标项目表记录项目基本信息和中标状态。投标记录表关联项目和投标方一个项目可以有多条投标。评标结果表存最终得分和中标方。附件表用多态关联既能挂招标文件也能挂投标文件。-- 招标项目表 CREATE TABLE project ( id BIGINT NOT NULL AUTO_INCREMENT, title VARCHAR(200) NOT NULL COMMENT 项目名称, content TEXT COMMENT 招标要求, budget DECIMAL(15,2) DEFAULT NULL COMMENT 预算金额, publisher_id BIGINT NOT NULL COMMENT 发布方用户ID, status TINYINT DEFAULT 0 COMMENT 0待审核 1招标中 2已截止 3已评标, deadline DATETIME DEFAULT NULL COMMENT 投标截止时间, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_publisher (publisher_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;status字段是整个系统的灵魂所有业务逻辑都围绕它转。idx_status索引是为了列表页按状态筛选时走索引不然数据量上来后查询会慢。budget用DECIMAL而不是FLOAT金额计算不能有精度损失这是财务类系统的铁律。3.2 状态流转的代码实现状态不能随便改必须有明确的流转规则。待审核只能变招标中招标中只能变已截止已截止只能变已评标。这个规则我一般写在 Service 层用一个 Map 定义合法流转。// 状态流转校验 private static final MapInteger, ListInteger STATUS_FLOW new HashMap(); static { STATUS_FLOW.put(0, Arrays.asList(1)); // 待审核 - 招标中 STATUS_FLOW.put(1, Arrays.asList(2)); // 招标中 - 已截止 STATUS_FLOW.put(2, Arrays.asList(3)); // 已截止 - 已评标 STATUS_FLOW.put(3, Collections.emptyList()); // 已评标是终态 } public void updateStatus(Long projectId, Integer targetStatus) { Project project projectMapper.selectById(projectId); ListInteger allowed STATUS_FLOW.get(project.getStatus()); if (allowed null || !allowed.contains(targetStatus)) { throw new BusinessException(非法的状态流转); } project.setStatus(targetStatus); projectMapper.updateById(project); }这段代码把流转规则集中管理新增状态时只改 Map 不改业务逻辑。BusinessException是自定义异常配合全局异常处理器返回统一格式的错误信息。注意STATUS_FLOW.put(3, Collections.emptyList())这行终态必须显式定义为空列表否则get返回 null 会走异常分支逻辑上虽然也对但语义不清晰。3.3 投标截止时间的定时处理招标项目到了截止时间要自动变成已截止状态不然投标方还能继续提交。这个用 Spring 的Scheduled注解就能做不用上 Quartz 那么重。// 每分钟检查一次过期项目 Scheduled(cron 0 * * * * ?) public void closeExpiredProjects() { ListProject expired projectMapper.selectList( new LambdaQueryWrapperProject() .eq(Project::getStatus, 1) .le(Project::getDeadline, new Date()) ); for (Project p : expired) { p.setStatus(2); projectMapper.updateById(p); } }cron表达式0 * * * * ?表示每分钟的第 0 秒执行。LambdaQueryWrapper是 MyBatis-Plus 的条件构造器比手写 SQL 安全。这里有个坑如果项目量大一次性查出来更新会锁表生产环境要分批处理。毕业设计数据量小无所谓但答辩时能说出这个点说明你有考虑过性能。4. 前后端联调接口规范、跨域与文件上传4.1 统一响应格式与全局异常前后端联调最怕的就是接口返回格式不统一前端一会儿要判断code一会儿要判断success。我一般定义一个Result类所有接口都返回这个结构。Data public class ResultT { private Integer code; // 200成功 500失败 private String message; private T data; public static T ResultT success(T data) { ResultT r new Result(); r.setCode(200); r.setMessage(操作成功); r.setData(data); return r; } public static T ResultT error(String msg) { ResultT r new Result(); r.setCode(500); r.setMessage(msg); return r; } }配合RestControllerAdvice做全局异常捕获Service 层抛出的BusinessException会被自动转成Result.errorController 里就不用写一堆 try-catch。前端 Axios 拦截器里统一判断code非 200 就弹提示这样业务代码能干净很多。4.2 跨域配置的两种方式开发阶段前端跑在 8080后端跑在 8081浏览器同源策略会拦截请求。解决方式有两种后端加 CORS 配置或者前端配代理。我推荐前端配代理因为后端配置在打包部署后反而多余。// vue.config.js 中配置代理 module.exports { devServer: { port: 8080, proxy: { /api: { target: http://localhost:8081, changeOrigin: true, pathRewrite: { ^/api: } } } } }target是后端地址changeOrigin设为 true 表示请求头里的 Host 会被替换成目标地址pathRewrite把/api前缀去掉。这样前端代码里写/api/project/list实际请求的是http://localhost:8081/project/list。注意pathRewrite的写法^/api是正则别漏了^。4.3 招标文件上传与存储招投标系统离不开文件上传招标文件、投标文件都要存。简单做法是存到本地磁盘数据库只存路径。生产环境应该用对象存储但毕业设计本地存就够了。PostMapping(/upload) public ResultString upload(RequestParam(file) MultipartFile file) { if (file.isEmpty()) { return Result.error(文件为空); } String originalName file.getOriginalFilename(); String suffix originalName.substring(originalName.lastIndexOf(.)); String newName UUID.randomUUID().toString() suffix; String datePath new SimpleDateFormat(yyyy/MM/dd).format(new Date()); File dest new File(uploadDir datePath / newName); if (!dest.getParentFile().exists()) { dest.getParentFile().mkdirs(); } try { file.transferTo(dest); return Result.success(/files/ datePath / newName); } catch (IOException e) { return Result.error(上传失败); } }文件名用 UUID 重命名避免同名覆盖和中文乱码。按日期分目录存防止单个目录文件过多。mkdirs而不是mkdir因为要创建多级目录。返回的路径是相对路径前端拼接域名后访问。这里有个安全点要校验文件后缀别让用户传.jsp或.sh上来虽然 SpringBoot 内嵌 Tomcat 默认不解析这些但养成习惯没坏处。5. 避坑与排查那些让我熬夜的报错5.1 启动报错Table xxx doesnt exist现象是应用启动正常但一调接口就报表不存在。原因通常是 MyBatis-Plus 的驼峰映射没开或者实体类没加TableName注解。比如实体类叫Project数据库表叫project默认映射是能对上的但如果表名是t_project就必须加TableName(t_project)。解决方式是检查实体类注解和application.yml里的map-underscore-to-camel-case配置确保为 true。5.2 前端请求 404 但后端日志没输出现象是浏览器控制台报 404后端控制台干干净净。原因一般是代理没生效或者路径写错了。先检查vue.config.js改完有没有重启Vue CLI 的代理配置改动必须重启才生效。再检查前端请求的 URL 和后端RequestMapping是否匹配注意/api前缀在pathRewrite里被去掉了后端接口不要重复写/api。5.3 MySQL 8.0 连接报Public Key Retrieval is not allowed现象是 JDBC 连接串没问题但启动时报这个错。原因是 MySQL 8.0 的caching_sha2_password插件要求公钥检索而 JDBC 默认不允许。解决方式是在连接串后面加allowPublicKeyRetrievaltrueuseSSLfalse。或者更彻底一点把用户认证插件改回mysql_native_passwordALTER USER biddinglocalhost IDENTIFIED WITH mysql_native_password BY Bidding2024;5.4 打包后前端页面空白现象是npm run build生成的dist放进 SpringBoot 的static目录后访问首页空白控制台报资源 404。原因是 Vue 打包默认用绝对路径/js/app.js而 SpringBoot 的静态资源路径可能带上下文。解决方式是在vue.config.js里把publicPath改成./用相对路径。另外 Vue Router 要用hash模式history模式需要后端配合做 fallback否则刷新页面会 404。5.5 定时任务不执行现象是Scheduled注解加了但方法就是不跑。原因通常是启动类没加EnableScheduling注解。这个注解必须显式加上SpringBoot 不会自动开启定时任务支持。另外注意Scheduled方法不能有参数返回值必须是 void否则启动会报错。6. 打包部署与答辩演示的实用技巧6.1 前后端合并打包成一个 Jar毕业设计答辩时老师不会让你分别启动前端和后端最好打成一个 Jar 包双击就能跑。做法是把 Vue 打包后的dist目录内容复制到 SpringBoot 的src/main/resources/static下然后正常mvn package。# 前端打包 cd bidding-frontend npm run build # 复制到后端静态目录 cp -r dist/* ../bidding-backend/src/main/resources/static/ # 后端打包 cd ../bidding-backend mvn clean package -DskipTests打包完成后target目录下会生成一个可执行 Jarjava -jar xxx.jar就能启动。注意 Vue Router 要用 hash 模式否则刷新非首页会 404。-DskipTests是跳过测试毕业设计一般没写测试不跳过会报错。6.2 答辩演示的数据准备答辩时最尴尬的是系统里没数据点进去全是空的。提前准备一份初始化 SQL包含几个测试用户、几个招标项目、几条投标记录。用户密码用 BCrypt 加密后存进去别存明文。演示流程按「登录招标方 → 发布项目 → 切换投标方 → 提交投标 → 切换评标方 → 查看结果」走一遍五分钟能讲清楚整个业务闭环。6.3 源码和论文的整理习惯我自己的习惯是项目根目录下建三个文件夹code放源码sql放建表和初始化脚本doc放论文和演示视频。sql文件夹里分两个文件schema.sql只建表data.sql只插数据这样别人拿到你的项目能快速还原环境。论文里的系统截图要提前截好别等到答辩前一天才发现系统跑不起来。最后说一句实在的毕业设计做完不是终点这套代码里的权限控制、状态流转、文件上传逻辑稍微改改就能用到实际项目里。我当年做完答辩后把项目重构了一遍换掉了硬编码的角色判断加上了 Redis 缓存后来面试时直接拿这个项目讲比背八股文管用得多。希望帮到你。本文还有配套的精品资源点击获取
返回列表