Return @notnull 验证失败时响应代码为 400
Return response code as 400 when @notnull validation fails
我正在使用 javax 和 Hibernate 实现来验证我的请求负载。
版本 - org.hibernate:hibernate-validator:5.4.1.final
示例 Pojo:
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
public class Customer implements Serializable{
@NotNull(message="name is null")
@Size(min = 1)
public String name;
@NotNull(message="country is null")
@Size(min = 1)
public String country;
}
示例控制器:
@RequestMapping(value = {"/customer"}, method = RequestMethod.POST)
@ResponseBody
public Customer doAdd(@RequestBody @Valid Customer inData){
//some logic
return outData
}
样本输入json:
{
"country":"canada"
}
控制台异常:
org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument at index 0 in method: ........ model.request.Customer,java.lang.String,java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse), with 1 error(s): [Field error in object 'Customer' on field 'name': rejected value [null]; codes [NotNull.Customer.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [Customer.name,name]; arguments []; default message [name]]; default message [name is null]]
此处,当 customer.name 为空时,我得到的响应代码为 422(无法处理的实体)。但我想 return 400(BAD Request)。我怎样才能在这里覆盖响应代码?任何文件参考将不胜感激。
注意 - 我不想在控制器端进行这些验证,我可以在哪里检查并相应地发送响应代码。
喜欢这个 -
更新 - 问题已解决 ------
我的问题已经解决了。谢谢大家的回复。
让我解释一下是什么原因造成的,
HttpRequest ----> @Valid on RequestBody ----> Javax validation on Request object-----> If any of the validation fails, **MethodArgumentNotValidException** exception is thrown.
开发人员有责任捕获此异常并抛出相应的 http 响应代码。
在我的例子中,异常处理程序已经存在并且正在捕获此 MethodArgumentNotValidException 和 returning HttpStatus.UNPROCESSABLE_ENTITY。这就是我看到 422 错误代码的原因。
现在我已经将异常处理程序更改如下,
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResource>
handleMethodArgumentNotValidException(MethodArgumentNotValidException exception, HttpServletRequest request) {
List<FieldErrorResource> fieldErrorResources = new ArrayList<>();
BindingResult bindingResult = exception.getBindingResult();
for (FieldError constraintViolation : bindingResult.getFieldErrors()) {
fieldErrorResources.add(FieldErrorResource.builder()
.field(constraintViolation.getField())
.resource(request.getContextPath())
.message(constraintViolation.getDefaultMessage()).build());
}
return responseEntityFor(HttpStatus.BAD_REQUEST,
"The content you've sent contains " + bindingResult.getErrorCount() + " validation errors.", fieldErrorResources);
}
您应该在 Customer
之后立即设置 BindingResult
。喜欢:
@RequestMapping(value = {"/customer"}, method = RequestMethod.POST)
@ResponseBody
public Customer doAdd(@RequestBody @Valid Customer inData, BindingResult bindingResult){
//some logic
return outData
}
您可以使用 RestControllerAdvice 来实现同样的效果
@RestControllerAdvice
public class ExceptionRestControllerAdvice {
@ExceptionHandler({ConstraintViolationException.class})
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public ExceptionResponseMessage handleInvalidParameterException(RuntimeException ex) {
return sendResponse(HttpStatus.BAD_REQUEST, ex);
}
private ExceptionResponseMessage sendResponse(HttpStatus status, RuntimeException ex) {
return new ExceptionResponseMessage(Instant.now(), status.value(), status.getReasonPhrase(),
ex.getClass().toString(), ex.getMessage());
}
}
public class ExceptionResponseMessage {
private Instant time;
private int status;
private String error;
private String exception;
private String message;
// setter and getter and constructor
我正在使用 javax 和 Hibernate 实现来验证我的请求负载。
版本 - org.hibernate:hibernate-validator:5.4.1.final
示例 Pojo:
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
public class Customer implements Serializable{
@NotNull(message="name is null")
@Size(min = 1)
public String name;
@NotNull(message="country is null")
@Size(min = 1)
public String country;
}
示例控制器:
@RequestMapping(value = {"/customer"}, method = RequestMethod.POST)
@ResponseBody
public Customer doAdd(@RequestBody @Valid Customer inData){
//some logic
return outData
}
样本输入json:
{
"country":"canada"
}
控制台异常:
org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument at index 0 in method: ........ model.request.Customer,java.lang.String,java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse), with 1 error(s): [Field error in object 'Customer' on field 'name': rejected value [null]; codes [NotNull.Customer.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [Customer.name,name]; arguments []; default message [name]]; default message [name is null]]
此处,当 customer.name 为空时,我得到的响应代码为 422(无法处理的实体)。但我想 return 400(BAD Request)。我怎样才能在这里覆盖响应代码?任何文件参考将不胜感激。
注意 - 我不想在控制器端进行这些验证,我可以在哪里检查并相应地发送响应代码。 喜欢这个 -
更新 - 问题已解决 ------
我的问题已经解决了。谢谢大家的回复。
让我解释一下是什么原因造成的,
HttpRequest ----> @Valid on RequestBody ----> Javax validation on Request object-----> If any of the validation fails, **MethodArgumentNotValidException** exception is thrown.
开发人员有责任捕获此异常并抛出相应的 http 响应代码。 在我的例子中,异常处理程序已经存在并且正在捕获此 MethodArgumentNotValidException 和 returning HttpStatus.UNPROCESSABLE_ENTITY。这就是我看到 422 错误代码的原因。
现在我已经将异常处理程序更改如下,
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResource>
handleMethodArgumentNotValidException(MethodArgumentNotValidException exception, HttpServletRequest request) {
List<FieldErrorResource> fieldErrorResources = new ArrayList<>();
BindingResult bindingResult = exception.getBindingResult();
for (FieldError constraintViolation : bindingResult.getFieldErrors()) {
fieldErrorResources.add(FieldErrorResource.builder()
.field(constraintViolation.getField())
.resource(request.getContextPath())
.message(constraintViolation.getDefaultMessage()).build());
}
return responseEntityFor(HttpStatus.BAD_REQUEST,
"The content you've sent contains " + bindingResult.getErrorCount() + " validation errors.", fieldErrorResources);
}
您应该在 Customer
之后立即设置 BindingResult
。喜欢:
@RequestMapping(value = {"/customer"}, method = RequestMethod.POST)
@ResponseBody
public Customer doAdd(@RequestBody @Valid Customer inData, BindingResult bindingResult){
//some logic
return outData
}
您可以使用 RestControllerAdvice 来实现同样的效果
@RestControllerAdvice
public class ExceptionRestControllerAdvice {
@ExceptionHandler({ConstraintViolationException.class})
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public ExceptionResponseMessage handleInvalidParameterException(RuntimeException ex) {
return sendResponse(HttpStatus.BAD_REQUEST, ex);
}
private ExceptionResponseMessage sendResponse(HttpStatus status, RuntimeException ex) {
return new ExceptionResponseMessage(Instant.now(), status.value(), status.getReasonPhrase(),
ex.getClass().toString(), ex.getMessage());
}
}
public class ExceptionResponseMessage {
private Instant time;
private int status;
private String error;
private String exception;
private String message;
// setter and getter and constructor