Spring Boot序列化问题:新增ChoicesDTO仅需传入问题ID而非完整QuestionDTO
解决新增时仅传入Question的idQ而非完整DTO的问题
这里提供几种实用的解决思路,按需选择:
方案1:拆分请求与响应DTO(推荐)
你的ChoicesResponseDTO更适合作为响应专用DTO(包含完整的Question详情),而新增操作属于请求场景,完全可以单独创建一个请求专用DTO,只保留必要字段:
@Data @AllArgsConstructor @NoArgsConstructor public class CreateChoicesRequestDTO { private Long idR; private ChoicesResponseType choicesResponseType; // 仅保留问题ID,无需嵌套完整的QuestionDTO private Long questionId; }
在新增接口里接收这个请求DTO,业务层再把questionId转换成对应的Question实体/DTO即可。这种方式符合单一职责原则,避免DTO混用导致的参数冗余问题。
方案2:通过Jackson注解控制反序列化
如果不想新增DTO,可以直接通过Jackson注解调整字段的序列化/反序列化规则:
方式A:给QuestionDTO字段设置访问权限
修改QuestionDTO,让只有idQ允许被反序列化(即接收请求时只需要这个字段),其他字段仅用于序列化(返回响应时展示):
@Data @AllArgsConstructor @NoArgsConstructor public class QuestionDTO { // 允许写入(反序列化),读取(序列化)不受限 @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) private Long idQ; // 仅允许读取(序列化),反序列化时忽略 @JsonProperty(access = JsonProperty.Access.READ_ONLY) private String contentQ; @JsonProperty(access = JsonProperty.Access.READ_ONLY) private Integer ordreQ; }
此时新增请求只需要传入{"questionDTO": {"idQ": 123}}即可,Swagger生成的Schema也会自动更新,不再要求传入其他Question字段。
方式B:自定义构造方法配合@JsonCreator
在ChoicesResponseDTO里添加一个接收questionId的构造方法,让Jackson可以直接解析扁平化的参数:
@Data @AllArgsConstructor @NoArgsConstructor public class ChoicesResponseDTO extends ResponseDTO { private Long idR; private ChoicesResponseType choicesResponseType; private QuestionDTO questionDTO; // 标记为Jackson可用的构造方法 @JsonCreator public ChoicesResponseDTO( @JsonProperty("idR") Long idR, @JsonProperty("choicesResponseType") ChoicesResponseType choicesResponseType, @JsonProperty("questionId") Long questionId ) { this.idR = idR; this.choicesResponseType = choicesResponseType; this.questionDTO = new QuestionDTO(); this.questionDTO.setIdQ(questionId); } }
现在请求可以直接传"questionId": 123,不用嵌套questionDTO对象,Swagger也会同步显示这个字段。
方案3:自定义Jackson反序列化器
如果需要更灵活的参数解析逻辑(比如同时支持嵌套questionDTO.idQ和扁平化questionId两种传参方式),可以写一个自定义反序列化器:
public class ChoicesResponseDeserializer extends StdDeserializer<ChoicesResponseDTO> { public ChoicesResponseDeserializer() { super(ChoicesResponseDTO.class); } @Override public ChoicesResponseDTO deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); ChoicesResponseDTO dto = new ChoicesResponseDTO(); dto.setIdR(node.get("idR").asLong()); dto.setChoicesResponseType(ChoicesResponseType.valueOf(node.get("choicesResponseType").asText())); // 兼容两种传参方式:嵌套的questionDTO.idQ 或 直接的questionId Long questionId; if (node.has("questionDTO") && node.get("questionDTO").has("idQ")) { questionId = node.get("questionDTO").get("idQ").asLong(); } else { questionId = node.get("questionId").asLong(); } QuestionDTO questionDTO = new QuestionDTO(); questionDTO.setIdQ(questionId); dto.setQuestionDTO(questionDTO); return dto; } }
然后在ChoicesResponseDTO上指定使用这个反序列化器:
@Data @AllArgsConstructor @NoArgsConstructor @JsonDeserialize(using = ChoicesResponseDeserializer.class) public class ChoicesResponseDTO extends ResponseDTO { private Long idR; private ChoicesResponseType choicesResponseType; private QuestionDTO questionDTO; }
内容的提问来源于stack exchange,提问作者Fares Salhi
相关产品推荐
相关产品推荐

