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 {
....
}
}
我正在尝试对 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 {
....
}
}