news 2026/10/30 6:56:10

基于Spring Boot的在线问卷调查系统源码解析与二次开发实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Spring Boot的在线问卷调查系统源码解析与二次开发实践

简介:面向Java Web初学者与Spring Boot实战者的在线问卷调查系统源码包,围绕问卷模板创建、问卷编辑发布、社交网络分享、结果统计与个人中心等模块,提供从用户认证授权到RESTful接口设计的完整参考实现。包内共294个文件,以100个Java源码、26个HTML页面、26个JavaScript脚本以及CSS、SQL、properties配置文件为主,并含图片、字体、图标等静态资源,压缩包约37.17MB,前后端与数据库相关文件分布较清晰,便于按模块查阅。目前已有269人学习下载,适合用于课程设计、毕业设计或框架练手,也可作为Spring Security鉴权、Spring Data JPA持久化与前后端联调的对照案例。读者可据此梳理Spring Boot项目的分层结构、实体与数据表映射、登录注册流程、问卷增删改查和图表统计的实现思路,也能参考静态资源组织与接口联调方式,快速搭建可运行的调查问卷应用原型。

1. 从一份“回收了 87 张表格”的调研说起

去年有个做市场的朋友找我,说他们每季度做一次客户满意度调研,问卷往群里一发,回收上来是几十份填好的 Excel,人工合并、去重、数票,两天时间就搭进去了,还容易数错。后来他们内部有人丢过来一份基于 Spring Boot 的在线问卷调查系统源码,问能不能直接改改就用。我看完的第一反应是:这类系统功能看着简单——建问卷、发链接、填、看统计,但它真正难的地方从来不在页面上,而在题目类型的扩展性、答卷的幂等控制、以及统计口径的一致性。这套源码把这三件事的骨架都搭好了,Spring Boot + MyBatis-Plus + MySQL 的组合也很容易接手,适合两类人:一类是想拿它当毕设或课程项目底稿的学生,另一类是真要在内部跑一份调研、又不想上 SaaS 的团队开发者。接下来我按自己拆项目的顺序,从技术选型一路讲到怎么改。

2. 定位与技术选型:这套系统为什么用 Spring Boot 打底

2.1 它解决的是“问卷全生命周期”,不是“表单页”

先把功能边界说清楚,不然后面看代码容易迷路。这套系统的核心对象只有四个:问卷(Survey)、题目(Question)、选项(Option)、答卷(Answer)。四个对象串起来是一条完整的状态链——新建问卷是草稿态,配好题目后发布,发布后生成一个可访问的作答入口,用户提交后形成答卷记录,最后按题目维度做聚合统计。中间还夹着两个容易被忽略但很关键的动作:问卷截止(超过时间窗或人为关闭后不再接收新答卷),以及答卷去重(同一个人对同一份问卷只能提交一次)。

所以它不是那种“拖拽生成一个表单、提交进数据库就完事”的轻量工具。你在源码里能看到问卷状态字段、开始结束时间、题目排序号、是否必答、答卷来源 IP 这些字段,这些都是为“一次严肃的调研”准备的。如果只是想收集个报名信息,用这套系统属于杀鸡用牛刀;但只要涉及多选题、评分题、结果要出图表、还要防止有人刷票,它的结构就比临时拼的表单合理得多。

模块划分上,源码大致是这么几块:用户与权限(登录、角色)、问卷管理(增删改查、发布、截止)、题目管理(题型、选项、排序)、作答端(渲染问卷、提交校验)、统计端(单题汇总、交叉筛选、导出)。有些版本还会带一个简答的模板库或者问卷复制功能,这个看你拿到的包,不影响主干理解。你接手时最该先看的是问卷和题目这两块的 Service,它们是整个系统的中枢。

2.2 技术栈拆解:每一层各自扛什么

选型上没有花活,是一套很典型的国内中小型管理系统组合,好处是资料多、上手快、出问题好查。

层次技术在这套系统里的职责
Web 框架Spring Boot 2.x提供内嵌容器、自动配置、统一异常处理、拦截器
持久层MyBatis-Plus单表 CRUD 走 BaseMapper,复杂统计手写 XML
数据库MySQL 5.7 / 8.0存问卷、题目、选项、答卷、答案明细
视图层Thymeleaf 或 Vue + Element管理端表格 + 作答端表单渲染
权限拦截器 / Spring Security管理端登录态校验,作答端通常放行
统计图表ECharts单选多选出饼图柱状图,评分题出均值

这里有两个选型点值得单独说一下,因为它们直接影响你后面改代码的手感。

第一是 MyBatis-Plus 而不是纯 JPA。原因是统计查询太多,比如“某问卷每道题的每个选项被选了多少次”,这种 SQL 用 JPA 拼起来很别扭,而 MyBatis 可以直接在 XML 里写一段带 GROUP BY 的原生 SQL,改起来直观。代价是单表 CRUD 要靠代码生成或者手写 Mapper,Power by MyBatis-Plus 的BaseMapper<T>能省掉大部分样板代码,所以常见做法是:单表操作走BaseMapper,聚合统计走自定义 XML。

第二是作答端用服务端渲染还是前后端分离。这取决于你拿到的包,但两种各有取舍:Thymeleaf 渲染的好处是链接直接可访问、不需要额外部署前端工程,缺点是题目动态渲染(尤其是逻辑跳转)写起来啰嗦;Vue 版本的好处是题目组件化、交互流畅,缺点是本地跑起来要同时起两个服务。如果你只是想快速验证功能,优先找带 Thymeleaf 的那份;如果要做二次开发、加复杂交互,Vue 版本更值得投入。

2.3 本地跑通:从建库到看到第一份问卷

跑起来的顺序不要乱,先库后服务,不然启动就报错。第一步建库,字符集用utf8mb4,这个别省,问卷标题里出现表情符号或者生僻字时,utf8会直接抛异常,这是我踩过的坑。第二步导入源码里的 SQL 脚本,一般包含建表语句和一条管理员初始数据。第三步改application.yml里的数据源,第四步启动。

server: port: 8080 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/survey?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver thymeleaf: cache: false # 开发期关掉模板缓存,改页面不用重启 mybatis-plus: mapper-locations: classpath*:mapper/*.xml configuration: map-underscore-to-camel-case: true # survey_id 自动映射 surveyId

配置里有几个参数值得留意。serverTimezone必须显式指定,否则 MySQL 8 驱动在某些环境下会把时间整体偏移 8 小时,表现出来就是“刚发布的问卷显示已截止”,非常唬人。map-underscore-to-camel-case打开后,数据库的下划线字段才能自动映射到实体的驼峰属性,如果关掉,你会看到一堆字段全是 null,但 SQL 明明查出了数据。thymeleaf.cache在开发期关掉,改 HTML 刷新即生效,省掉反复重启。

启动命令就一条,如果包里有 Maven Wrapper 就用 wrapper:

# 打包并启动,跳过测试加快首次启动 ./mvnw clean package -DskipTests java -jar target/survey-0.0.1-SNAPSHOT.jar

启动成功后访问http://localhost:8080,用初始管理员账号登录,进管理端新建一份问卷、加两道题、点发布,然后用无痕窗口打开作答链接提交一份,再回管理端看统计页。这条链路走通,说明库、服务、模板、统计四个环节都是通的,后面再看代码就有底了。

3. 目录结构与数据模型:五张表撑起整个系统

3.1 包结构:按层切还是按业务切

源码的包结构大概率是经典的三层切法,这也是这类项目最常见的组织方式:

com.example.survey ├── controller # 管理端与作答端接口 ├── service # 业务逻辑,接口 + impl ├── mapper # MyBatis-Plus Mapper 接口 ├── entity # 数据库实体 ├── dto # 请求参数,如 SubmitDTO、SurveyQueryDTO ├── vo # 返回给前端的聚合对象,如 StatVO ├── config # 拦截器、跨域、MyBatis-Plus 配置 └── common # 统一返回体、异常、工具类

说句实在话,按层切在项目初期没什么问题,但写到后面你会发现SurveyService越来越胖,发布、复制、统计、导出全塞在一起。我的习惯是接手后先别急着重构,等业务稳定了再把“统计”单独拆一个StatService,把“导入导出”拆一个ExportService。因为统计逻辑最容易被反复改口径,独立出来之后改动半径小,也不会误伤发布流程。

另外提醒一下entity和dto一定要分开。很多初版代码图省事,前端参数直接用实体接,结果提交答卷时前端多传一个id,就把已有题目覆盖了。这个坑在答题接口上尤其危险,因为答题端是公开访问的,参数完全不可信。

3.2 五张核心表:字段设计的取舍

建表脚本是理解这个项目最快的方式。核心就五张表,我把关键字段摘出来:

CREATE TABLE t_survey ( id BIGINT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(120) NOT NULL, description VARCHAR(500) NULL, status TINYINT NOT NULL DEFAULT 0 COMMENT '0草稿 1已发布 2已截止', start_time DATETIME NULL COMMENT '为空表示不限开始', end_time DATETIME NULL COMMENT '为空表示不限结束', creator_id BIGINT NOT NULL, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除标记' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE t_question ( id BIGINT PRIMARY KEY AUTO_INCREMENT, survey_id BIGINT NOT NULL, type TINYINT NOT NULL COMMENT '1单选 2多选 3填空 4评分 5矩阵', title VARCHAR(255) NOT NULL, required TINYINT NOT NULL DEFAULT 0, sort_no INT NOT NULL DEFAULT 0, options_json TEXT NULL COMMENT '选项列表,JSON 数组', KEY idx_survey (survey_id, sort_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE t_answer ( id BIGINT PRIMARY KEY AUTO_INCREMENT, survey_id BIGINT NOT NULL, user_key VARCHAR(64) NOT NULL COMMENT '登录用户ID或匿名设备指纹', submit_ip VARCHAR(45) NULL, submit_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_survey_user (survey_id, user_key) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE t_answer_item ( id BIGINT PRIMARY KEY AUTO_INCREMENT, answer_id BIGINT NOT NULL, question_id BIGINT NOT NULL, content VARCHAR(1000) NULL COMMENT '文本答案', option_keys VARCHAR(255) NULL COMMENT '选中的选项 key,多选用逗号分隔', score INT NULL COMMENT '评分题的分数', KEY idx_question (question_id), KEY idx_answer (answer_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这几张表的字段设计里有三个决定,值得展开讲。

第一个是t_answer上的唯一索引uk_survey_user。这个索引是防刷票的最后一道闸门,比起在 Service 里先查后插,靠数据库唯一约束更可靠,因为并发下“先查再插”会有窗口期,两个人同时提交能双双插进去。代价是插入冲突会抛DuplicateKeyException,你得在全局异常处理里把它翻译成“您已提交过本问卷”,而不是把 500 抛给用户。

第二个是t_question.options_json用 JSON 存选项。这个选择在问卷系统里非常常见,原因是选项永远跟着题目走,从不单独查询,拆成独立表反而要每次 JOIN 一次。但它有个代价:统计时没法直接 JOIN 选项表,选项的展示文案得从 JSON 里解析出来再和聚合结果拼。这在代码里体现为统计 Service 里多一步内存合并,不算大问题。

第三个是deleted逻辑删除。问卷一旦发布过、有人答过,物理删除就会把答卷变成孤儿数据,所以逻辑删除是必须的。注意配合 MyBatis-Plus 的@TableLogic注解使用,否则你手写的 SQL 还得自己加deleted = 0,漏一处就查出脏数据。

3.3 题目类型怎么扩展:一个枚举撑起五种题型

题型扩展性是这个系统能不能长期用的关键。源码里一般会有一个QuestionType枚举,把题型和它的校验规则、渲染方式绑定在一起:

public enum QuestionType { SINGLE(1, "单选"), MULTI(2, "多选"), TEXT(3, "填空"), SCORE(4, "评分"), MATRIX(5, "矩阵"); private final int code; private final String label; QuestionType(int code, String label) { this.code = code; this.label = label; } public static QuestionType of(int code) { for (QuestionType t : values()) { if (t.code == code) return t; } throw new BizException("未知题型: " + code); } }

这段代码本身没什么技术含量,但它定了一个规矩:题型用 code 存库、用枚举在内存里流转,前端传的永远是 code,服务端永远先经过of()翻译一次。这个规矩的价值在于,将来加“排序题”“文件上传题”时,你只需要在枚举里加一项,然后在提交校验和统计聚合两处各补一个分支,而不是满项目搜type == 1。

我在别的项目里见过反面例子:题型判断直接写成if (q.getType() == 1)散落在六七个类里,后来要加一种题型,改了十几处还漏了两处,上线后统计页直接空白。血泪经验就是,凡是这种固定集合的字段,第一件事就是把它变成枚举,哪怕初期只有两个值。

4. 核心链路拆解:一次作答提交到底走了哪些代码

4.1 发布与截止:状态机比 if 判断靠谱

问卷的状态流转看着简单,实际上是最容易写乱的地方。草稿可以编辑题目,已发布不能改题目结构(改了会让历史答卷对不上),已截止只能看统计。如果不用状态机,代码里就会出现“这个方法里判断了三次状态”的情况。

常见做法是把状态判断收拢成一个校验方法:

public void checkPublishable(Survey survey) { if (survey.getStatus() != SurveyStatus.DRAFT.getCode()) { throw new BizException("只有草稿状态的问卷可以发布"); } Long count = questionMapper.selectCount( new LambdaQueryWrapper<Question>().eq(Question::getSurveyId, survey.getId())); if (count == null || count == 0) { throw new BizException("问卷至少需要一道题目才能发布"); } // 单选题必须有选项,这里只做抽样校验,完整校验遍历题目 }

checkPublishable里做了两件事:校验当前状态是否允许发布,以及校验问卷内容是否完整。之所以把内容校验放在发布这一步而不是保存草稿时,是因为草稿本来就是半成品,你没法要求用户一次填完;但发布出去意味着要给别人答了,这时候一道没有选项的单选题会让作答页直接崩掉。

截止逻辑同理,不要写成定时任务扫描(虽然可以),更稳的做法是在作答入口处做时间窗判断。因为定时任务有执行间隔,中间那几分钟用户还是能提交;而入口处判断是即时的。这两条一起用最保险:入口判断拦住正常流量,定时任务负责把过期问卷的状态刷成“已截止”,让列表页显示正确。

4.2 作答提交:事务、幂等、校验三件套

这是整个系统最容易出问题的接口,因为它同时要处理并发、事务和用户输入校验。我把典型实现拆开看:

@Transactional(rollbackFor = Exception.class) public Long submit(SubmitDTO dto, String userKey, String ip) { Survey survey = surveyMapper.selectById(dto.getSurveyId()); // 1. 状态与时间窗校验 if (survey == null || survey.getStatus() != SurveyStatus.PUBLISHED.getCode()) { throw new BizException("问卷不存在或未发布"); } LocalDateTime now = LocalDateTime.now(); if (survey.getEndTime() != null && now.isAfter(survey.getEndTime())) { throw new BizException("问卷已截止"); } // 2. 落主表,唯一索引兜底防重复提交 Answer answer = new Answer(); answer.setSurveyId(dto.getSurveyId()); answer.setUserKey(userKey); answer.setSubmitIp(ip); try { answerMapper.insert(answer); } catch (DuplicateKeyException e) { throw new BizException("您已提交过本问卷"); } // 3. 逐题落明细,必答题在这里兜底校验 List<Question> questions = questionMapper.selectList( new LambdaQueryWrapper<Question>().eq(Question::getSurveyId, dto.getSurveyId())); for (Question q : questions) { AnswerItem item = buildItem(answer.getId(), q, dto.getItem(q.getId())); answerItemMapper.insert(item); } return answer.getId(); }

代码不长,但三个点必须说透。

事务边界:整个方法包在一个事务里,任何一道题落库失败都整体回滚,避免出现“主表有记录但明细缺一半”的脏数据。rollbackFor = Exception.class不能省,因为默认只回滚RuntimeException,如果你自定义的BizException继承了Exception而不是RuntimeException,异常抛出去事务却不回滚,这个问题极难排查。

幂等控制:靠唯一索引而不是先查后插。注意这里捕获的是DuplicateKeyException,只有真正插入时撞索引才触发,并发下两个人同时点提交,数据库只放行一个。userKey的取值是个设计点——登录用户用用户 ID,匿名用户用设备指纹或者前端生成并落到 localStorage 的 UUID,后者防不住刻意刷票,但能挡住正常用户的手抖重复提交。真要做严格的一人一票,得靠登录态。

必答校验:在遍历题目时对required = 1的题判断答案是否为空,为空直接抛业务异常。这一步必须在服务端做,前端那点required属性随手就能绕过,不能当安全边界。

4.3 统计聚合:别在 Java 里数循环

统计页是这类系统的门面,也是最容易写出性能问题的地方。我见过一种写法:把某个问卷的所有answer_item一次性查进内存,然后 for 循环按questionId分组、再按选项计数。问卷几十份的时候没问题,上千份之后内存直接顶上去,而且每次刷新都全量算一遍。

正确做法是把聚合下推到数据库:

-- 单选/多选题:每个题目下每个选项被选中的次数 SELECT ai.question_id, o.opt_key, COUNT(*) AS cnt FROM t_answer_item ai JOIN t_question q ON q.id = ai.question_id JOIN t_answer a ON a.id = ai.answer_id WHERE a.survey_id = #{surveyId} AND q.type IN (1, 2) AND FIND_IN_SET(o.opt_key, ai.option_keys) > 0 GROUP BY ai.question_id, o.opt_key;

不过这段 SQL 有个前提——选项得能 JOIN 出来。前面说了选项存在 JSON 字段里,所以实际代码里通常是两步:先用一条 SQL 把各选项的计数查出来,再在 Service 里从options_json解析出选项文案,按 key 合并成前端要的[{name, value}]结构。多选因为存在option_keys里是逗号分隔的字符串,用FIND_IN_SET展开,这个函数用不上索引,数据量大的时候会慢,这是这套设计的固有代价。

评分题的口径又不一样,不能数选项,要算均值和分布:

SELECT question_id, AVG(score) AS avg_score, MIN(score) AS min_score, MAX(score) AS max_score, COUNT(*) AS total FROM t_answer_item WHERE question_id IN (#{ids}) AND score IS NOT NULL GROUP BY question_id;

统计里最容易被忽略的是分母。一道非必答题,如果 100 人里有 20 人没填,那这道题的有效样本是 80 不是 100,百分比必须按 80 算。这个口径要在代码里显式处理,否则统计出来的比例加起来不到 100%,运营同事会来问你为什么。

4.4 作答页渲染:题目顺序与跳转逻辑

作答端要做的不只是把题目循环渲染出来,还得处理排序和条件跳转。排序靠sort_no,SQL 里ORDER BY sort_no ASC即可,简单。真正麻烦的是逻辑跳转——比如“第 3 题选了 A 就跳到第 5 题”。这类功能在源码里可能没有,但属于二次开发的高频需求。

实现思路是在题目上挂一个next_rule字段(JSON),存“选了某选项后跳转到哪道题”,前端在选项变化时读取规则决定下一步渲染哪题。这里有个血泪教训:跳转逻辑一定要前后端一致,前端跳了但后端按全量题目校验必答,用户就会被卡在“你有一道没见过的题没填”。正确做法是后端在提交时按同一套跳转规则算出“实际生效的题目集合”,只对这个集合做必答校验。这种前后端规则各写一遍、又不同步的情况,是这类系统上线后最常见的投诉来源。

5. 避坑与排查:五个真实踩过的坑

5.1 数据层:时间差 8 小时与中文变问号

现象:刚发布的问卷,作答页直接提示“问卷已截止”,可结束时间明明设在一周后。原因:JDBC URL 没配serverTimezone,MySQL 8 驱动按 UTC 解析,写入的时间和读取的时间差了 8 小时。解决:URL 里显式加serverTimezone=Asia/Shanghai,同时确认数据库服务器的时区,两者要对齐。这个问题在本地开发机上可能不出现(因为机器时区恰好一致),一部署到别的环境就爆,属于典型的“环境玄学”。

现象二:问卷标题里的中文存进库变成问号或者乱码。原因:建库时用了utf8字符集,连接串也没指定characterEncoding。解决:建库语句统一DEFAULT CHARSET=utf8mb4,连接串带上characterEncoding=utf8mb4,三处(库、表、连接)必须一致,缺一处都可能出问题。

5.2 提交链路:重复提交与事务不回滚

现象:网络卡顿时用户连点两次提交,数据库里出现两条同问卷的答卷,统计数字翻倍。原因:只在 Service 里做了“先查是否已提交”,两个请求并发进来时都查到“没提交过”。解决:加唯一索引uk_survey_user兜底,同时前端提交按钮点击后置灰;后端把DuplicateKeyException捕获后返回友好提示。索引是硬约束,代码是软约束,两个都要。

现象二:提交时某道题校验失败抛出业务异常,用户重新提交后发现主表多了一条答卷记录但没有明细。原因:自定义异常继承的是Exception,而@Transactional默认只回滚RuntimeException。解决:要么让业务异常继承RuntimeException,要么显式写rollbackFor = Exception.class。这个坑不看日志根本发现不了,因为接口返回的是正常的错误提示。

5.3 统计与展示:口径错位和空数据崩页

现象:管理端统计页某道题百分比加起来是 92%,运营来问是不是算错了。原因:这道题非必答,有 8% 的人跳过,分母用了总答卷数而不是该题的有效答卷数。解决:聚合 SQL 里按question_id分组时,分母取该题的非空记录数,Java 侧不要再二次换算。

现象二:新发布的问卷还没人答,点开统计页直接白屏报 500。原因:图表渲染时对空数组取[0]或者对空结果做除法。解决:统计接口在没有数据时返回结构完整但数值为 0 的对象,前端图表组件做空数据兜底。这类问题在测试阶段很难发现,因为测试数据总是有的,上线后第一批用户点进来才发现。

现象三:多选题选项文案和计数对不上。原因:选项存在 JSON 里,统计结果按 key 合并时用了String比较但两边的 key 大小写或者空格不一致。解决:选项 key 在保存时就统一成小写无空格的固定格式(比如opt_1、opt_2),不要用选项文案本身当 key。

6. 二次开发:先加一道题型,再谈重构

接手这类源码,我的建议是先做一次“最小改造”来熟悉结构,而不是上来就重构。最合适的练手目标是加一种题型——比如“排序题”或者“文件上传题”。整个改造路径能让你把实体、Mapper、Service、前端渲染全走一遍,而且改动可控。

具体步骤是这样:先在QuestionType枚举里加一项;然后在t_question表上不用改结构(options_json复用),但t_answer_item需要存更长的内容时得确认字段长度够;接着在提交校验的分支里加一条,排序题的答案必须包含全部选项且不重复;统计层则要决定口径,排序题通常不出饼图,而是看“每个选项排在首位的次数”。这一圈改下来,你对代码里哪些地方是“开着的”哪些是“焊死的”就有判断了。

如果要做的是面向真实业务的改造,我列几个优先级:

改造项价值改动面
作答链接加短码链接短、便于分享小,加一列 + 一个跳转接口
答卷导出 Excel运营刚需中,引入 EasyExcel,按题目动态出列
逻辑跳转长问卷体验大,前后端都要改
交叉分析(按某题筛选)分析深度中,统计 SQL 加条件参数
问卷模板复制重复建问卷省事小,深拷贝问卷和题目

优先做导出和复制,这两个投入产出比最高,而且不碰核心链路,改坏了也不影响用户提交。逻辑跳转放最后,因为它会同时改动作答页渲染、必答校验、统计口径三处,是典型的高风险改造。

验证方法上,我的习惯是每次改完核心链路,手动走一遍“新建 → 发布 → 无痕提交 → 重复提交 → 看统计 → 截止后再提交”这条完整链路,六步缺一不可。自动化测试能覆盖大部分,但重复提交和截止后提交这两个边界,手动点一遍心里才有底。从那以后我每次改动提交接口,都强制走一遍这六步,哪怕只改了一个字段名——因为这类系统的错误往往不报错,只是数字悄悄不对,等发现的时候已经回收了几百份脏答卷了。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/30 6:53:37

pixel-wifi-captive-portal

Pixel 连接 WiFi 提示"网络连接受限"的排查与解决 基于 Pixel 3(Android 12 AOSP)真机的完整排查记录 一、问题现象 一台运行原生 Android(AOSP)的 Pixel 3,连接家庭 WiFi(运营商光猫)后: WiFi 状态显示"已连接",IP、网关、DNS 均已正常获取但系统提示 “…

作者头像 李华
网站建设 2026/10/30 6:52:50

AlibabaCloudLinux2/CentOS7安装Python3.13

序&#xff1a; 公司测试机安装Python3一直报错&#xff0c;记录一下。 1. 安装pyenv # 1. 安装 pyenv&#xff08;需先装编译依赖&#xff0c;同上&#xff09; # curl https://pyenv.run | bash git clone https://gitee.com/mirrors/pyenv.git ~/.pyenv# 2. 配置环境变量…

作者头像 李华
网站建设 2026/10/30 6:51:58

招聘站JS逆向卡壳?Playwright+AST组合拳,控制流平坦化也能轻松拆

做行业人才供需分析项目的时候&#xff0c;碰过某头部招聘站的岗位详情接口&#xff0c;所有请求都带一个动态sign参数&#xff0c;有效期几分钟&#xff0c;改一下岗位ID直接返回403。最开始走了老路&#xff1a;抓包、搜关键词、扒混淆JS硬啃&#xff0c;结果对方做了控制流平…

作者头像 李华
网站建设 2026/10/30 6:51:34

企业知识库的FAQ怎么写:从一个具体问题开始(原生端验收)

企业知识库里有很多资料&#xff0c;并不意味着员工能够快速找到可用答案。搜索结果可能很长&#xff0c;问题却很具体&#xff1a;服务适用于哪些情况&#xff0c;办理之前要准备什么&#xff0c;遇到例外应该联系谁。FAQ可以帮助团队把资料整理成便于查找和确认的问答。 一、…

作者头像 李华
网站建设 2026/10/30 6:50:40

2026家电经销商系统怎么选?真实数据、价盘返利、订单履约全解析

家电行业渠道以"层级多、客单高、服务重、价盘敏感"为特征&#xff0c;经销商既是销量主力&#xff0c;也是品牌商最想看清却又最难看清的环节。进入2026年&#xff0c;家电以旧换新、下沉市场与全渠道融合持续推进&#xff0c;品牌商对经销商的数字化管控从"可…

作者头像 李华