毕业设计实战:基于SSM+MySQL的问卷调查系统,避开这些坑轻松搞定毕设!

61 阅读11分钟

毕业设计实战:基于SSM+MySQL的问卷调查系统,避开这些坑轻松搞定毕设!

当初做问卷调查系统毕设时,我被“试题选项动态生成”卡了整整一周——一开始把选项写死在数据库里,结果用户想改个选项都得改代码重部署,导师看了直接摇头说“这系统一点都不灵活”😫 后来踩遍所有坑,才总结出这套从需求到测试的完整流程。今天就把问卷调查系统的实战经验全部分享出来,宝子们跟着做,毕设轻松搞定!

一、需求分析别瞎猜!先搞懂“谁发问卷,谁答问卷”

最开始我跳过需求分析,花两周写了个“智能问卷推荐算法”,结果导师一句“核心是问卷创建、试题管理、答题统计,不是推荐算法”直接打回重做!后来才明白,问卷调查系统的核心就是 “管理员发,用户答” ,必须抓住这两个角色的核心需求。

1. 核心用户 & 核心功能(踩坑后总结版)

问卷调查系统就两类核心用户:管理员(问卷发布者)和普通用户(答题者)。千万别加“数据分析员”、“审核员”等复杂角色!我当初加了后,权限管理一团糟,最后全砍掉才顺畅。

  • 管理员端(后台管理,必须做的功能):

    • 用户管理:维护答题用户信息(查看/冻结/重置密码)、按姓名/注册时间筛选。
    • 问卷管理:这是核心中的核心
      • 问卷创建:设置问卷名称、答题时长、结束语、问卷状态。
      • 试题管理:为每个问卷添加试题(单选、多选、简答)、设置试题排序。
      • 问卷发布:控制问卷是否开放答题。
    • 数据统计:查看每份问卷的答题情况(参与人数、答题详情)。
    • 新闻资讯管理:发布系统公告、新闻动态。
    • 字典管理:维护问卷类型、试题类型等基础数据。
  • 用户端(答题者前台,核心功能):

    • 问卷列表:查看所有可参与的问卷,按发布时间排序。
    • 问卷答题:这是用户端核心
      • 进入问卷后显示倒计时。
      • 逐题显示(单选显示单选按钮,多选显示复选框,简答显示文本框)。
      • 支持暂存答案、提交问卷。
    • 我的答题记录:查看已参与的问卷列表及答题时间。
    • 个人信息管理:修改密码、完善个人信息。

2. 需求分析避坑指南(血泪教训!)

  • 别空想,要模拟!找两个同学,一个扮演发问卷的管理员,一个扮演答题用户。模拟过程中,用户反馈“答到一半断网了,回来得重头答”,我才增加了“答案暂存”功能(每答一题自动保存到本地存储)。这比我自己想的“答题进度条动画”实用多了。
  • 一定要画用例图!用DrawIO简单画一下,标清楚“用户-参与问卷”、“管理员-查看统计结果”。跟导师汇报时,图形比干讲半小时逻辑清晰10倍。
  • 写个简单的需求清单:列出“功能点+约束条件”。比如:
    • “问卷答题有时长限制,超时自动提交”
    • “同一用户同一问卷只能答一次”
    • “单选/多选题目选项可动态配置”
    • “简答题有字数限制(如500字以内)” 编码时就对着这个清单做,不会跑偏。

3. 可行性分析(三句话说清楚,让导师点头)

  • 技术可行性:Java、SSM框架(Spring+SpringMVC+MyBatis)、MySQL都是学校教过的。遇到问题,网上资料一堆。避坑提示:别用太新的Spring 6.x,和MyBatis兼容性还在磨合,就用稳定的SSM组合。
  • 经济可行性:所有工具全免费!IDEA社区版、MySQL、Maven。答辩时说:“系统开发零成本,投入使用后可大幅提升问卷调查效率,节约纸质问卷成本。”
  • 操作可行性:界面参照常见的在线考试系统,流程清晰。我让室友测试,3分钟就完成了一份模拟问卷,导师觉得“用户体验良好”。

二、技术选型:稳字当头,别追新!

当初我看别人用SpringBoot,我也跟风用,结果在“试题选项动态渲染”上卡了几天。后来换回 Java 8 + SSM + MySQL 8.0 + jQuery + Bootstrap ,这套组合经久不衰,资料多,坑少。

技术栈详解与避坑

技术选择理由避坑提醒
Java 8语法稳定,企业主流,SSM完美支持。别用Java 17+,部分老框架依赖不兼容。
SSM框架经典组合,学校教过,资料丰富。Spring和MyBatis版本要匹配(Spring 5.3.x + MyBatis 3.5.x)。
MySQL 8.0免费,性能好,支持JSON字段(存试题选项很方便)。字符集一定选utf8mb4,否则用户简答里的emoji会乱码。
jQuery + Bootstrap快速搭建页面,兼容性好。Bootstrap用4.x版本,别用5.x(有些组件用法变了)。
Maven项目管理,依赖管理方便。国内镜像配阿里云的,下载快。

开发环境一步到位

  1. 安装JDK 1.8:配置好环境变量。
  2. 安装IDEA + Tomcat 9:IDEA装好Maven插件。
  3. 安装MySQL 8.0 + Navicat:建库questionnaire_system,字符集utf8mb4
  4. 创建Maven Web项目
    <!-- pom.xml核心依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.11</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.33</version>
    </dependency>
    

三、数据库设计:动态选项是关键!

我当初的坑:把试题选项直接存在examquestion_options字段里,用逗号分隔。结果用户想加个“其他,请说明”的选项都改不了表结构。后来改成JSON格式存储,灵活多了。

核心表结构设计(重点!)

-- 问卷表
CREATE TABLE `exampaper` (
  `id` int NOT NULL AUTO_INCREMENT,
  `exampaper_name` varchar(200) NOT NULL COMMENT '问卷名称',
  `exampaper_date` int DEFAULT 30 COMMENT '答题时长(分钟)',
  `exampaper_jieshuyu` text COMMENT '结束语',
  `exampaper_types` int DEFAULT 1 COMMENT '状态:1开放,2关闭',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 试题表(核心!)
CREATE TABLE `examquestion` (
  `id` int NOT NULL AUTO_INCREMENT,
  `exampaper_id` int NOT NULL COMMENT '所属问卷',
  `examquestion_name` text NOT NULL COMMENT '试题内容',
  `examquestion_options` json DEFAULT NULL COMMENT '选项(JSON数组,如["A.选项1","B.选项2"])',
  `examquestion_types` int DEFAULT 1 COMMENT '题型:1单选,2多选,3简答',
  `examquestion_sequence` int DEFAULT 0 COMMENT '排序,值越大越靠前',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `fk_exampaper` (`exampaper_id`),
  CONSTRAINT `fk_exampaper` FOREIGN KEY (`exampaper_id`) REFERENCES `exampaper` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 问卷调查记录表
CREATE TABLE `examrecord` (
  `id` int NOT NULL AUTO_INCREMENT,
  `examrecord_uuid_number` varchar(50) DEFAULT NULL COMMENT '答题流水号',
  `yonghu_id` int DEFAULT NULL COMMENT '答题用户',
  `exampaper_id` int DEFAULT NULL COMMENT '所属问卷',
  `total_score` int DEFAULT 0 COMMENT '得分(如果有计分)',
  `insert_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '提交时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_user_exam` (`yonghu_id`,`exampaper_id`) COMMENT '同一用户同一问卷只能答一次'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 答题详情表
CREATE TABLE `examredetails` (
  `id` int NOT NULL AUTO_INCREMENT,
  `examredetails_uuid_number` varchar(50) DEFAULT NULL COMMENT '关联答题流水号',
  `yonghu_id` int DEFAULT NULL,
  `examquestion_id` int DEFAULT NULL COMMENT '试题ID',
  `examredetails_myanswer` text COMMENT '用户答案',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

设计亮点

  1. examquestion_optionsJSON类型存储,前端解析方便,增减选项不用改表结构。
  2. examrecord表加了唯一约束,防止同一用户重复答题。
  3. 答题记录分两个表:examrecord记录整体,examredetails记录每题答案,便于统计。

四、功能实现:抓住核心,做出亮点

1. 管理员端:问卷与试题管理(核心)

关键逻辑:问卷和试题是父子关系,先创建问卷,再为问卷添加试题。

页面设计要点

  • 问卷列表页:表格显示所有问卷,操作列有“管理试题”、“发布/关闭”、“查看统计”。
  • 试题管理页(弹窗或独立页):
    • 显示当前问卷的所有试题,可拖拽排序。
    • 添加试题表单:题型选择(切换时动态显示不同输入框)、题目内容、选项输入(单选/多选显示选项输入框,简答不显示)。
    • 选项输入框旁有“添加选项”、“删除选项”按钮。

避坑代码(Controller层 - 添加试题)

@PostMapping("/addQuestion")
@ResponseBody
public Result addQuestion(@RequestBody Examquestion question) {
    // 1. 校验问卷是否存在且为可编辑状态
    Exampaper paper = exampaperService.getById(question.getExampaperId());
    if (paper == null || paper.getExampaperTypes() == 2) {
        return Result.error("问卷不存在或已发布,无法添加试题");
    }
    
    // 2. 根据题型处理选项
    if (question.getExamquestionTypes() == 1 || question.getExamquestionTypes() == 2) {
        // 单选或多选,校验选项不能为空
        if (question.getExamquestionOptions() == null || question.getExamquestionOptions().isEmpty()) {
            return Result.error("请至少添加一个选项");
        }
        // 这里examquestion_options字段存的已经是JSON字符串了
        // 前端传过来的是数组,MyBatis配置了JSON类型处理器会自动转换
    } else {
        // 简答题,清空选项
        question.setExamquestionOptions(null);
    }
    
    // 3. 设置排序值(新增的放在最后)
    LambdaQueryWrapper<Examquestion> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(Examquestion::getExampaperId, question.getExampaperId())
           .select(Examquestion::getExamquestionSequence);
    List<Examquestion> list = examquestionService.list(wrapper);
    int maxSeq = list.stream().mapToInt(Examquestion::getExamquestionSequence).max().orElse(0);
    question.setExamquestionSequence(maxSeq + 1);
    
    examquestionService.save(question);
    return Result.success("试题添加成功");
}

2. 用户端:问卷答题页面(核心体验)

关键逻辑:倒计时、自动保存、题型适配渲染。

页面设计要点

  • 顶部显示:问卷名称、剩余时间(红色倒计时)。
  • 试题区域:一题一题显示,下方有“上一题”、“下一题”、“暂存”、“提交”按钮。
  • 选项渲染
    • 单选:<input type="radio">
    • 多选:<input type="checkbox">
    • 简答:<textarea rows="4">
  • 底部进度条:显示已完成题数/总题数。

前端关键代码(jQuery)

// 动态渲染题目
function renderQuestion(question) {
    $('#questionTitle').text(question.examquestion_name);
    $('#optionsContainer').empty();
    
    if (question.examquestion_types == 1 || question.examquestion_types == 2) {
        // 单选或多选
        var options = JSON.parse(question.examquestion_options || '[]');
        $.each(options, function(index, option) {
            var type = question.examquestion_types == 1 ? 'radio' : 'checkbox';
            var html = '<div class="form-check">' +
                       '<input class="form-check-input" type="' + type + '" ' +
                       'name="question_' + question.id + '" value="' + index + '" id="opt_' + index + '">' +
                       '<label class="form-check-label" for="opt_' + index + '">' + option + '</label>' +
                       '</div>';
            $('#optionsContainer').append(html);
        });
    } else {
        // 简答
        $('#optionsContainer').html('<textarea class="form-control" rows="4" ' +
                                   'id="answerText" placeholder="请输入您的回答..."></textarea>');
    }
}

// 自动暂存答案(每答一题或每10秒)
function autoSave() {
    var answer = getCurrentAnswer(); // 获取当前题答案
    localStorage.setItem('temp_'+currentQuestionId, JSON.stringify(answer));
}

3. 数据统计模块(答辩亮点)

关键逻辑:按问卷统计答题情况,展示每题的选择分布。

页面设计要点

  • 选择问卷:下拉框选择要统计的问卷。
  • 总体统计:显示参与人数、平均用时、完成率。
  • 每题统计
    • 单选/多选:用柱状图或饼图显示每个选项的选择人数和百分比。
    • 简答题:列表显示所有回答(可分页)。

实现思路

-- 统计单选/多选题每个选项的选择人数
SELECT 
    eq.examquestion_name as 题目,
    eq.examquestion_options->'$[0]' as 选项A,
    COUNT(CASE WHEN ed.examredetails_myanswer LIKE '%0%' THEN 1 END) as 选A人数,
    eq.examquestion_options->'$[1]' as 选项B,
    COUNT(CASE WHEN ed.examredetails_myanswer LIKE '%1%' THEN 1 END) as 选B人数
FROM examquestion eq
LEFT JOIN examredetails ed ON eq.id = ed.examquestion_id
WHERE eq.exampaper_id = #{paperId} 
  AND eq.examquestion_types = 1
GROUP BY eq.id;

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

五、系统测试:重点测这些,答辩稳过

核心功能测试用例

测试模块测试场景操作步骤预期结果测试结论
问卷答题超时自动提交开始答题后等待超过设定时长时间到自动提交,提示“时间到”
问卷答题同一用户重复答题用同一账号再次进入已答过的问卷提示“您已参与过本次问卷调查”
试题管理动态添加选项在管理页面点击“添加选项”按钮页面动态新增一个选项输入框
数据统计查看答题分布管理员进入统计页面,选择问卷显示每题每个选项的选择人数和百分比
简答题输入超长内容在简答题输入超过500字提交时提示“字数超限”或前端实时显示字数统计

兼容性测试

  • 浏览器:Chrome、Firefox、Edge。特别注意:JSON字段的解析在不同浏览器内核下要测试。
  • 移动端:用手机浏览器访问,确保答题页面能正常显示和操作(Bootstrap默认支持响应式,但还是要测)。

六、答辩准备:讲出你的设计亮点

  1. 演示流程要完整:“大家好,我演示一个完整的问卷调查流程。首先,管理员登录创建一份‘大学生就业意向调查’问卷(展示),然后添加5道题,包括单选、多选和简答(展示动态添加选项功能)。接着,切换用户账号,进入问卷列表看到这份问卷(展示),开始答题,有倒计时提醒(展示),答完提交。最后切回管理员账号,查看这份问卷的统计结果(展示图表和数据)。”

  2. 重点讲“你解决的坑”

    • “我一开始把选项用逗号分隔存字符串,后来改用JSON格式存储,这样前端解析方便,增减选项不用改数据库结构。”
    • “为了防止用户重复答题,我在examrecord表加了(user_id, exampaper_id)的唯一约束。”
    • “简答题我做了字数限制和输入提示,避免用户输入无效内容。”
  3. 准备好问答

    • Q:为什么用SSM不用SpringBoot? A:SSM是学校课程重点,我对这套技术栈更熟悉。而且SSM的分层结构清晰,便于理解MVC模式。
    • Q:数据量大了统计会慢怎么办? A:可以给examrecord表的insert_time加索引,还可以考虑定时生成统计报表,避免实时查询大量数据。
    • Q:系统还有什么可以改进? A:可以增加问卷模板功能,方便快速创建;还可以增加数据导出功能(导出Excel)。

最后:一点真心话

问卷调查系统看起来简单,但要把用户体验做好需要很多细节考虑。关键是把“创建-答题-统计”这个核心流程做顺畅,把数据设计的灵活一点(比如用JSON存选项),你的毕设就成功了一大半。

需要项目源码(带详细注释)SQL脚本(含测试数据)答辩常见问题解答的宝子,可以在评论区留言。

觉得这篇干货有帮助,记得点赞收藏!祝大家毕设顺利,答辩一次过!💪