2017-07-28 26 views
0

我正在使用Spring Boot進行Restful Web Services。Spring Boot - 使用RestControllerAdvice的全局自定義異常處理機制

試圖建立一個全局的自定義異常處理機制,它依賴於@RestControllerAdvice,它可以處理已知但未知的異常。

的pom.xml

<parent> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-parent</artifactId> 
    <version>1.5.4.RELEASE</version> 
</parent> 

<properties> 
    <java.version>1.8</java.version> 
</properties> 

<repositories> 
    <repository> 
     <id>spring-releases</id> 
     <url>https://repo.spring.io/libs-release</url> 
    </repository> 
</repositories> 

<pluginRepositories> 
    <pluginRepository> 
     <id>spring-releases</id> 
     <url>https://repo.spring.io/libs-release</url> 
    </pluginRepository> 
</pluginRepositories> 

<dependencies> 
    <!-- Spring --> 
    <dependency> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-web</artifactId> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-test</artifactId> 
     <scope>test</scope> 
    </dependency> 
</dependencies> 

GlobalControllerExceptionHandler:

@RestControllerAdvice 
public class GlobalControllerExceptionHandler { 

    private static final Logger LOG = Logger.getLogger(GlobalControllerExceptionHandler.class); 

    @ExceptionHandler(value = { ConstraintViolationException.class }) 
    @ResponseStatus(HttpStatus.BAD_REQUEST) 
    public ApiErrorResponse constraintViolationException(ConstraintViolationException ex) { 
     LOG.error(ex.getCause().toString()); 
     return new ApiErrorResponse(400, "Bad Request"); 
    } 

    @ExceptionHandler(value = { NoHandlerFoundException.class }) 
    @ResponseStatus(HttpStatus.NOT_FOUND) 
    public ApiErrorResponse noHandlerFoundException(Exception ex) { 
     LOG.error(ex.getCause().toString()); 
     return new ApiErrorResponse(404, "Resource Not Found"); 
    } 

    @ExceptionHandler(value = { Exception.class }) 
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) 
    public ApiErrorResponse unknownException(Exception ex) { 
     LOG.error(ex.getCause().toString()); 
     return new ApiErrorResponse(500, "Internal Server Error"); 
    } 
} 

ApiErrorResponse:

public class ApiErrorResponse { 

    private int status; 
    private String message; 

    public ApiErrorResponse(int status, String message) { 
     this.status = status; 
     this.message = message; 
    } 

    public int getStatus() { 
     return status; 
    } 

    public String getMessage() { 
     return message; 
    } 

    @Override 
    public String toString() { 
     return new ToStringBuilder(this).append(status) 
             .append(message) 
             .toString(); 
    } 
} 

與此問題是,當我使用第三方庫做一些事情, 的未知的異常可能是404,但是返回爲500!

例如使用ElasticSearch具有未知指數(故意看到異常的類型):

{ 
    "timestamp": 15, 
    "status": 500, 
    "error": "Internal Server Error", 
    "exception": "org.elasticsearch.client.ResponseException", 
    "message": "POST http://localhost:9200/fn3r4343/_search?pretty=true: HTTP/1.1 404 Not Found" 
     { 
     "error": { 
      "root_cause": [ 
       { 
        "type": "index_not_found_exception", 
        "reason": "no such index", 
        "resource.type": "index_or_alias", 
        "resource.id": "fn3r4343", 
        "index_uuid": "_na_", 
        "index": "fn3r4343" 
       } 
      ], 
      "type": "index_not_found_exception", 
      "reason": "nosuchindex", 
      "resource.type": "index_or_alias", 
      "resource.id": "fn3r4343", 
      "index_uuid": "_na_", 
      "index": "fn3r4343" 
     } 
     { "root_cause" : 
      [ 
       { 
        "type" :"index_not_found_exception", 
        "reason" : no such index", "resource.type" : "index_or_alias", 
        "resource.id" : "fn3r4343", 
        "index_uuid" : "_na_", 
        "index" : "fn3r4343" 
       } 
      ], 
      [ 
        { 
        "type" : "index_not_found_exception", 
        "reason" : "no such index", 
        "resource.type" : "index_or_alias", 
        "resource.id" : "fn3r4343", 
        "index_uuid" : "_na_", 
        "index" : "fn3r4343" 
       }, 
       "status": 404 
       ] 
     } 
     "path": "/myapp/search" 
} 

正如人們所看到的,這將返回一個HTTP 500狀態,但在有效載荷其真正HTTP 404!

我所尋求的是返回的是:

{ 
    "message" : "Index Not Found Exception", 
    "status" : "HTTP 404" 
} 

而對於已知的HTTP 404例外:

是否有一個很好的做法/機構使用RestControllerAdvice捕捉任何類型的異常並將響應自定義爲JSON格式,該格式對於使用REST API的客戶端可讀/有用?

這個職位是不是真的具體到彈性搜索,而是通過嘗試使用@RestControllerAdvice處理任何類型的異常放的客戶端應用程序的正確響應尋求如何...

回答

1

正在被提出的基礎異常是org.elasticsearch.client.ResponseException(你可能使用低級別的REST客戶端)。

因此,在你的建議,你需要添加一個處理該異常並返回底層的狀態代碼:

@ExceptionHandler(value = { ResponseException.class }) 
public ApiErrorResponse noHandlerFoundException(Exception ex) { 
    LOG.error(ex.getCause().toString()); 
    int status = ((ResponseException) ex).getResponse().getStatusLine().getStatusCode(); 
    return new ApiErrorResponse(status, "<some message depending on status code>"); 
} 
+0

謝謝@Val ...我正在使用低級別的REST客戶端。你的解決方案有很多幫助,但我怎麼能得到實際的異常消息?順便說一句,我們彼此認識Java Ranch,歡呼! –

0

我覺得這下面類應該幫助:

@ControllerAdvice 
public class CustomExceptionHandler extends ResponseEntityExceptionHandler { 


@ExceptionHandler(value = {MyException.class}) 
protected ResponseEntity<Object> handleConflict(Exception exception, WebRequest request) 
{ 
    FinalResponse response = new FinalResponse()//Define this Bean in a way that it contains all required paramteres to be sent in response when exception occurs 
    response.setErrorCd("123"); 
    response.setMessage("Exception while processing."); 
    if (exception instanceof MyException) 
    { 
     return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); 
    } 
    else 
    { 
     return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); 
    } 
} 
} 
+0

謝謝你,但如果在MyException.class屬於第三方LIB(如彈性搜索)?有沒有一種通用的方式來獲得任何類型的異常拋出?另外,我會在哪裏獲得response.setErrorId(「123」)的實際數字?我認爲得到實際的數字是解決我的問題的關鍵。調用的RestController如何使用它(例如,將爲Web請求插入什麼)? –

+0

通過在代碼中添加try catch來拋出該第三方異常並拋出自己的異常。即使你不這樣做,我提到將在我提供的邏輯的ELSE部分中處理,但這不會是信息。所以包裝第三方異常類會更好。 另外我曾經提到過定義你自己的FinalResponse類,當你發生特定的錯誤時,你需要提供一個字段作爲輸出。理想情況下,應該在錯誤響應時定義錯誤代碼和corressponding消息。 –