用Spring Boot+JPA快速搭建问卷提交接口的核心是定义结构化DTO与实体模型,避免Map接收和时间类型误用,多选题推荐关联表存储。

如何用 Spring Boot + JPA 快速搭建问卷提交接口
核心是避免从零写 HTTP 解析和数据库映射。Spring Boot 的 @RequestBody 能直接绑定 JSON 表单数据,JPA 的 @Entity 可对应问卷、题目、回答三张表。
常见错误是把所有字段塞进一个大 JSON 对象里,导致后续统计困难。正确做法是拆成结构化模型:
-
Survey:含 id、title、created_at -
Question:含 id、survey_id、text、type("single", "multiple", "text") -
Answer:含 id、question_id、respondent_id、value(String)、choices(JSON 数组,仅 multiple 用)
提交时前端发类似这样的 JSON:
{
"survey_id": 1,
"answers": [
{"question_id": 1, "value": "Java"},
{"question_id": 2, "choices": [1, 3]},
{"question_id": 3, "value": "喜欢模块化设计"}
]
}
为什么不能直接用 Map 接收表单数据
看似灵活,实则埋雷。JPA 不会自动识别 Map 中的嵌套结构,保存时要么报 IllegalArgumentException,要么存成 BLOB 失去查询能力。
立即学习“Java免费学习笔记(深入)”;
更严重的是类型丢失:前端传 "age": "25",后端 Map 里拿到的是 String,但业务上它该是 Integer——校验、排序、聚合全会出错。
正确做法是定义 DTO 类,用 @JsonProperty 显式声明字段,并配合 @Valid 做基础校验:
public class SubmitRequest {
private Long survey_id;
@Valid
private List answers;
// getter/setter
}
public class AnswerItem {
private Long question_id;
private String value;
private List choices;
}
MySQL 存储多选题答案的两种方式及取舍
多选题选项(如“你常用哪些框架?[ ]Spring [ ]MyBatis [ ]Netty”)的答案存储,容易踩坑。
方案一:用 JSON 字段(如 JSON 类型或 TEXT 存字符串)
- 优点:写入快,结构灵活
- 缺点:MySQL 5.7+ 才支持
JSON_CONTAINS,旧版本只能用LIKE模糊查,无法走索引;导出做 BI 分析时解析成本高
方案二:建关联表 answer_choice(answer_id, option_id)
- 优点:可高效统计“选了 Spring 又选了 Netty 的人数”,支持外键约束和联合索引
- 缺点:插入需两步(先插
Answer,再批量插answer_choice),代码稍多
推荐方案二,尤其当问卷要支持后台筛选导出时。
前端传时间戳,后端怎么避免时区错乱
用户在东八区填完问卷点提交,前端 JS 用 new Date().toISOString() 发 "2024-06-15T08:30:00.000Z",后端若用 LocalDateTime 接收,会丢掉 Z(UTC 标识),变成系统默认时区时间,入库后可能偏差 8 小时。
必须统一用 Instant 或 ZonedDateTime:
- DTO 字段声明为
private Instant submit_time; - JPA 实体对应字段用
@Column(columnDefinition = "TIMESTAMP WITH TIME ZONE")(PostgreSQL)或datetime(MySQL,靠应用层保证 UTC) - 配置 Jackson:
spring.jackson.time-zone=UTC,确保反序列化不偏移
别依赖 java.util.Date,它已被 Instant 更清晰地替代。
复杂点在于历史问卷数据迁移和前端兼容——如果已有老系统用毫秒数传时间,后端得加 @JsonDeserialize 适配器,这点常被忽略。










