我有以下@RestController
@RequestMapping(...)
public ResponseEntity(@RequestBody @Valid SomeDTO, BindingResult errors) {
//do something with errors if validation error occur
}
public class SomeDTO {
public SomeEnum someEnum;
}
如果JSON请求是{ "someEnum": "valid value" }
,一切正常。但是,如果请求为{ "someEnum": "invalid value" }
,则仅返回错误代码400。
如何捕获此错误,以便我可以提供自定义错误消息,例如“someEnum必须具有值A / B / C”。
答案 0 :(得分:2)
@Amit 提供的答案很好并且有效。如果您想以特定方式反序列化枚举,则可以继续进行。但该解决方案不可扩展。每个需要验证的枚举都必须用 @JsonCreator
注释。
其他答案无助于美化错误消息。
所以这是我对 spring 网络环境中所有枚举通用的解决方案。
@RestControllerAdvice
public class ControllerErrorHandler extends ResponseEntityExceptionHandler {
public static final String BAD_REQUEST = "BAD_REQUEST";
@Override
public ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException exception,
HttpHeaders headers, HttpStatus status, WebRequest request) {
String genericMessage = "Unacceptable JSON " + exception.getMessage();
String errorDetails = genericMessage;
if (exception.getCause() instanceof InvalidFormatException) {
InvalidFormatException ifx = (InvalidFormatException) exception.getCause();
if (ifx.getTargetType().isEnum()) {
errorDetails = String.format("Invalid enum value: '%s' for the field: '%s'. The value must be one of: %s.",
ifx.getValue(), ifx.getPath().get(ifx.getPath().size()-1).getFieldName(), Arrays.toString(ifx.getTargetType().getEnumConstants()));
}
}
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setTitle(BAD_REQUEST);
errorResponse.setDetail(errorDetails);
return handleExceptionInternal(exception, errorResponse, headers, HttpStatus.BAD_REQUEST, request);
}
}
这将处理所有类型的所有无效枚举值,并为最终用户提供更好的错误消息。
示例输出:
{
"title": "BAD_REQUEST",
"detail": "Invalid enum value: 'INTERNET_BANKING' for the field: 'paymentType'. The value must be one of: [DEBIT, CREDIT]."
}
答案 1 :(得分:1)
Yon可以使用@ControllerAdvice
实现此目的,如下所示
@org.springframework.web.bind.annotation.ExceptionHandler(value = {InvalidFormatException.class})
public ResponseEntity handleIllegalArgumentException(InvalidFormatException exception) {
return ResponseEntity.badRequest().body(exception.getMessage());
}
基本上,我们的想法是抓住com.fasterxml.jackson.databind.exc.InvalidFormatException
并根据您的要求处理它。
答案 2 :(得分:1)
def setUp(self):
self.driver = webdriver.Remote(command_executor='http://localhost:4444/wd/hub',
desired_capabilities=DesiredCapabilities.FIREFOX) #remote-server or localhost
I created a fully functional Spring boot Application with a Test on Bitbucket
答案 3 :(得分:0)
@Valid has to do with Hibernate bean validation. Currently enum type is not supported out of the box. I found this answer to be the closet, https://funofprograming.wordpress.com/2016/09/29/java-enum-validator/, the drawback however is that you have to make the enum field of type String instead.
答案 4 :(得分:0)
您不需要@Valid进行枚举验证,您可以使用以下代码获得所需的响应:
控制器代码,StackDTO中包含一个枚举PaymentType:
@RequestMapping(value = "/reviews", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<String> add(@RequestBody StackDTO review) {
return new ResponseEntity<String>(HttpStatus.ACCEPTED);
}
创建一个异常类,如EnumValidationException
public class EnumValidationException extends Exception {
private String enumValue = null;
private String enumName = null;
public String getEnumValue() {
return enumValue;
}
public void setEnumValue(String enumValue) {
this.enumValue = enumValue;
}
public String getEnumName() {
return enumName;
}
public void setEnumName(String enumName) {
this.enumName = enumName;
}
public EnumValidationException(String enumValue, String enumName) {
super(enumValue);
this.enumValue = enumValue;
this.enumName = enumName;
}
public EnumValidationException(String enumValue, String enumName, Throwable cause) {
super(enumValue, cause);
this.enumValue = enumValue;
this.enumName = enumName;
}
}
我有如下的枚举,在方法创建
上有一个特殊的注释@JsonCreatorpublic enum PaymentType {
CREDIT("Credit"), DEBIT("Debit");
private final String type;
PaymentType(String type) {
this.type = type;
}
String getType() {
return type;
}
@Override
public String toString() {
return type;
}
@JsonCreator
public static PaymentType create (String value) throws EnumValidationException {
if(value == null) {
throw new EnumValidationException(value, "PaymentType");
}
for(PaymentType v : values()) {
if(value.equals(v.getType())) {
return v;
}
}
throw new EnumValidationException(value, "PaymentType");
}
}
最后是RestErrorHandler类,
@ControllerAdvice
public class RestErrorHandler {
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ResponseEntity<ValidationErrorDTO> processValidationIllegalError(HttpMessageNotReadableException ex,
HandlerMethod handlerMethod, WebRequest webRequest) {
EnumValidationException exception = (EnumValidationException) ex.getMostSpecificCause();
ValidationErrorDTO errorDTO = new ValidationErrorDTO();
errorDTO.setEnumName(exception.getEnumName());
errorDTO.setEnumValue(exception.getEnumValue());
errorDTO.setErrorMessage(exception.getEnumValue() + " is an invalid " + exception.getEnumName());
return new ResponseEntity<ValidationErrorDTO>(errorDTO, HttpStatus.BAD_REQUEST);
}
}
ValidationErrorDTO是带有enumValue,enumName和errorMessage的setter / getters的dto。现在,当您使用以下请求将POST调用发送到控制器端点/评论时
{"paymentType":"Credit2"}
然后代码将响应返回为400,响应体位于以下 -
{
"enumValue": "Credit2",
"enumName": "PaymentType",
"errorMessage": "Credit2 is an invalid PaymentType"
}
如果它能解决您的问题,请告诉我。