
简介基于Spring Boot、MySQL与Vue构建的在线问卷调查系统完整项目面向Java毕业设计或课程设计人群提供前后端分离的问卷设计、发布、统计与管理实现方案。系统包含管理员与用户双角色覆盖登录注册、问卷与题目管理、题目统计、问卷调查记录、新闻资讯、轮播图设置等常见业务模块。压缩包共755个文件以Java源码、Vue组件、JS脚本、CSS样式、XML配置、SQL脚本为主另含图标、图片、字体及安装运行批处理脚本整体大小约23.59MB结构清晰便于导入学习和二次开发。目前已吸引87人学习下载。包内不仅附有完整项目源码与数据库脚本还包含毕业论文文档可配合启动脚本快速在IDEA或Eclipse中运行调试适合需要从零搭建同类系统、补充毕设材料或研究Spring BootVue整合开发的读者同时便于结合真实业务场景理解问卷创建、数据统计与权限分配的完整流程。1. 一个常见的 Java 毕设项目为什么有人跑三天跑不起来有人十分钟就打开了问卷页面基于 springBootmysqlmavenvue 的在线问卷调查系统是这几年 Java 方向毕业设计和初级工程师练手出现频率最高的一类项目。你拿到的所谓“含源码数据库毕业论文”的压缩包里通常是一个 Spring Boot 后端、一个 Vue 前端、一份 SQL 脚本和一篇可以直接改改用的论文。但它绝不是解压即跑——真正卡住绝大多数人的不是业务代码而是环境变量、数据库初始化、前端代理、以及那两个端口之间的联调。这套项目最大的价值也正在于此它麻雀虽小却完整地覆盖了从数据库建模、后端接口、JWT 登录鉴权到 Vue 页面联调的全链路。一篇合格的实践笔记应该能把这条链路在你自己的电脑上完整复现并且让你知道每一步是在干什么、改了什么、挂了该查哪里。这篇文章就按这个标准来写。2. 在线问卷系统的完整技术拆解从业务流程到数据表2.1 这类系统到底在管理哪些对象在打开源码之前先把业务模型想清楚。一个在线问卷调查系统核心参与方无非三种管理员、创建问卷的人、填写问卷的人。在很多毕设版本里管理员和创建问卷的人会合并成同一个角色普通用户也能登录但只能填写被分配到的问卷。业务上最基础的一条主链路是管理员登录后台创建一份问卷往里添加若干题目每道题可能有多个选项然后发布问卷用户拿到链接或登录后进入填写页逐题作答提交答卷管理员在后台查看统计数据或导出原始结果。理解这条链路的关键在于问卷和题目是嵌套关系题目和选项也是嵌套关系而答卷是另一种完全不同的数据结构。很多人在改这类项目时翻车就是因为把“一道题的几个选项”和“一份问卷的所有问题”装进了同一张表最后统计时只能写出又臭又长的手写 SQL。源头做对后面才不折腾。2.2 数据库设计核心表问卷、题目、选项、答卷大多数 Spring Boot 版本的问卷系统数据库最少会包含六张表用户表、角色表或直接在用户表里加 role 字段、问卷表、题目表、选项表、答卷表。问卷表里通常会有一个 status 字段标记草稿、发布中、已结束比如 0 草稿 1 发布 2 结束。题目表通过 survey_id 关联问卷表再用一个 type 字段区分单选、多选、文本题。选项表通过 question_id 关联题目。答卷表则比较特殊一条记录对应一份完整答卷核心字段是 survey_id、user_id以及一个存答案内容的大字段很多项目直接用 text 类型把整个 JSON 结构存进去。用 JSON 存答案看起来偷懒但对这类课程项目和毕设来说是最务实的选择。原因是问卷题目在发布之后通常不允许改动原始作答数据很少需要按题目维度做复杂的 SQL 关联导出 Excel 统计时在 Java 里解析 JSON 反而比拼十几层 JOIN 要快得多。如果你想在技术上表现得比普通毕设更完整可以在答卷表旁边加一张 answer_detail 表做明细拆分但这不改变整体架构。2.3 前后端分离架构下Spring Boot 和 Vue 各自负责什么这个项目的后端是一个标准的 Spring Boot 单体应用Maven 管理依赖MySQL 存数据使用 MyBatis 或 MyBatis-Plus 做持久层Spring Security 或简单拦截器做登录校验用 JWT 换 token。前端是一个 Vue 2 或 Vue 3 的单页应用通过 axios 请求后端接口用 vue-router 做页面跳转配合 Element UI 或类似组件库快速搭界面。前端页面通常包含登录页、问卷管理列表页、问卷编辑页动态增删题目、问卷填写页、统计结果页。后端接口则按模块拆分典型的 controller 有AuthController登录注册、SurveyController问卷增删改查与发布、QuestionController题目维护、AnswerController提交答卷与查询统计。在跑通整个项目之前建议先画一张接口清单前端页面和接口对应上后面联调会省很多力气。接口清单不用复杂一张纸或一个文档就够。3. 把环境先立住JDK、Maven、MySQL、Vue 的安装与启动3.1 这些环境到底要装到什么版本才能和项目匹配大多数这类项目的后端代码基于 Java 8 语法编写Spring Boot 版本在 2.2.x 到 2.7.x 之间对应的 JDK 8 或 JDK 11 都足够。少数新版本的源码用到了 Java 17 特性但毕业设计项目里非常少选 JDK 8 或 JDK 11 反而最稳妥。Maven 用 3.6.x 或 3.8.x 都可以重点不是版本而是三个配置项本地仓库路径、阿里云镜像、JDK 编译版本。MySQL 用 5.7 或 8.0 都行但 SQL 脚本如果是 5.7 时代导出的直接导入 8.0 大概率遇到字符集或认证插件的问题这一点在避坑一章会展开说。Vue 项目如果是 Vue 2 Element UI 的脚手架Node 版本建议 14.x 或 16.x太新的 Node 18/20 在 node-sass 上很容易栽跟头。安装顺序建议是先 JDK再 Maven再 MySQL最后 Node。前三个直接关系到后端能不能启动Node 关系到前端能不能跑起来。每一步装完都先做一个最小验证不要等全部装完再排查那样出了问题根本不知道是哪一层坏了。3.2 Maven 必须改的三个地方本地仓库、镜像、JDK 版本Maven 装好之后不要急着运行项目。先打开 conf/settings.xml确认三件事localRepository 是否指向你想要的位置mirror 是否配置了阿里云镜像profiles 里是否锁定了 JDK 版本。很多初学者的默认 settings.xml 从未动过下载依赖要走 Maven 中央仓库速度慢且容易超时项目第一次 build 就半路失败这个坑几乎人手一份。下面是一份可以直接替换到 settings.xml 的镜像配置片段复制到mirrors标签内即可mirror idaliyunmaven/id mirrorOf*/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror这里mirrorOf的值写*意思是所有 Maven 依赖下载请求都走这个镜像包括中央仓库、Jcenter 等外部仓库。阿里云公共仓库聚合了绝大部分 Java 依赖对这套项目来说完全够用。配置完成后在命令行执行mvn -v确认 Maven 版本正常再执行mvn help:system触发一次依赖下载看到 BUILD SUCCESS 后后端依赖下载环节就不会再来回折磨你了。3.3 用命令逐层验证环境JDK、MySQL、Maven 各一行装完环境先别解压源码按顺序跑下面这几组命令任何一步报错都停下来先解决。JDK 验证看的是版本号MySQL 验证看的是能否免密或密码登录Maven 验证看的是配置是否生效。java -version javac -version mvn -v mysql -u root -p node -v npm -vjavac -version很多人会漏掉但其实比java -version更关键。Spring Boot 项目用 Maven 编译时依赖 javac如果只装了 JRE 而没装 JDKjava 命令有输出javac 直接提示无法找到后端代码根本无法编译。MySQL 的登录验证要注意5.7 默认 root 密码为空或通过临时密码登录8.0 的 root 初始化则强制要求先设置一个密码两种方式差别很大。Node 的版本输出只要确认不是自动跳到最新的 20.x 即可Vue 2 项目在这个版本下大概率出问题。3.4 导入数据库SQL 脚本不是只能整包执行拿到 SQL 脚本后先不要急着一次性执行。先打开脚本看一眼它是否包含CREATE DATABASE语句。很多毕设项目的 SQL 里已经建好库直接执行即可但另一部分只包含CREATE TABLE这时候你需要先手动建库再导入。推荐在命令行里先确认库是否存在再选择库执行脚本。常见的做法是mysql -u root -p -e CREATE DATABASE IF NOT EXISTS survey DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; mysql -u root -p survey /path/to/survey.sql第一行命令用-e参数直接执行建库语句utf8mb4字符集是这类项目必须的否则问卷题目里一旦出现中文或表情符号存储会直接乱码。第二行把 SQL 脚本导入到指定数据库中。执行完成后用SHOW TABLES;确认表已经建出来再挑一张核心表执行DESC survey;检查字段结构是否正常。脚本执行报错最常见的两种原因是字符集不匹配和脚本文件里包含 MySQL 8.0 不认识的注释语法前者用 utf8mb4 解决后者需要在导入前把脚本里的旧的排序规则关键字删掉。3.5 后端第一个启动命令spring-boot:run 和它的日志判读数据库准备完毕后在项目根目录执行mvn spring-boot:run启动后端。第一次启动会下载大量依赖日志滚动速度很快看到BUILD SUCCESS不算启动成功看到 Spring Boot 的 Banner 和Tomcat started on port(s): 8080才算真正起来了。如果启动失败日志的末尾几行通常会直接告诉你原因端口被占、数据库密码错误、表不存在、或者某个 Bean 注入失败。启动成功后先验证一个公共接口比如登录接口或验证码接口用 curl 直接打一次请求比打开浏览器更快定位问题。例如curl -X POST http://localhost:8080/api/auth/login -H Content-Type: application/json -d {username:admin,password:123456}如果返回一段包含 token 的 JSON 数据说明后端和数据源已经打通。如果返回空白或 500切换后端日志窗口看异常栈重点看是 SQL 语法错误还是数据库连接失败这是两个完全不同的排错方向。后端到这一步先停下来把前端搭起来再说。4. 把前后端联调打通跨域配置、接口对接与数据回显4.1 前端 devServer 代理为什么跨域问题会在本地开发时出现前端项目启动后默认跑在 5173Vue 3 Vite或 8081Vue 2 vue-cli 配置端口后端跑在 8080两个端口不同浏览器就会触发同源策略所有请求在 Network 面板里显示 CORS error。解决方式有两种后端加CrossOrigin或全局 CORS 配置前端 devServer 配代理。实际项目里最常见的做法是两边都做后端为上线留余地前端为本地开发省心。Vue 2 项目在项目根目录下新建vue.config.js配置 devServer 代理把/api前缀的请求转发到后端 8080 端口这是保持前后端分离结构最干净的方式浏览器里所有请求看起来都是相对路径不会出现 CORS。Vue 3 Vite 项目则是在vite.config.js里配置 server.proxy原理一样。两种配置细节不完全相同下面以 Vue 2 为例如果你的项目是 Vue 3照着关键词找 Vite 的 proxy 配置即可。// vue.config.js const path require(path); module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/api: } } } } };port是前端开发服务器的端口号改成 8081 是为了避免和后端 8080 冲突。proxy对象里/api是所有后端接口的前缀target指向后端服务地址changeOrigin: true会把请求头里的 Host 改写成后端域名部分后端鉴权逻辑依赖这个值。pathRewrite的作用是重写路径——如果后端接口本来就是/api/auth/login那么这里不需要 rewrite保留原路径如果后端接口是/auth/login前端请求写/api/auth/login代理过去时就得把/api剥掉。这里非常容易踩坑要先确认后端接口有没有/api前缀再决定怎么写。4.2 后端全局 CORS 配置一个类解决所有请求跨域前端代理在本地开发时解决的是“浏览器到 devServer”这一段但如果你直接用 IP 访问后端比如上线部署时 nginx 配置没做好跨域问题会再次出现。所以后端加一个全局 CORS 配置是更稳的做法。在 Spring Boot 项目里常见做法是写一个配置类实现WebMvcConfigurer覆盖addCorsMappings方法也可以用CrossOrigin注解但每个 Controller 都要加太繁琐。下面这套配置是当前最常见的全局 CORS 方案需要放在 Spring Boot 能扫描到的包下package com.example.survey.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }addMapping(/**)的含义是所有后端接口都允许跨域请求allowedOriginPatterns(*)表示允许任意来源访问注意这里不能用allowedOrigins(*)和allowCredentials(true)同时使用这是 JDK 版本的已知限制会导致启动报错。毕设项目里鉴权方式通常是前端本地存的 JWT token所以allowCredentials保持true即可。maxAge(3600)是预检请求的缓存时间单位秒设置之后同一来源的浏览器在一小时内不会重复发起 OPTIONS 预检请求能减少很多无效请求。4.3 axios 请求封装登录态从哪里来接口报错怎么统一处理后端接口联调时最常遇到的问题不是接口本身出错而是前端没有携带 token。常见做法是在 axios 的请求拦截器里取出 localStorage 或 sessionStorage 中保存的 token放到请求头 Authorization 字段里。下面是一个典型的 axios 封装片段很多项目里直接放在src/utils/request.jsimport axios from axios; const request axios.create({ baseURL: process.env.VUE_APP_API_BASE || /api, timeout: 10000 }); request.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers.Authorization Bearer token; } return config; }); request.interceptors.response.use( response response.data, error { if (error.response error.response.status 401) { localStorage.removeItem(token); window.location.href /login; } return Promise.reject(error); } ); export default request;baseURL是接口前缀开发环境走/api会被 devServer 代理生产环境可以换成完整后端地址这也是为什么推荐用环境变量而不是写死。timeout设为 10 秒问卷提交接口如果包含大量文本答案响应时间会比较长10 秒是一个折中值。请求拦截器里关键的一行是Authorization: Bearer token有些项目的后端拦截器只认token字段而不是Authorization需要对照后端的 JWT 过滤器源代码确认。响应拦截器里的401处理是一个好习惯——token 过期后自动清空登录态并跳回登录页否则用户会在问卷填写页面遇到各种莫名其妙的白屏或请求失败。4.4 一个最小可用的登录联调流程从点击按钮到页面跳转环境都立住之后完整走一遍登录联调是检验全链路最有效的方式。前端登录页表单提交时调用request.post(/auth/login, { username, password })后端返回 token 和用户信息前端把 token 存入 localStorage再通过 vue-router 跳转到问卷列表页。列表页挂载时请求request.get(/survey/list)拉取问卷数据渲染成表格。如果这一步成功说明后端数据库连接正常、接口路由正确、前端代理生效、axios 封装没有缺失后续所有功能都建立在这条链路上。如果列表页空白但登录成功优先打开浏览器开发者工具切到 Network 面板刷新页面看/survey/list请求是否发出、状态码是多少、响应体是什么。响应体如果是{code:200,data:[]}那是真的没数据如果看到 404大概率是接口路径不匹配这种问题十有八九是前端写错路径或者代理 rewrite 配置不对最容易解决但最难定位。5. 在线问卷调查系统联调避坑六个常见的翻车点与排查办法5.1 启动时报错 Port already in use不是代码问题是端口被占现象执行mvn spring-boot:run后日志提示Web server failed to start. Port 8080 was already in use.后端直接退出。原因之前启动过另一个 Spring Boot 项目或者某个进程占用了 8080 端口没有释放。解决在命令行执行netstat -ano | findstr 8080查出占用端口的 PID根据系统是 Windows 还是 Linux 杀掉对应进程后重新启动或者直接修改后端配置文件的server.port为 8081同时同步修改前端代理 target 端口。不要一遇到端口冲突就改端口先确认是不是自己之前启动的服务没关干净否则改一次端口后续所有接口配置都要跟着动。5.2 mysql 8.0 导入 5.7 的 SQL 脚本字符集和认证插件不兼容现象SQL 脚本在 MySQL 5.7 上正常执行导入 8.0 时报错Unknown collation: utf8mb4_0900_ai_ci或using password: NO之类的问题部分表现在启动后端时提示数据库连接失败。原因MySQL 8.0 的默认字符集排序规则变成 utf8mb4_0900_ai_ci而 5.7 时代的脚本写死的是 utf8mb4_general_ci同时 8.0 默认使用 caching_sha2_password 认证插件老版本连接驱动可能不认识。解决打开 SQL 脚本用编辑器全局替换utf8mb4_0900_ai_ci为utf8mb4_general_ci在 pom.xml 里把 mysql-connector-java 升级到 8.0.33 或对应版本如果你用的是 Spring Boot 2.7.x 以上还要留意依赖中自带驱动版本的兼容性。5.3 前端安装依赖时 node-sass 构建失败Node 版本不对现象在 Vue 2 项目根目录执行npm install后终端输出大量node-gyp错误提示gyp ERR! stack Error: Cant find Python executable或直接node-sass加载失败。原因node-sass 是一个需要本地编译的原生模块依赖 Python 和 C 编译工具链Node 版本太新时 node-sass 的二进制预编译产物不存在只能现场编译而大部分人的电脑没有安装对应的构建工具链。解决优先换 Node 版本14.17.x 或 16.15.x 是 Vue 2 node-sass 项目的稳定区间如果项目已经切换到 sassdart-sass则基本没有这个问题。不要强行在 Node 20 上编译 node-sass浪费时间且成功率很低。5.4 前端页面能打开但接口全 404代理路径和后端接口前缀对不上现象前端登录成功跳转列表页后表格一直转圈Network 面板里接口请求显示 404。原因很典型的一种情况是前端 axios 的 baseURL 是/api代理把/api重写成了空而后端真实接口路径是/survey/list最终请求变成了/survey/list路径错位另一种情况是后端接口本身就没有/api前缀但代理没做 pathRewrite请求带着/api去打后端后端自然找不到。解决先在后端 Controller 里找到登录接口的真实路径比如PostMapping(/auth/login)然后决定代理写法——后端接口带/api前缀则前端 baseURL 写/api代理直接透传不 rewrite不带前缀则前端写法不变代理打开 pathRewrite。核心原则只有一条代理之后的最终请求路径必须和后端 Controller 里的路径完全一致。5.5 提交问卷时提示未登录后端却没有任何日志前端少发了 token现象问卷填写页提交答案时前端弹出“请先登录”的提示但打开 Network 面板能看到请求正常发出后端控制台也没有异常日志。原因axios 拦截器没有生效或者 token 的 key 名不对。更隐蔽的情况是——你用的 axios 实例是在request.js里创建的但页面里却直接从axios公共库发请求绕过了拦截器。解决打开页面源码确认所有 HTTP 请求都用封装后的request对象发出再打开浏览器 Application/Local Storage 面板确认 token 的 key 名和后端拦截器的读取字段名一致。很多项目后端拦截器读的是token头部前端写的却是Authorization两边对不上就出现这种诡异的“假未登录”现象。5.6 后端能跑、前端能跳问卷列表却返回空数据数据库里根本没有前端要求的字段现象接口返回 200响应数据格式正常但列表渲染不出来或出现了字段名全部是 undefined 的表格行。原因后端实体类的字段命名是下划线风格如survey_id前端模板里写的却是驼峰surveyId两者对不上。注意如果项目使用了 MyBatis-Plus开启驼峰映射后通常能自动转换但如果手写 SQL 的 resultMap 没配全就会漏字段。解决先看后端实体类用了什么注解再对比数据库列名和前端取值字段优先在后端实体上统一加TableField(survey_id)注解或在前端模板里改成对应字段名。这个坑不涉及复杂技术但一旦碰上查起来特别费眼神。6. 项目跑通之后如何用一份演示清单证明这套系统真的可用项目能启动、能登录、能提问卷之后不要急着去改代码加功能先做一遍完整的回归演示验证所有核心链路。一个合格的在线问卷调查系统至少要能在五分钟内按顺序演示以下流程管理员登录、创建一份包含单选题、多选题、文本题的问卷、把问卷发布、退出登录、用普通用户账号注册并登录、找到该问卷并完成填写、再切回管理员账号查看统计结果。每一步都要能用一两句话说清前端页面在哪里操作、后端接口是什么、数据库哪张表的数据发生了变化。如果有人问你“为什么不用原生 JavaScript 或 JSP 做而要用前后端分离这么重的一套”你的回答锚点应该是Vue 负责问卷编辑时的动态增删题目体验Spring Boot 负责把问卷、答卷、统计结果通过 REST 接口稳定地暴露给多端MySQL 负责把结构化数据按关系模型存下来。这套技术组合解决的不仅是功能问题更是后续扩展和维护的结构问题。如果想要在答辩或面试时多一些增量亮点可以在统计报表里增加一条导出链路用 Apache POI 把问卷结果导出成 Word 文档并把每道题的选择占比生成一个简单的柱状图图表画进去。POI 的 XWPFDocument 支持在文档中插入图片而柱状图的生成可以借助 JFreeChart 渲染成 BufferedImage 后写入 Word。这个功能的好处是它同时覆盖了文件生成、图表渲染、数据聚合三个能力点不需要额外引入复杂的报表组件工作量控制在 200 行左右的代码就能完成。这也恰好回应了“Java POI word 能生成图表吗”这个问题的核心思路——POI 本身不画图表但用 JFreeChart 先画出图片再把图片嵌进 Word是 Java 生态里最不折腾的常规做法。而如果要继续深挖剩下的路无非三条把问卷系统的权限模型从简单的角色字段换成 Spring Security 细粒度权限控制把原本存 JSON 的答卷表拆成明细表配合定时任务做统计聚合或者把前后端分别打包后用 nginx 部署到服务器上把本地能跑变成线上能访问。这三条路每一条都能让这套课程项目向生产级迈一小步但做之前一定要评估自己的时间。我个人的习惯是无论多小的项目跑通后先写一份 README 放在项目根目录记录三件事环境版本、启动命令、演示账号。这件事能让你三个月后回来看这个项目时少花一个下午重新“考古”也能让答辩老师或接手的人不用猜你的项目怎么跑。希望这篇笔记帮到你把你手上那套源码从“能打开”变成“能讲清楚、扛得住追问”。本文还有配套的精品资源点击获取