Spring 引导,如何将@Valid 与List<T> 一起使用

Spring boot, how to use @Valid with List<T>

我正在尝试对 Spring 引导项目进行验证。所以我把 @NotNull 注释放在实体字段上。在控制器中,我这样检查:

@RequestMapping(value="", method = RequestMethod.POST)
public DataResponse add(@RequestBody @Valid Status status, BindingResult bindingResult) {
    if(bindingResult.hasErrors()) {
        return new DataResponse(false, bindingResult.toString());
    }

    statusService.add(status);

    return  new DataResponse(true, "");
}

这行得通。但是当我输入 List<Status> statuses 时,它不起作用。

@RequestMapping(value="/bulk", method = RequestMethod.POST)
public List<DataResponse> bulkAdd(@RequestBody @Valid List<Status> statuses, BindingResult bindingResult) {
    // some code here
}

基本上,我想要的是像在 add 方法中那样对请求主体列表中的每个 Status 对象应用验证检查。因此,发送方现在将知道哪些对象有故障,哪些没有。

我怎样才能简单、快速地做到这一点?

我的直接建议是将 List 包装在另一个 POJO bean 中。并将其用作请求正文参数。

在你的例子中。

@RequestMapping(value="/bulk", method = RequestMethod.POST)
public List<DataResponse> bulkAdd(@RequestBody @Valid StatusList statusList, BindingResult bindingResult) {
// some code here
}

和StatusList.java将是

@Valid
private List<Status> statuses;
//Getter //Setter //Constructors

不过我没试过。

更新: 接受的答案 in this SO link 很好地解释了为什么列表不支持 bean 验证。

只需用 @Validated 注释标记控制器。

它会抛出 ConstraintViolationException,因此您可能希望将其映射到 400: BAD_REQUEST:

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice(annotations = Validated.class)
public class ValidatedExceptionHandler {

    @ExceptionHandler
    public ResponseEntity<Object> handle(ConstraintViolationException exception) {

        List<String> errors = exception.getConstraintViolations()
                                       .stream()
                                       .map(this::toString)
                                       .collect(Collectors.toList());

        return new ResponseEntity<>(new ErrorResponseBody(exception.getLocalizedMessage(), errors),
                                    HttpStatus.BAD_REQUEST);
    }

    private String toString(ConstraintViolation<?> violation) {
        return Formatter.format("{} {}: {}",
                                violation.getRootBeanClass().getName(),
                                violation.getPropertyPath(),
                                violation.getMessage());
    }

    public static class ErrorResponseBody {
        private String message;
        private List<String> errors;
    }
}
@RestController
@Validated
@RequestMapping("/products")
    public class ProductController {
        @PostMapping
        @Validated(MyGroup.class)
        public ResponseEntity<List<Product>> createProducts(
            @RequestBody List<@Valid Product> products
        ) throws Exception {
            ....
        }
}