Spring Boot(Java)多对多关联场景下新增Employee时POST请求报415 Unsupported Media Type错误
嗨,我来帮你排查这个415错误的问题,顺便也聊聊多对多关联的序列化/反序列化配置,毕竟你还提到了GET请求要展示双向关联数据的需求~
先搞懂415错误的核心原因
415 Unsupported Media Type本质上是服务器无法处理你发送的请求体格式,结合你的场景,我把可能的原因和解决步骤按优先级排序:
1. 先排查最容易踩的坑:请求头和请求体格式
这是415错误最常见的触发点,先快速验证:
- 检查Content-Type请求头:
不管用Postman还是Curl,必须确保请求头里包含Content-Type: application/json。- Postman:在「Headers」标签里手动添加这个键值对,不要漏;
- Curl:加上
-H "Content-Type: application/json"参数,比如:curl -X POST -H "Content-Type: application/json" -d '{"name":"张三"}' http://localhost:8080/employees
- 简化请求体测试:
先不要在POST Employee的请求体里带assignedProjects字段,只传Employee的基础属性(比如name、email),比如:
如果这样能成功,说明是请求体里的关联项目数据导致反序列化失败;如果还是报415,那肯定是请求头或JSON语法的问题(比如引号不配对、逗号漏写)。{ "name": "John Doe", "email": "john@example.com" }
2. 调整Jackson注解,同时解决循环引用和双向展示需求
你当前用的@JsonManagedReference和@JsonBackReference虽然能解决循环引用,但有个问题:被@JsonBackReference标记的属性会被反序列化忽略,而且序列化时也不会返回,这就导致你GET Project的时候看不到关联的Employee列表,不符合你的需求。
推荐换成@JsonIdentityInfo注解,它能让双向关联的实体在序列化时互相展示,同时用对象ID标记避免循环引用:
修改Employee实体
import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; import jakarta.persistence.*; import java.util.HashSet; import java.util.Set; @Entity @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; @ManyToMany @JoinTable( name = "youtube-dev-2-prod-coding-employee_project", joinColumns = @JoinColumn(name = "employee_id"), inverseJoinColumns = @JoinColumn(name = "project_id") ) private Set<Project> assignedProjects = new HashSet<>(); // 构造方法、getter、setter省略 }
修改Project实体
import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; import jakarta.persistence.*; import java.util.HashSet; import java.util.Set; @Entity @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") public class Project { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String description; @ManyToMany(mappedBy = "assignedProjects") private Set<Employee> employeeSet = new HashSet<>(); // 构造方法、getter、setter省略 }
这样调整后:
- GET
/employees/{id}会返回该员工的所有关联项目; - GET
/projects/{id}会返回该项目的所有关联员工; - 反序列化时也不会因为双向关联导致解析失败,完美匹配你的需求。
3. 检查Controller接口定义
确保你的Employee新增接口正确使用了@RequestBody注解,Spring需要这个注解来把JSON请求体转换为Java对象:
import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/employees") public class EmployeeController { private final EmployeeService employeeService; // 构造注入 public EmployeeController(EmployeeService employeeService) { this.employeeService = employeeService; } @PostMapping public ResponseEntity<Employee> createEmployee(@RequestBody Employee employee) { Employee savedEmployee = employeeService.saveEmployee(employee); return ResponseEntity.ok(savedEmployee); } }
如果漏了@RequestBody,Spring会把请求体当成URL参数解析,直接触发415错误。
4. 日志调试(如果以上都没解决)
如果还是报错,可以开启Jackson的调试日志,看具体是哪个字段解析失败:
在application.properties里添加:
logging.level.com.fasterxml.jackson=DEBUG logging.level.org.springframework.http.converter.json=DEBUG
启动项目后重新发送POST请求,查看控制台日志,Jackson会输出详细的反序列化错误信息(比如某个字段不存在、类型不匹配)。
最后总结
先从请求头和请求体格式入手排查415,这是最快速的解决路径;然后调整Jackson注解为@JsonIdentityInfo,既能解决双向展示的需求,又能避免循环引用导致的序列化/反序列化问题。
内容来源于stack exchange

