如何从Validated Spring RestController获取多个缺少请求参数的详细信息?

时间:2017-07-06 08:02:11

标签: java spring spring-mvc spring-restcontroller

我正在尝试使用Spring对两个@RequestParam的验证,@ControllerAdvice捕获框架在缺少参数时抛出的异常,并返回带有缺失参数的400错误。

所以,我的代码如下:

@RestController
@Validated
public class FooController {
  @RequestMapping(value = "/foo", method = RequestMethod.GET)
  @ResponseBody
  public Foo getFoo(@RequestParam LocalDate dateFrom, @RequestParam LocalDate dateTo) {
    // Do stuff
  }
}

@ControllerAdvice
public class ExceptionController {
  @ExceptionHandler(value = {MissingServletRequestParameterException.class})
  @ResponseStatus(value = HttpStatus.BAD_REQUEST)
  @ResponseBody
  public ErrorResponse handleMissingParameterException(MissingServletRequestParameterException ex) {
    return new ErrorResponse(ex.getMessage());
  }
}

如果我错过了一个参数,这非常有效 - 我得到了一个很好的JSON响应,如下所示:

{
  "reason": "Required LocalDate parameter 'dateFrom' is not present"
}

有400状态。

但是,如果我错过了这两个参数,我会得到与上面相同的错误响应 - 即它只报告第一个缺失参数,如果我可以列出所有这些参数,我更喜欢它。

查看异常的方法,似乎只打算处理单个参数 - 它以单数形式显示方法getParameterName()getParameterType()

有什么方法可以让Spring在一个例外中报告所有验证错误,以改善客户体验?

2 个答案:

答案 0 :(得分:3)

您可以先设置 @RequestParam(required = false),然后使用 @NotNull

如果参数为 null,则将抛出 ConstraintViolationException。要处理它,只需声明一个 @ExceptionHandler 方法。检查下面的代码片段

@RestController
@Validated
public class FooController {
  @RequestMapping(value = "/foo", method = RequestMethod.GET)
  @ResponseBody
  public Foo getFoo(
      @RequestParam (required = false) 
      @NotNull(message = "Required LocalDate parameter dateFrom is not present") 
      LocalDate dateFrom,
      @RequestParam (required = false) 
      @NotNull(message = "Required LocalDate parameter dateTo is not present") 
      LocalDate dateTo) 
  ) {
    // Do stuff
  }
}

@ControllerAdvice
public class ExceptionController {
    @ExceptionHandler({ConstraintViolationException.class})
    public ResponseEntity<List<ErrorResponseDTO>> exceptionHandler(ConstraintViolationException e) {
        List<ErrorResponseDTO> errors = new ArrayList<>(e.getConstraintViolations().size());
        e.getConstraintViolations().forEach(violation -> errors.add(new ErrorResponseDTO(violation.getMessage())));
        return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
    }
}

结果是这样的:

[
    {
        "reason": "Required LocalDate parameter dateFrom is not present"
    },
    {
        "reason": "Required LocalDate parameter dateTo is not present"
    }
]

答案 1 :(得分:2)

而是引入一个带有验证注释的POJO过滤器

public class Filter {
    @NotNull
    private LocalDate dateFrom;
    @NotNull
    private LocalDate dateTo;
}

然后在控制器中使用它

public Foo getFoo(@Valid Filter filter) {
  // Do stuff
}

BindingResult将提供所有验证错误