Spring Boot POST请求映射报错:不支持的媒体类型问题排查
嵌套JSON请求的媒体类型不支持问题排查与解决
问题描述
我在Postman中发送如下嵌套结构的JSON请求:
{ "title": "the", "type": "MCQ", "teacher_id": "2", "questions" : [{ "content": "Who are you", "answers":[{ "content": "you", "correct" : "true" }] }], "status": "OPEN" }
尝试切换媒体类型后仍无法请求到对应接口,怀疑问题出在包含answers列表的questions嵌套结构上,收到的错误信息:
"error": "Unsupported Media Type", "trace": "org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type 'application/json;charset=UTF-8'"
相关代码
Exam实体类
package com.academy.exams.entity; import com.fasterxml.jackson.annotation.JsonManagedReference; import jakarta.annotation.PostConstruct; import jakarta.persistence.*; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import java.util.List; @Entity @Table(name = "Exam") public class Exam { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "exam_id") private Long examId; private String title; @Enumerated(EnumType.STRING) private ExamType type; @JsonManagedReference @OneToMany(mappedBy = "exam", cascade = CascadeType.ALL) private List<Question> questions; @Column(name = "teacher_id") private Long teacherId; private String status; public Long getId() { return examId; } public void setId(Long examId) { this.examId = examId; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public ExamType getType() { return type; } public void setType(ExamType type) { this.type = type; } public List<Question> getQuestions() { return questions; } public void setQuestions(List<Question> questions) { this.questions = questions; } public Long getTeacherId() { return teacherId; } public void setTeacherId(Long teacherId) { this.teacherId = teacherId; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } @PostConstruct public void init() { System.out.println("Exam initialized"); } }
仓库接口
@Repository public interface ExamRepository extends JpaRepository<Exam, Long> {}
服务层代码
public Exam CreateExam(Exam exam){ return examRepository.save(exam); }
控制器代码
package com.academy.exams.controller; import com.academy.exams.entity.Exam; import com.academy.exams.service.ExamService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/exams") public class ExamController { @Autowired private ExamService examService; @PostMapping("/create") public Exam createExam(@RequestBody Exam exam){ return examService.CreateExam(exam); } }
Question实体类
package com.academy.exams.entity; import com.academy.exams.entity.Exam; import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import java.util.List; @Entity @Table(name = "Question") public class Question { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "question_id") private Long questionId; @Column(name = "content") private String content; @JsonBackReference @ManyToOne @JoinColumn(name = "exam_id") private Exam exam; @JsonBackReference @OneToMany(mappedBy = "question", cascade = CascadeType.ALL) private List<Answer> answers; public Long getId() { return questionId; } public void setId(Long id) { this.questionId = questionId; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Exam getExam() { return exam; } public void setExam(Exam exam) { this.exam = exam; } public List<Answer> getAnswers() { return answers; } public void setAnswers(List<Answer> answers) { this.answers = answers; } }
Answer实体类
package com.academy.exams.entity; import com.fasterxml.jackson.annotation.JsonManagedReference; import jakarta.persistence.*; @Entity @Table(name = "Answer") public class Answer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name ="answer_id") private Long answerId; private String content; @Column(name="correct") private Boolean correct; @JsonManagedReference @ManyToOne @JoinColumn(name = "question_id" ) private Question question; public Long getId() { return answerId; } public void setId(Long answerId) { this.answerId = answerId; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Boolean getCorrect() { return correct; } public void setCorrect(Boolean correct) { this.correct = correct; } }
问题排查与解决
1. JSON字段与实体类属性不匹配
- 请求中的
teacher_id是字符串类型"2",但Exam实体类的teacherId是Long类型,序列化时会触发类型转换失败; - 请求中的
correct是字符串"true",但Answer实体类的correct是Boolean类型,同样会导致解析失败,最终引发媒体类型不支持的异常(Spring无法解析请求体时会抛出该错误); - 字段名不匹配:请求中的
teacher_id与实体类的teacherId不对应,Jackson默认采用驼峰映射规则。
解决:
修改请求JSON为以下格式:
{ "title": "the", "type": "MCQ", "teacherId": 2, "questions" : [{ "content": "Who are you", "answers":[{ "content": "you", "correct" : true }] }], "status": "OPEN" }
2. Jackson双向引用注解错误
Question实体类中answers字段使用@JsonBackReference,Answer实体类的question字段使用@JsonManagedReference,这会导致嵌套的answers无法被正确反序列化。正确的配置应该是:一对多关系中,一方(Question)的集合字段用@JsonManagedReference,多方(Answer)的引用字段用@JsonBackReference。
解决:
修改Question实体类的answers字段注解:
@JsonManagedReference @OneToMany(mappedBy = "question", cascade = CascadeType.ALL) private List<Answer> answers;
修改Answer实体类的question字段注解:
@JsonBackReference @ManyToOne @JoinColumn(name = "question_id" ) private Question question;
3. Postman请求配置检查
- 确保请求方法为POST,URL正确指向
/exams/create; - 在Headers中设置
Content-Type: application/json,无需额外添加charset=UTF-8参数; - 选择Raw格式发送JSON,避免使用其他格式。
4. 依赖检查
确认项目的pom.xml(或build.gradle)中包含spring-boot-starter-web依赖,它默认集成了Jackson相关模块,确保未排除Jackson组件。
内容的提问来源于stack exchange,提问作者JaCoffee
相关产品推荐
相关产品推荐

