2013-05-20 31 views
10

Tôi gặp sự cố khi sử dụng các chú thích @ControllerAdvice@Valid cùng nhau trong bộ điều khiển REST.Lỗi phần còn lại mùa xuânHandling @ControllerAdvice/@Valid

Tôi có một bộ điều khiển còn lại tuyên bố như sau:

@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(); 
    } 
} 

Và một lớp 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); 
    } 
} 

Vấn đề là, nếu tôi thêm một "ném RuntimeException mới" trong phương pháp RestExample.add thì ngoại lệ được xử lý một cách chính xác bởi Lớp RestErrorHandler.

Tuy nhiên khi cong một yêu cầu không hợp lệ để điều khiển các RestErrorHandler không bắt ném ngoại lệ bởi các validator và tôi nhận được phản hồi 400 BadRequest. (Đối với yêu cầu không hợp lệ Ý tôi là một yêu cầu xml nơi Tên đăng nhập không được xác định)

Lưu ý rằng XmlRequestUser lớp là autogenerated bởi các plugin 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> 

Các lớp được tạo có đúng một chú thích @NotNull trên các trường Tên người dùng và Mật khẩu.

My context.xml là rất dễ dàng, chỉ chứa một máy quét cho các bộ điều khiển và cho phép MVC: chú thích-driven

<context:component-scan base-package="com.aa.rest" /> 
<mvc:annotation-driven /> 

Có ai biết làm thế nào để làm việc @ControllerAdvice và @Valid chú thích với nhau trong một Bộ điều khiển REST?

Xin cảm ơn trước. Antonio

Trả lời

11

Bạn đang đi đúng hướng, nhưng bạn cần ghi đè lên handleMethodArgumentNotValid() thay vì phương pháp handleException(), ví dụ:

@ControllerAdvice 
public class RestErrorHandler extends ResponseEntityExceptionHandler { 

    @Override 
    protected ResponseEntity<Object> handleMethodArgumentNotValid(
      MethodArgumentNotValidException ex, 
      HttpHeaders headers, 
      HttpStatus status, 
      WebRequest request) { 

     LOG.error(e); 
     String bodyOfResponse = e.getMessage(); 
     return new ResponseEntity(errorMessage, headers, status); 
    } 
} 

Từ javadoc của MethodArgumentNotValidException:

ngoại lệ được ném ra khi xác nhận vào một cuộc tranh cãi với chú thích @Valid thất bại.

Nói cách khác, MethodArgumentNotValidException được ném khi xác thực không thành công. Nó được xử lý bằng phương pháp handleMethodArgumentNotValid() do ResponseEntityExceptionHandler cung cấp, cần được ghi đè nếu bạn muốn triển khai tùy chỉnh.

+0

Cảm ơn, đây chính xác là những gì tôi đang tìm kiếm. –

+1

@matsev Thay vì mở rộng ResponseEntityExceptionHandler và ghi đè phương thức handleMethodArgumentNotValid, anh ta có thể đơn giản sử dụng một @ExceptionHandler (MethodArgumentNotValidException.class) không? – Stephane

+0

@StephaneEybert Chắc chắn, tại sao không. Tôi đã chọn để mở rộng 'ResponseEntityExceptionHandler' vì nó đã được mở rộng trong câu hỏi ban đầu. Liên quan: bằng cách sử dụng chú thích '@ ControllerAdvice' (bất kể bạn mở rộng' ResponseEntityExceptionHandler' hoặc sử dụng chú thích '@ ExceptionHandler'), bạn sẽ nhận được xử lý lỗi nhất quán cho tất cả các bộ điều khiển. – matsev

1

Ngoài việc này, tôi còn gặp phải vấn đề khác về xác thực đệ quy.

Lớp được tạo thiếu một chú thích @valid trên các XmlElements khác.

Lý do cho điều này có liên quan đến thực tế là tôi đã sai bằng cách sử dụng không gian tên:

Plugin được cấu hình để sử dụng một không gian tên riêng

<arg>-XJsr303Annotations:targetNamespace=http://www.foo.com/bar</arg> 

Vì vậy, XSD cần phải có này làm không gian tên đích (ví dụ):

<?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> 

Loại liên quan Antonio

Các vấn đề liên quan