【问题标题】:BindException thrown instead of MethodArgumentNotValidException in REST application在 REST 应用程序中抛出 BindException 而不是 MethodArgumentNotValidException
【发布时间】:2014-06-06 07:48:15
【问题描述】:

我有一个简单的 Spring Rest Controller 并进行了一些验证。我的理解是验证失败会引发 MethodArgumentNotValidException。但是,我的代码会引发 BindException。在调试消息中,我还看到应用返回了 null ModelAndView。

为什么 Rest Controller 会抛出 BindException 或返回 null ModelAndView?

注意:我正在使用 curl 测试我的 Web 应用程序并进行 HTTP POST

curl -X POST http://localhost:8080/tasks

我故意省略了“name”参数,这是一个用@NotNull 和@NotBlank 注释标记的必填字段。

我的控制器:

@RestController
public class TasksController {

    private static Logger logger = Logger.getLogger(TasksController.class);

    @Autowired
    private MessageSource messageSource;

    @Autowired
    private Validator validator;

    @InitBinder
    protected void initBinder(WebDataBinder binder){
        binder.setValidator(this.validator);
    }         


    @RequestMapping(value = "/tasks", method = RequestMethod.POST)
    public Task createTask(@Valid TasksCommand tasksCommand){

        Task task = new Task();
        task.setName(tasksCommand.getName());
        task.setDue(tasksCommand.getDue());
        task.setCategory(tasksCommand.getCategory());

        return task;
    }
}

我的“命令”类(包含验证注释)

public class TasksCommand {

    @NotBlank
    @NotNull
    private String name;

    private Calendar due;

    private String category;

    ... getters & setters ommitted ...
}

我的 RestErrorHandler 类:

@ControllerAdvice
public class RestErrorHandler {

    private static Logger logger = Logger.getLogger(RestErrorHandler.class);

    @Autowired
    private MessageSource messageSource;

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ErrorsList processErrors(MethodArgumentNotValidException ex){
        logger.info("error handler invoked ...");
        BindingResult result = ex.getBindingResult();
        List<FieldError> fieldErrorList = result.getFieldErrors();

        ErrorsList errorsList = new ErrorsList();
        for(FieldError fieldError: fieldErrorList){
            Locale currentLocale = LocaleContextHolder.getLocale();
            String errorMessage = messageSource.getMessage(fieldError, currentLocale);

            logger.info("adding error message - " + errorMessage + " - to errorsList");
            errorsList.addFieldError(fieldError.getField(), errorMessage);
        }

        return errorsList;
    }
}

标有@ExceptionHandler(...) 注解的 processErrors 方法永远不会被调用。如果我尝试使用 @ExceptionHandler(...) 注释捕获 BindException,则该处理程序方法会被调用。

我有几个支持类 - Task、TaskCommand、Error 和 ErrorsList - 如果需要,我可以发布代码。

【问题讨论】:

  • 我的@RestController 也有同样的问题。当我将@Controller@RequestBody@ResponseBody 结合使用时,它可以工作。你有没有机会解决这个问题?
  • 我刚刚回复了我的答案。请看下文。尽管您的问题可能有所不同。无论哪种方式,它都应该工作。

标签: java spring rest exceptionhandler


【解决方案1】:

问题出在我的 curl 命令上。

curl -d 发送内容类型“application/x-www-form-urlencoded”。因此,Spring 将数据解释为 Web 表单数据(而不是 JSON)。 Spring 使用 FormHttpMessageConverter 将 POST 的主体转换为域对象并导致 BindException。

我们想要的是让 Spring 将 POST 数据视为 JSON,并使用 MappingJackson2HttpMessageConverter 将 POST 的主体解析为对象。这可以通过使用 curl 命令指定“Content-Type”标头来完成:

curl -X POST -H "Content-Type: application/json" -d '{"name":"name1", "due":"2014-DEC-31 01:00:00 PDT", "category":"demo"}' http://localhost:8080/tasks

查看这篇文章了解如何使用 curl 发布 JSON 数据: How to POST JSON data with Curl from Terminal/Commandline to Test Spring REST?

另外,这里是有关 MessageConverters 的相关 Spring 文档: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestbody http://docs.spring.io/spring/docs/current/spring-framework-reference/html/remoting.html#rest-message-conversion

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多