2014-04-22 1 views
7

일부 유효성 검사가있는 간단한 스프링 레스트 컨트롤러가 있습니다. 내 이해는 유효성 검사 실패는 MethodArgumentNotValidException을 던질 것입니다. 그러나 내 코드 대신 BindException이 throw됩니다. 디버그 메시지에서, 나는 또한 응용 프로그램이 null ModelAndView를 반환하는 것을 보았습니다.REST 응용 프로그램에서 MethodArgumentNotValidException 대신 BindException이 발생했습니다.

나머지 컨트롤러가 BindException을 던지거나 null ModelAndView를 반환하는 이유는 무엇입니까?

참고 : 나는 컬을 사용하여 내 웹 응용 프로그램을 테스트하고 내가 의도적으로 @NotNull 및 @NotBlank 주석으로 표시 필수 항목 인 "이름"매개 변수를 생략하고는 HTTP POST

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

을하고있다.

내 컨트롤러 :

@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; 
    } 
} 

processErrors 방법은 @ExceptionHandler 표시 (...) 주석은 절대 호출되지 않습니다. @ExceptionHandler (...) 주석을 사용하여 BindException을 catch하려고하면 핸들러 메소드가 호출됩니다.

필자는 필요한 경우 Task, TaskCommand, Error 및 ErrorsList와 같은 몇 가지 지원 클래스를 게시 할 수 있습니다.

+0

나는'@ RestController'에서 똑같은 문제를 겪고 있습니다. '@Controller'를'@ RequestBody'와'@ResponseBody'와 결합하면 작동합니다. 혹시 이걸 해결 했니? – Dormouse

+0

방금 ​​대답했습니다. 아래를 봐주세요. 귀하의 문제가 다른 것 일지라도. 어느 쪽이든 작동해야합니다. – Jigish

답변

2

문제는 내 컬 명령과 관련이 있습니다.

curl -d는 Content-Type "application/x-www-form-urlencoded"를 보냅니다. 결과적으로 Spring은 JSON 대신 데이터를 웹 양식 데이터로 해석합니다. Spring은 FormHttpMessageConverter를 사용하여 POST의 본문을 도메인 객체로 변환하고 BindException을 발생시킵니다.

우리가 원하는 것은 Spring에서 POST 데이터를 JSON으로 처리하고 MappingJackson2HttpMessageConverter를 사용하여 POST 본문을 객체로 파싱하는 것입니다.

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 

컬 사용하여 JSON 데이터를 게시하는 방법에 대한이 게시물을 참조하십시오 : 이것은 컬 명령 "Content-Type"헤더를 지정하여 수행 할 수 있습니다 또한 How to POST JSON data with Curl from Terminal/Commandline to Test Spring REST?

을 여기에 관련 봄 문서에 대한이야 MessageConverters : 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