无web.xml配置Spring MVC时Postman请求RestController返回400错误
问题原因
400错误由配置错误+请求规则不匹配共同导致,核心诱因有三点:
- 类级别
@RequestMapping错误添加了consumes = MediaType.APPLICATION_JSON_UTF8_VALUE属性,强制该控制器下所有接口(包括无请求体的GET接口)必须匹配JSON请求的Content-Type。浏览器发GET请求时默认不带Content-Type头,Spring会跳过校验因此访问正常;Postman会记忆上次请求的Header配置,若默认带上了非JSON类型的Content-Type(如form-data、x-www-form-urlencoded),会触发校验失败(部分Spring版本下媒体类型不匹配会返回400而非标准的415状态码)。 - Spring容器分层配置错误:
@EnableWebMvc属于Spring MVC Web层的配置注解,被错误放在了根容器(RootConfig)中。根容器负责管理Service、DAO等业务持久层Bean,DispatcherServlet对应的子容器才负责管理Controller、消息转换器、参数解析器等Web层组件,配置错位会导致JSON解析、请求匹配逻辑异常。 - 若Postman发送的是POST请求,大概率是请求配置错误:未设置Content-Type为application/json、请求体JSON格式非法、字段与
Curso实体类不匹配、实体类缺少无参构造方法导致Jackson反序列化失败,都会触发400错误。
解决方法
按以下步骤逐一修复:
1. 修正控制器的请求映射配置
将consumes属性从类级别移到需要接收JSON请求体的POST方法上,避免给GET接口强加不必要的请求限制:
@RestController @RequestMapping( value = "/cursos", produces = MediaType.APPLICATION_JSON_UTF8_VALUE ) public class CursoRestController { @Autowired private CursoService cursoService; @GetMapping @ResponseStatus(HttpStatus.OK) public List<Curso> listAll() { System.out.println("Test"); return cursoService.findAll(); } // 只给POST方法加consumes限制 @PostMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Void> save(@RequestBody Curso curso) { cursoService.save(curso); URI location = ServletUriComponentsBuilder.fromCurrentRequest() .path("/{id}") .buildAndExpand(curso.getId()) .toUri(); return ResponseEntity.created(location).build(); } }
2. 修正Spring容器分层配置
将Web层配置和业务持久层配置拆分,避免容器扫描错位:
- 新增独立的Web层配置类
SpringWebConfig,将@EnableWebMvc移到此类中,专门扫描Controller包:
@Configuration @EnableWebMvc @ComponentScan("br.com.gabriel.restful.controller") public class SpringWebConfig implements WebMvcConfigurer { // 如需配置静态资源映射、自定义消息转换器可在此处重写对应方法 }
- 修改
SpringRootConfig,移除@EnableWebMvc注解,排除Web层组件扫描,显式导入JPA配置避免漏扫:
@Configuration @EnableTransactionManagement @ComponentScan(basePackages = "br.com.gabriel.restful", excludeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, value = RestController.class )) @Import(SpringJpaConfig.class) public class SpringRootConfig { }
- 修改
SpringInitConfig,将Web配置类注册到DispatcherServlet的子容器中:
public class SpringInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringRootConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringWebConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
3. 检查Postman请求配置
- 发GET请求时不要手动设置Content-Type头,直接访问
/cursos即可。 - 发POST请求时按以下要求配置:
- 请求头添加
Content-Type: application/json - Body选择
raw类型,右侧下拉选择JSON格式 - 传入合法JSON,字段与
Curso实体类属性一一对应,示例:
{ "nome": "Spring MVC入门课程", "cargaHoraria": 40 } - 请求头添加
- 确认
Curso实体类添加了public无参构造方法,避免Jackson反序列化失败。
4. 调试定位(可选)
如果修复后仍返回400,添加日志配置打印具体错误原因,在项目resources目录下的配置文件中添加:
# SpringMVC web层调试日志 logging.level.org.springframework.web=DEBUG # JSON反序列化日志 logging.level.com.fasterxml.jackson.databind=DEBUG
重启项目后发请求,控制台会明确打印400错误的具体触发点(如JSON字段不匹配、参数缺失等)。
内容的提问来源于stack exchange,提问作者Gabriwl
相关产品推荐
相关产品推荐

