18

REST コントローラーで@ControllerAdviceアノテーションと@Validアノテーションを一緒に使用すると問題が発生します。

次のように宣言された残りのコントローラーがあります。

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

そして 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);
    }
}

問題は、メソッドRestExample.add内に「throw new RuntimeException」を追加すると、 RestErrorHandlerクラスによって例外が正しく処理されることです。

ただし、コントローラーへの無効なリクエストをカールすると、RestErrorHandlerはバリデーターによってスローされた例外をキャッチせず、400 BadRequestレスポンスを受け取ります。(無効なリクエストとは、ユーザー名が指定されていない 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>

生成されたクラスには、ユーザー名とパスワードのフィールドに @NotNull 注釈が正しく含まれています。

私のcontext.xmlは非常に簡単で、コントローラー用のスキャナーと mvc:annotation-driven を有効にするだけです。

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

RESTコントローラーで@ControllerAdviceと@Validアノテーションを一緒に機能させる方法を知っている人はいますか?

前もって感謝します。アントニオ

4

3 に答える 3

34

あなたは正しい軌道に乗っていますが、メソッドの代わりに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);
    }
}

MethodArgumentNotValidExceptionの JavaDoc から:

@Valid で注釈が付けられた引数の検証が失敗した場合にスローされる例外。

つまり、MethodArgumentNotValidException検証が失敗すると a がスローされます。カスタム実装が必要な場合は、オーバーライドする必要があるhandleMethodArgumentNotValid()によって提供されるメソッドによって処理されます。ResponseEntityExceptionHandler

于 2013-05-20T17:36:28.933 に答える
1

これに加えて、再帰的検証に関して別の問題がありました。

生成されたクラスには、他の XmlElements の@valid注釈がありませんでした。

この理由は、名前空間を間違って使用していたという事実に関連しています。

プラグインは特定の名前空間を使用するように構成されています

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

したがって、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>

よろしくアントニオ

于 2013-05-28T12:11:33.767 に答える