Пользовательская обработка исключений шаблона Rest

Я использую некоторые конечные точки REST из внешнего API, и для этой цели я использую интерфейс шаблона Rest. Я хотел бы иметь возможность создавать пользовательские исключения приложений, когда я получаю определенные коды состояния HTTP от этих вызовов. Чтобы достичь этого, я реализую интерфейс ResponseErrorHandler следующим образом:

public class MyCustomResponseErrorHandler implements ResponseErrorHandler {

    private ResponseErrorHandler myErrorHandler = new DefaultResponseErrorHandler();

    public boolean hasError(ClientHttpResponse response) throws IOException {
        return myErrorHandler.hasError(response);
    }

    public void handleError(ClientHttpResponse response) throws IOException {
        String body = IOUtils.toString(response.getBody());
        MyCustomException exception = new MyCustomException(response.getStatusCode(), body, body);
        throw exception;
    }

}

public class MyCustomException extends IOException {

    private HttpStatus statusCode;

    private String body;

    public MyCustomException(String msg) {
        super(msg);
        // TODO Auto-generated constructor stub
    }

    public MyCustomException(HttpStatus statusCode, String body, String msg) {
        super(msg);
        this.statusCode = statusCode;
        this.body = body;
    }

    public HttpStatus getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(HttpStatus statusCode) {
        this.statusCode = statusCode;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

}

наконец, это код клиента (не относящийся к делу код опущен):

public LoginResponse doLogin(String email, String password) {
    HttpEntity<?> requestEntity = new HttpEntity<Object>(crateBasicAuthHeaders(email,password));
    try{
        ResponseEntity<LoginResponse> responseEntity = restTemplate.exchange(myBaseURL + "/user/account/" + email, HttpMethod.GET, requestEntity, LoginResponse.class);
        return responseEntity.getBody();
    } catch (Exception e) {
        //Custom error handler in action, here we're supposed to receive a MyCustomException
        if (e instanceof MyCustomException){
            MyCustomException exception = (MyCustomException) e;
            logger.info("An error occurred while calling api/user/account API endpoint: " + e.getMessage());
        } else {
             logger.info("An error occurred while trying to parse Login Response JSON object");
        }
    }
    return null;
}

контекст моего приложения:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:spring="http://camel.apache.org/schema/spring"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">

    <!-- Rest template (used in bridge communication) -->
    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <property name="errorHandler" ref="myCustomResponseErrorHandler"></property>
    </bean>

    <!-- Bridge service -->
    <bean id="myBridgeService" class="a.b.c.d.service.impl.MyBridgeServiceImpl"/>

    <!-- Bridge error handler -->
    <bean id="myCustomResponseErrorHandler" class="a.b.c.d.service.handlers.MyCustomResponseErrorHandler"/>

</beans>

Я подозреваю, что я я неправильно понимаю поведение этой пользовательской обработки ошибок. Каждый метод шаблона rest может вызвать исключение RestClientException, которое после иерархии исключений является подклассом RuntimeException, а не IOException, которое создается в обработчике ошибок пользовательского ответа, т. е.: я не могу поймать свое пользовательское исключение в вызовах метода шаблона rest.

любые подсказки о том, как я мог бы поймать эти исключения? Spring RestTemplate вызывает веб-сервис с ошибками и проанализируйте код состояния очень связан, но с моей точки зрения испытывает ту же проблему, хотя она была предложена в качестве решения.

[1]:

2 ответов


вы сделали свой заказ Exception продлить от IOException

public class MyCustomException extends IOException {

на ResponseErrorHandler#handleError() метод вызывается из RestTemplate#handleResponseError(..) которая вызывается RestTemplate#doExecute(..). Этот корневой вызов обернут в try-catch блок, который ловит IOException и переосмысливает его, завернутый в ResourceAccessException, который является RestClientException.

одна из возможностей-поймать RestClientException и cause.

еще одна возможность сделать свой заказ Exception быть подтипом RuntimeException.


вы можете создать контроллер с помощью аннотации @ControllerAdvice Если вы используете springmvc. В контроллере пишем:

@ExceptionHandler(HttpClientErrorException.class)
public String handleXXException(HttpClientErrorException e) {
    log.error("log HttpClientErrorException: ", e);
    return "HttpClientErrorException_message";
}

@ExceptionHandler(HttpServerErrorException.class)
public String handleXXException(HttpServerErrorException e) {
    log.error("log HttpServerErrorException: ", e);
    return "HttpServerErrorException_message";
}
...
// catch unknown error
@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
    log.error("log unknown error", e);
    return "unknown_error_message";
}

и DefaultResponseErrorHandler кидаем эти два вида исключений:

@Override
public void handleError(ClientHttpResponse response) throws IOException {
    HttpStatus statusCode = getHttpStatusCode(response);
    switch (statusCode.series()) {
        case CLIENT_ERROR:
            throw new HttpClientErrorException(statusCode, response.getStatusText(),
                    response.getHeaders(), getResponseBody(response), getCharset(response));
        case SERVER_ERROR:
            throw new HttpServerErrorException(statusCode, response.getStatusText(),
                    response.getHeaders(), getResponseBody(response), getCharset(response));
        default:
            throw new RestClientException("Unknown status code [" + statusCode + "]");
    }
}

и вы можете получить через:e.getResponseBodyAsString();e.getStatusCode(); blabla для получения ответного сообщения при возникновении исключений.