java Spring Rest ErrorHandling @ControllerAdvice / @Valid
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16651160/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring Rest ErrorHandling @ControllerAdvice / @Valid
提问by daemon_nio
I'm having trouble when Using @ControllerAdviceand @Validannotations together in a REST controller.
在 REST 控制器中一起使用@ControllerAdvice和@Valid注释时遇到问题。
I have a rest controller declared as follows:
我有一个rest控制器声明如下:
@Controller
public class RestExample {
...
/**
* <XmlRequestUser><username>user1</username><password>password</password><name>Name</name><surname>Surname</surname></XmlRequestUser>
* curl -d "@restAddRequest.xml" -H "Content-Type:text/xml" http://localhost:8080/SpringExamples/servlets/rest/add
*/
@RequestMapping(value="rest/add", method=RequestMethod.POST)
public @ResponseBody String add(@Valid @RequestBody XmlRequestUser xmlUser) {
User user = new User();
user.setUsername(xmlUser.getUsername());
user.setPassword(xmlUser.getPassword());
user.setName(xmlUser.getName());
user.setSurname(xmlUser.getSurname());
// add user to the database
StaticData.users.put(xmlUser.getUsername(), user);
LOG.info("added user " + xmlUser.getUsername());
return "added user " + user.getUsername();
}
}
And an ErrorHandler class:
还有一个 ErrorHandler 类:
@ControllerAdvice
public class RestErrorHandler extends ResponseEntityExceptionHandler {
private static Logger LOG = Logger.getLogger(RestErrorHandler.class);
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<Object> handleException(final RuntimeException e, WebRequest request) {
LOG.error(e);
String bodyOfResponse = e.getMessage();
return handleExceptionInternal(e, bodyOfResponse, new HttpHeaders(), HttpStatus.CONFLICT, request);
}
}
The problem is that, if I add a "throw new RuntimeException"within the method RestExample.addthen the exception is correctly handled by RestErrorHandlerclass.
问题是,如果我在方法RestExample.add 中添加“throw new RuntimeException”,那么RestErrorHandler类会正确处理异常。
However when curling a not valid request to the controller the RestErrorHandlerdoesn't catch the exception thrown by the validator and I receive a 400 BadRequestresponse. (For not valid request I mean an xml request where Username is not specified)
但是,当向控制器卷曲无效请求时,RestErrorHandler不会捕获验证器抛出的异常,并且我收到400 BadRequest响应。(对于无效请求,我的意思是未指定用户名的 xml 请求)
Note that XmlRequestUserclass is autogenerated by the plugin maven-jaxb2-plugin+ krasa-jaxb-tools(pom.xml):
请注意,XmlRequestUser类是由插件maven-jaxb2-plugin+ krasa-jaxb-tools(pom.xml)自动生成的:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>src/main/xsd</schemaDirectory>
<schemaIncludes>
<include>*.xsd</include>
</schemaIncludes>
<args>
<arg>-XJsr303Annotations</arg>
<arg>-XJsr303Annotations:targetNamespace=http://www.foo.com/bar</arg>
</args>
<plugins>
<plugin>
<groupId>com.github.krasa</groupId>
<artifactId>krasa-jaxb-tools</artifactId>
<version>${krasa-jaxb-tools.version}</version>
</plugin>
</plugins>
</configuration>
</plugin>
The generated class has correctly a @NotNull Annotation on Username and Password fields.
生成的类在用户名和密码字段上正确地具有 @NotNull 注释。
My context.xmlis very easy, containing just a scanner for controllers and enabling mvc:annotation-driven
我的context.xml非常简单,只包含一个控制器扫描器并启用 mvc:annotation-driven
<context:component-scan base-package="com.aa.rest" />
<mvc:annotation-driven />
Does anybody know how to make working @ControllerAdvice and @Valid annotations together in a REST controller?
有人知道如何在 REST 控制器中同时使用 @ControllerAdvice 和 @Valid 注释吗?
Thanks in advance. Antonio
提前致谢。安东尼奥
回答by matsev
You are on the right track, but you need to override the handleMethodArgumentNotValid()instead of the handleException()
method, e.g.
您在正确的轨道上,但您需要覆盖handleMethodArgumentNotValid()而不是handleException()
方法,例如
@ControllerAdvice
public class RestErrorHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException exception,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
LOG.error(exception);
String bodyOfResponse = exception.getMessage();
return new ResponseEntity(errorMessage, headers, status);
}
}
From the JavaDoc of MethodArgumentNotValidException:
来自MethodArgumentNotValidException的 JavaDoc :
Exception to be thrown when validation on an argument annotated with @Valid fails.
当对用 @Valid 注释的参数的验证失败时抛出的异常。
In other words, a MethodArgumentNotValidException
is thrown when the validation fails. It is handled by the handleMethodArgumentNotValid()
method provided by the ResponseEntityExceptionHandler
, that needs to be overridden if you would like a custom implementation.
换句话说,MethodArgumentNotValidException
当验证失败时抛出a 。它由handleMethodArgumentNotValid()
提供的方法处理,ResponseEntityExceptionHandler
如果您想要自定义实现,则需要覆盖该方法。
回答by daemon_nio
In addition to this I had another problem on recursive validation.
除此之外,我在递归验证方面还有另一个问题。
The generated classes were missing a @validannotation on the other XmlElements.
生成的类在其他 XmlElements 上缺少@valid注释。
The reason for this is related to the fact that I was wrongly using the namespaces:
这样做的原因与我错误地使用命名空间有关:
The plugin is configured to use a particular namespace
该插件被配置为使用特定的命名空间
<arg>-XJsr303Annotations:targetNamespace=http://www.foo.com/bar</arg>
So the XSD need to have this as target namespace (e.g.):
所以 XSD 需要将此作为目标命名空间(例如):
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foo.com/bar"
xmlns:foo="http://www.foo.com/bar" >
<xs:complexType name="XmlPassword">
<xs:sequence>
<xs:element name="password" type="xs:string" />
<xs:element name="encryption" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="XmlToken">
<xs:sequence>
<xs:element name="password" type="foo:XmlPassword" />
</xs:sequence>
</xs:complexType>
</xs:schema>
Kind regards Antonio
亲切的问候安东尼奥
回答by Th??ng ??c
Better format of return message:
更好的返回消息格式:
@ControllerAdvice
public class MyControllerAdvice extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
BindingResult result = ex.getBindingResult();
List<FieldErrorVM> fieldErrors = result.getFieldErrors().stream()
.map(f -> new FieldErrorVM(f.getObjectName(), f.getField(), f.getCode()))
.collect(Collectors.toList());
return handleExceptionInternal(ex, "Method argument not valid, fieldErrors:" + fieldErrors ,new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
}
}