资讯动态

SpringBoot+Vue前后端分离开发问卷管理系统实战

发布时间:2026/10/13 13:11:52 来源:尧图企业网站定制
我做后端开发也快两年了前阵子接手了一个挺有意思的需求——给单位内部做一套调查问卷管理系统。领导当时给的需求就三句话能发问卷、能填问卷、能看结果。听起来很简单对吧但真正动手做起来才发现一个看起来简单的问卷系统从题型设计、问卷编辑、逻辑跳转到数据统计每一环都藏着不少细节。这个项目最终的技术组合是 java springboot vue elementui maven mysql也就是常说的前后端分离架构。我把它完整做了下来从数据库设计到前后端联调再到服务器部署中间踩了不少坑也总结了不少经验。这篇文章就把整个项目的设计思路、核心实现、踩坑记录都整理出来希望能给正在做类似管理系统、或者准备做毕业设计/个人项目的朋友一些参考。1. 需求梳理与功能边界问卷系统不只是发问卷很多人一听到调查问卷系统第一反应是不就是表单吗。实际上真实业务场景里的问卷系统远比想象中复杂。我先把需求一层层拆开明确功能边界这一步直接决定了后面数据库怎么设计、接口怎么划分。1.1 从业务角色倒推功能模块任何管理系统先搞清楚有哪几类人用。这套问卷系统里有三类角色管理员负责创建问卷、管理问卷状态、查看所有统计数据、管理用户账号。管理员是系统的核心使用者权限最大。普通用户受访者登录后可以查看分配给自己的问卷、填写问卷、查看自己参与过的历史记录。访客可选有些场景下问卷需要对外匿名发放不需要登录也能填写。这类场景要单独考虑。这三类角色决定了系统至少要拆出以下模块问卷管理创建、编辑、发布、关闭、删除、问卷填写答题、校验、提交、数据统计图表展示、导出、用户管理、权限控制。1.2 问卷本身的实体关系问卷系统最核心的领域模型是这样的一份问卷survey包含多个题目question每个题目包含多个选项option用户提交的每一份答卷answer_sheet包含多条答案记录answer_detail。这里最容易犯的错误是图省事把题目和选项设计成冗余字段存JSON。小规模demo可以这么做但一旦涉及问卷编辑增删改题目、题目排序、题型多样化JSON方案改起来非常痛苦。我最终选择了规范的关系型设计宁可多几张表也不要后面返工。1.3 功能优先级排序需求评审时我按优先级把功能排了个序优先级功能说明P0问卷CRUD、发布/关闭没有这些系统跑不起来P0在线填写问卷核心业务动作P0答案统计与图表看结果这个需求P1用户登录与权限管理内部系统的安全底线P1问卷逻辑跳转某些题目答案决定后续题目是否显示P2数据导出Excel方便线下二次分析P2问卷模板复用同类型问卷不必反复创建先把P0和P1做扎实P2作为迭代版本的功能。这个思路很重要尤其是个人开发一上来就想把所有功能做全反而容易烂尾。2. 技术选型思考SpringBootVue这对组合凭什么省心技术选型这块我在动手前专门做了对比。这不是拍脑袋定的每个选择背后都有实际考量。2.1 后端为什么选SpringBootJavaWeb领域的后端框架绕不开Spring家族。SpringBoot相比传统SSHSpring MVC Hibernate最大优势是自动配置和起步依赖。传统SSM搭建一个项目要手动配置web.xml、spring配置文件、数据源、事务管理器半天时间就耗在配置上了SpringBoot一个starter依赖搞定内置Tomcat打包直接java -jar就能跑。对于这种中小型管理系统开发效率提升非常明显。另外SpringBoot生态成熟Spring Security、MyBatis-Plus、Spring Data JPA这些轮子都无缝集成。我做的是管理系统权限控制是刚需Spring Security JWT这套方案很稳定社区资料也多遇到问题基本都能搜到答案。2.2 前端为什么选VueElementUI前端框架当时在Vue和React之间犹豫了一下。最终选Vue核心原因是ElementUI这套组件库。问卷管理系统有大量表单类页面——问卷编辑页、答题页、用户管理页这些页面天生适合用现成的UI组件快速搭建。ElementUI的el-form、el-table、el-dialog、el-tree几乎覆盖了管理系统90%的界面需求不需要自己从零写下拉框和表格。Vue的双向数据绑定对表单场景尤其友好。问卷编辑时题型切换、选项增删数据响应式更新体验非常顺滑。选项多的时候不用像原生JS那样手动操作DOM维护成本低很多。2.3 Maven和MySQL的角色Maven负责依赖管理和项目构建这没啥好说的多模块项目尤其需要。MySQL则承担所有结构化数据存储。问卷和答案数据天然是结构化的关系型数据库是合适的选择。有人可能问为什么不用MongoDB存问卷JSON我的理由是题目和选项需要频繁地增删改查关系型模型更清晰事务也更有保障。比如一份问卷发布后要统计每个题目的参与人数SQL一句GROUP BY就出来了用非关系型反而绕。2.4 整体架构图逻辑分层没画流程图我用文字把逻辑分层说清楚前端层Vue ElementUI Axios ↓ HTTP JSON 后端控制器层RestController ↓ 服务层业务逻辑、事务管理 ↓ 数据访问层MyBatis-Plus Mapper ↓ MySQL数据库前端只负责界面渲染和交互后端只暴露RESTful接口互不干扰。这样一来小程序端、移动端H5后续要接入直接复用后端接口就行不用改业务逻辑。3. 数据库设计问卷系统的表结构是怎么一步步定下来的数据库设计是整个项目的基石。表结构不对后面写代码就是灾难。我分了两步走先画ER关系再写建表SQL。3.1 核心表设计概览最终我设计了6张核心表外加2张辅助表表名用途关键字段sys_user用户表id, username, password, role, statussurvey问卷表id, title, description, status, create_time, deadlinequestion题目表id, survey_id, type, title, sort_order, requiredquestion_option选项表id, question_id, option_text, sort_orderanswer_sheet答卷表id, survey_id, user_id, submit_timeanswer_detail答案明细表id, answer_sheet_id, question_id, content辅助表是survey_publish问卷发布记录表记录发给了哪些人、什么时候发布的和 user_survey_status用户问卷完成状态表标记某人是否已填写某份问卷。3.2 为什么答案表要拆成answer_sheet和answer_detail这是整个设计里最关键的决策。一开始我图方便设计了一张answer表字段是survey_id user_id question_id answer_content每个题目一行记录。后来仔细一琢磨发现问题很大统计查询时没法区分谁填的和哪次填的。比如同一份问卷允许用户修改答案后再次提交那用户的两次提交混在一起无法区分是哪一次的。所以必须拆成两张表answer_sheet代表一次提交行为记录整体信息哪个用户、哪份问卷、什么时间提交的answer_detail记录这次提交里每个题目分别填了什么通过answer_sheet_id关联。这样每次提交生成一个sheet下面的detail只属于那一次提交逻辑非常清晰。3.3 题型设计用type字段扩展而非建多张表问卷系统支持的题型有单选题、多选题、填空题、下拉题、日期题。我当时考虑过每种题型建一张表后来否掉了——太笨重而且问卷编辑器的逻辑会变得极其复杂。我采用的办法是在question表加一个type字段用字符串区分SINGLE单选、MULTIPLE多选、TEXT填空、SELECT下拉、DATE日期。单选题和多选题的选项存在question_option表里填空和日期题则没有选项记录。答案明细表里加一个content字段统一存答案字符串——单选题存选项ID多选题存多个选项ID逗号拼接填空题直接存文本。这里有个要注意的点多选题的答案怎么存。最规范的做法是每个选项一条记录用question_id option_id来标记。但这样会带来一个麻烦——同一道多选题用户勾了3个选项答案明细表里就插入3条记录统计时还得按答案分组去重。我权衡了一下选择了逗号拼接的方案配合FIND_IN_SET函数做统计开发效率高很多。缺点是如果要精确分析同时选了A和B的人有多少SQL写起来麻烦。对于目前的需求规模这种做法完全够用后续真有复杂分析需求再调整。3.4 建表SQL要点与索引设计核心建表SQL节选如下CREATE TABLE survey ( id bigint(20) NOT NULL AUTO_INCREMENT, title varchar(200) NOT NULL COMMENT 问卷标题, description text COMMENT 问卷说明, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 0草稿 1发布 2关闭, create_user_id bigint(20) DEFAULT NULL COMMENT 创建人, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT问卷表; CREATE TABLE question ( id bigint(20) NOT NULL AUTO_INCREMENT, survey_id bigint(20) NOT NULL COMMENT 所属问卷ID, type varchar(20) NOT NULL COMMENT 题目类型, title varchar(500) NOT NULL COMMENT 题目标题, required tinyint(1) NOT NULL DEFAULT 1 COMMENT 是否必填, sort_order int(11) NOT NULL DEFAULT 0 COMMENT 排序, PRIMARY KEY (id), KEY idx_survey_id (survey_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT题目表;索引这块我的经验是查询条件里最常用的字段一定要建索引。survey表按status筛选要建idx_statusquestion表按survey_id查询要建idx_survey_idanswer_detail表按answer_sheet_id查询索引同理。但不要过多建索引每个索引都是写性能的负担。问卷系统的数据量不会到千万级三四个核心索引足够了。字符集我统一用了utf8mb4而不是utf8。原因很简单utf8mb4是真正的4字节UTF-8能存emoji表情。问卷答案里用户可能会输入emoji用utf8会直接报错或者乱码。这是个很容易踩的小坑大家建表时记住就好。4. 后端核心业务逻辑实现从接口设计到事务控制数据库设计好了后端开发就顺畅多了。这节我讲几个核心模块的实现思路包括接口RESTful规范、问卷编辑的保存逻辑、发布/关闭的状态流转、以及答案提交的事务处理。4.1 项目分层与依赖配置后端用Maven构建Java版本用1.8稳定SpringBoot 2.x全兼容。pom.xml里核心依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt/artifactId version0.9.1/version /dependency持久层我选了MyBatis-Plus而不是JPA。个人习惯是MyBatis-Plus的代码生成器和条件构造器能省掉大量重复的CRUD代码。相比JPASQL可控性更强后期要写复杂统计SQL也更直接。分层结构controller接口层、service业务层、mapper数据层、entity实体、dto数据传输对象。每层职责单一不建议跨层调用。4.2 RESTful接口设计接口设计直接参考RESTful风格以下是我最终定的核心接口清单方法路径功能POST/api/survey创建问卷PUT/api/survey/{id}更新问卷草稿状态DELETE/api/survey/{id}删除问卷POST/api/survey/{id}/publish发布问卷POST/api/survey/{id}/close关闭问卷GET/api/survey/{id}获取问卷详情含题目选项GET/api/survey/page分页查询问卷列表POST/api/answer/submit提交答卷GET/api/statistics/{surveyId}获取问卷统计数据接口设计的一个原则是让前端拿到一次渲染页面所需的全部数据。比如获取问卷详情接口返回的结构应该包含题目、选项、题目类型、是否必填前端拿到就能直接渲染答题页面不用再发多个请求拼接数据。4.3 问卷编辑的保存策略整存整取问卷编辑是前端交互最复杂的模块。用户可能给问卷加题目、删题目、改题目类型、拖动排序、增删选项。这些操作如果每一步都走后端接口那需要设计题目级的增删改查接口数量爆炸事务也不好管理。我的方案是整存整取前端编辑器维护一份完整的问卷结构JSON点保存时一次提交整个问卷到后端后端先删除原有题目和选项再重新插入新数据。这个操作包在同一个事务里保证一致性。Transactional(rollbackFor Exception.class) public void saveOrUpdateSurvey(SurveyDTO dto) { // 1. 保存或更新问卷基本信息 Survey survey new Survey(); BeanUtils.copyProperties(dto, survey); surveyMapper.insertOrUpdate(survey); // 2. 删除旧的题目和选项 questionMapper.deleteBySurveyId(survey.getId()); // 3. 重新插入题目和选项 ListQuestionDTO questions dto.getQuestions(); if (CollectionUtils.isNotEmpty(questions)) { for (QuestionDTO q : questions) { Question question new Question(); BeanUtils.copyProperties(q, question); question.setSurveyId(survey.getId()); questionMapper.insert(question); // 插入选项 if (CollectionUtils.isNotEmpty(q.getOptions())) { for (String opt : q.getOptions()) { QuestionOption option new QuestionOption(); option.setQuestionId(question.getId()); option.setOptionText(opt); optionMapper.insert(option); } } } } }这套方案的实时性不强但逻辑简单可靠。要注意的是只允许在草稿状态编辑问卷。一旦问卷发布用户已经开始填写题目就不能再改了。发布状态下编辑要么禁止要么强制生成一个新版本。我选择的是简单粗暴——发布后只有关闭问卷这一个操作改题目必须关闭问卷再编辑然后重新发布。这样能避免数据混乱毕竟问卷系统的核心是数据有效性和一致性不是编辑体验。4.4 答案提交的事务与防重复答案提交是数据一致性要求最高的接口。一个用户填完一份问卷会同时插入一条answer_sheet记录和多条answer_detail记录。这些操作必须放在同一个事务里任何一条失败都整体回滚否则就会出现答卷主记录存在但答案明细缺失的脏数据。我额外处理了一个容易忽略的问题防重复提交。用户可能手抖点两次提交或者网络差导致重试后端没有幂等控制的话会产生重复的答卷记录。实现方案是前端控制加后端兜底。前端用loading状态禁用提交按钮这是常规操作。后端则在提交接口里先查user_survey_status表如果该用户对这份问卷已经有已完成标记就直接拒绝Transactional(rollbackFor Exception.class) public void submitAnswer(AnswerSubmitDTO dto) { String username SecurityUtils.getCurrentUsername(); Long surveyId dto.getSurveyId(); // 防重复已提交过则直接返回 Integer status userSurveyStatusMapper.getStatus(username, surveyId); if (status ! null status 1) { throw new BusinessException(您已经填写过该问卷); } // 插入答卷主记录 AnswerSheet sheet new AnswerSheet(); sheet.setSurveyId(surveyId); sheet.setUsername(username); answerSheetMapper.insert(sheet); // 插入答案明细 for (AnswerItemDTO item : dto.getAnswers()) { AnswerDetail detail new AnswerDetail(); detail.setAnswerSheetId(sheet.getId()); detail.setQuestionId(item.getQuestionId()); detail.setContent(item.getContent()); answerDetailMapper.insert(detail); } // 更新完成状态 UserSurveyStatus statusRecord new UserSurveyStatus(); statusRecord.setUsername(username); statusRecord.setSurveyId(surveyId); statusRecord.setStatus(1); userSurveyStatusMapper.insertOrUpdate(statusRecord); }这个防重复方案在用户同时点了两次提交这种极端情况下还是存在并发漏洞——两个请求都查到status为空然后都插入成功。真要彻底解决得靠数据库的唯一约束或者Redis分布式锁。我当时的处理是在user_survey_status表上建了(username, survey_id)唯一索引利用数据库自身保证不会重复。这也属于一个典型的生产环境经验能用数据库约束解决的问题别指望代码逻辑100%不出错。5. 前端页面开发VueElementUI让问卷编辑不再是难事后端接口就绪后前端开发正式进场。前端我按页面维度规划登录页、问卷列表页、问卷编辑页、问卷填写页、数据统计页。最核心的两个页面是问卷编辑页和填写页前者交互复杂后者体验要求高。5.1 前端工程结构与路由设计前端用Vue CLI搭建后面升级到Vite也顺路由直接采用vue-router页面级路由如下const routes [ { path: /login, component: Login }, { path: /survey/list, component: SurveyList, meta: { requiresAuth: true } }, { path: /survey/edit/:id, component: SurveyEdit, meta: { requiresAuth: true, role: ADMIN } }, { path: /survey/fill/:id, component: SurveyFill, meta: { requiresAuth: true } }, { path: /survey/statistics/:id, component: SurveyStatistics, meta: { requiresAuth: true, role: ADMIN } }, ];路由守卫配合后端JWT做权限控制路由跳转前检查本地有没有token没有就重定向到登录页。管理角色才能进入编辑和统计页面普通用户只能看到待填写问卷列表。接口请求统一封装了Axios实例所有请求自动带上Authorization请求头响应拦截器统一处理401token过期和500错误提示。这一步非常重要能省掉每个页面重复的错误处理代码。5.2 问卷编辑页动态表单的核心实现问卷编辑页是前后端开发中工作量最大的页面。用户需求是能看到问卷的题目列表可以添加/删除/编辑题目可以设置题型可以添加选项可以上下移动题目。ElementUI在这块帮了大忙。我用v-for循环渲染一个题目数组每个题目是一个卡片卡片内部根据题型动态渲染不同的编辑控件。单选/多选题型显示选项列表每个选项是一个输入框加删除按钮填空/日期题型直接显示一个输入框提示。核心逻辑代码大致这样div v-for(question, index) in questionList :keyquestion.id el-card classquestion-card div classquestion-header span第{{ index 1 }}题/span el-select v-modelquestion.type changehandleTypeChange(question) el-option label单选题 valueSINGLE/el-option el-option label多选题 valueMULTIPLE/el-option el-option label填空题 valueTEXT/el-option /el-select el-button typetext clickmoveUp(index)上移/el-button el-button typetext clickmoveDown(index)下移/el-button el-button typetext classdanger clickremoveQuestion(index)删除/el-button /div el-input v-modelquestion.title placeholder请输入题目标题/el-input div v-ifquestion.type SINGLE || question.type MULTIPLE div v-for(opt, optIndex) in question.options :keyoptIndex classoption-row el-input v-modelquestion.options[optIndex] placeholder选项内容/el-input el-button typetext clickremoveOption(question, optIndex)删除/el-button /div el-button clickaddOption(question)添加选项/el-button /div /el-card /div关键点在于数据驱动的思维页面上的所有编辑操作本质都是对questionList这个数组的操作。添加题目就是push一个对象删除题目就是splice上移下移就是交换数组元素位置。最后点保存按钮时直接把questionList序列化提交给后端接口。5.3 问卷填写页题型动态渲染与校验填写页和编辑页类似也是动态渲染但多了校验逻辑。用户提交前必须检查所有必填题是否已答。ElementUI的表单校验功能在动态场景下要特殊处理——每个题目对应的prop是动态的比如answers[3]代表第4题。我当时用了一个比较讨巧的方案不用ElementUI的复杂校验规则而是在提交前手动遍历题目列表检查必填题答案是否为空为空则用el-message提示并滚动定位到对应题目。实现思路如下function validateAnswers() { for (let i 0; i questionList.length; i) { const q questionList[i]; const answer answerMap[q.id]; if (q.required (!answer || answer.length 0)) { ElMessage.warning(第${i 1}题是必填题); return false; } } return true; }多选题的答案我处理成数组提交前join(,)变成字符串传给后端。单选直接存选中值。5.4 数据统计页ECharts图表让结果一目了然看结果这个需求我一开始直接用表格展示答案明细但被业务方吐槽看不出什么趋势。后来引入了ECharts做可视化效果好了很多。单选/多选题目用饼图展示各选项占比填空题用列表展示所有回答整份问卷的回收情况用柱状图展示每日提交量。ECharts的用法很成熟Vue里直接用echarts包在mounted钩子获取数据后初始化图表即可mounted() { this.fetchStatistics().then(data { const chart echarts.init(document.getElementById(pieChart)); chart.setOption({ series: [{ type: pie, data: data.pieData }] }); }); }一个要注意的坑是统计接口的数据结构最好专门设计别指望前端拿原始答题记录自己算。我把统计逻辑全放在后端SQL里后端算好了给前端返回各选项的投票数量和占比。原因很简单前端处理量大而且多选题的统计逻辑放在前端又慢又容易出bug。6. 实测中踩过的坑从分页失效到事务回滚任何项目写代码只是开始联调和测试才是真正磨人的阶段。这套问卷系统我踩了不少坑有些是低级错误有些是设计时没考虑到的场景。我把有代表性的几个写出来给大家提个醒。6.1 MyBatis-Plus分页插件没配置导致分页失效这是我项目里第一个玄学问题。问卷列表页要实现分页我按照MyBatis-Plus的文档引入了分页插件结果发现数据压根不分页selectPage方法返回的总记录数永远是0但数据却全量返回了。排查了一圈发现问题在配置类上。MyBatis-Plus的分页功能必须显式注册MybatisPlusInterceptor并且添加PaginationInnerInterceptor。我一开始只引入了依赖没写配置类所以分页插件根本没生效Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }这个坑比较典型——很多框架功能都需要额外配置不是引入依赖就自动生效的。建议大家遇到类似问题时第一步先检查配置类有没有写全不要一上来就怀疑框架本身。6.2 事务只加在Controller层导致的部分更新问题问卷保存接口我一开始图省事把Transactional注解加在了Controller层的方法上。当时想着反正一个方法就一个操作加上事务应该也行。结果联调时出现了一个诡异场景新增问卷时题目插入成功了但选项插入抛了异常最终数据库里出现了有题目没选项的半截数据。查了半天发现原因很经典Transactional注解加在Controller层Spring AOP的代理对象没有拦截到导致事务注解根本没有生效。Spring事务的底层是AOP代理只有通过代理对象调用的方法事务增强才会生效而且官方推荐把事务注解加在Service层的业务方法上。修复方式很简单把事务注解移到Service层的saveOrUpdateSurvey方法上。这个坑让我养成了一个习惯——凡是涉及多表写入的方法第一步先确认事务在Service层方法上而且方法必须是public。6.3 问卷填写时的XSS过滤问题问卷系统有个特殊的安全隐患填空题答案会原样显示在统计页面和问卷详情里。如果用户恶意提交一段JavaScript代码在统计页面会直接执行——这就是典型的存储型XSS攻击。我在提交接口里加了一道过滤对答案内容做HTML转义。具体是写了一个工具方法把、、、、这些特殊字符替换成HTML实体。同时前端渲染时也用{{ }}插值而不是v-htmlVue默认会转义。双保险下基本堵住了这个漏洞。权限这块我用的Spring Security JWT方案。密码存储用BCrypt加密登录后签发JWT接口通过拦截器校验token。角色权限用PreAuthorize(hasRole(ADMIN))注解控制。这套方案是目前Java后端最主流的做法网上教程很多我这里不展开细说但提醒一句管理系统的每一个写接口都必须做权限校验别只在前端隐藏按钮。6.4 ElementUI表格大数据量渲染卡顿问卷填写页如果题目数量特别多比如超过50题页面上所有题目一次性渲染出来会出现明显的卡顿。用户每输入一个字符都略微延迟体验很差。我的优化方案有两个一是分页展示题目每页显示10题用户答题翻页类似考试系统二是用v-show代替v-if来切换题目区域减少重复组件销毁重建的开销。分页方案虽然简单但用户翻页时已填数据必须保留。所以我把所有题目的答案统一存放在一个answerMap对象里翻页只影响当前显示哪些题目不对数据做任何清理。这样既解决了性能问题又保证了数据安全。7. 发布部署与后续维护从本地跑到服务器上线项目开发完成后还要经过部署上线这一关。这一步很多个人开发者容易忽略但恰恰是生产环境运行质量的关键。7.1 Maven打包与前后端分离部署后端打包非常简单Maven生命周期的package命令直接打出可执行jar包。需要注意的是打包前确认profile环境。我在application.yml里配置了开发环境和生产环境用spring.profiles.active切换数据源。生产环境连接的是服务器上的MySQL账号密码通过环境变量注入不写死在配置文件里。部署方案我采用了经典的Nginx SpringBoot方式前端打包后生成dist目录里面的静态文件放到Nginx的html目录下后端jar包在服务器上执行nohup java -jar survey-system.jar 启动Nginx配置反向代理/api路径转发到后端的8080端口同时解决跨域问题server { listen 80; server_name your-server-ip; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }前后端分离部署最大的好处是互不影响前端只负责静态资源后端只管API。升级时前端替换静态文件、后端重启服务各自独立操作。7.2 数据备份与回收策略问卷系统的数据是业务的核心资产备份不能马虎。我设置了两个层面第一MySQL每天凌晨自动mysqldump全量备份备份文件保留7天第二核心表survey、answer_sheet、answer_detail做定期数据完整性检查确保没有孤儿数据。另外有一个数据增长的问题每份问卷的answer_detail记录数等于提交人数 × 题目数。一份100人填写的30题问卷会产生3000条明细记录。如果问卷很多数据量增长很快。我的处理是为热门问卷增加归档机制——关闭超过半年的问卷明细数据自动归档到历史表主表只保留热数据查询性能能一直维持在较好水平。7.3 后续可以扩展的方向这套系统目前满足了基本需求但迭代空间还很大。我自己列了几个后续想做的方向供大家参考逻辑跳转功能根据上一题答案动态显示/隐藏后续题目这需要前端在填写页增加条件判断逻辑后端数据结构已经预留了字段问卷模板市场把常用的满意度调查、员工考核问卷做成模板创建时一键引用Excel导出用EasyExcel将问卷明细数据导出为Excel方便业务方离线分析批量分发发布问卷时按组织架构批量选择人员自动生成待办通知我个人做这个项目的体感是调查问卷系统看着简单但作为一个完整的前后端分离案例它覆盖了CRUD、事务管理、权限控制、复杂表单交互、数据可视化、安全防护、部署运维等几乎所有Web开发的常见知识点。如果你现在在学SpringBoot和Vue准备找个项目练手这个选题非常合适——难度适中又不至于简单到没东西写回事。做完这一套你对前后端分离开发的理解会上一个大台阶。最后再分享一个小的实操心得开发过程中一定要尽早前后端联调不要等后端全部写完再写前端。我当时是后端每完成一个模块就立刻和前端对接调试这样接口设计有问题能第一时间发现改起来成本也低。项目做到后面你会发现最耗时间的往往不是写代码而是前后端接口的沟通和联调——早发现、勤沟通是项目顺利交付的关键。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑