Spring Boot @ControllerAdvice 部分工作,不适用于自定义异常

Posted

技术标签:

【中文标题】Spring Boot @ControllerAdvice 部分工作,不适用于自定义异常【英文标题】:Spring Boot @ControllerAdvice partially working, not working for custom exception 【发布时间】:2017-11-06 01:24:57 【问题描述】:

我在 Spring Boot 1.5.3 中使用 @ControllerAdvice 注释的 ExceptionHandler 遇到了一种特殊情况。它捕获任何异常默认异常,但如果我抛出自定义异常,它不会触发。

异常处理程序:

@ControllerAdvice
public class ResponseEntityExceptionHandler 

@ExceptionHandler( HttpMessageNotReadableException.class )
protected ResponseEntity<ErrorModel> handleInvalidJson(RuntimeException e, WebRequest request) 
    return new ResponseEntity<ErrorModel>(new ErrorModel().message("Could not parse JSON."), HttpStatus.BAD_REQUEST);


@ExceptionHandler( NumberFormatException.class )
protected ResponseEntity<ErrorModel> handleInvalidRequest(RuntimeException e, WebRequest request) 
    return new ResponseEntity<ErrorModel>(new ErrorModel().message("Invalid request parameter."), HttpStatus.BAD_REQUEST);


@ExceptionHandler( CannotCreateTransactionException.class )
protected ResponseEntity<ErrorModel> handleTransactionCreationException(RuntimeException e, WebRequest request) 
    return new ResponseEntity<ErrorModel>(new ErrorModel().message("Error connecting to the database, please make sure it is still available."), HttpStatus.BAD_REQUEST);


@ExceptionHandler( NotFoundException.class )
protected ResponseEntity<ErrorModel> handleApiException(RuntimeException e, WebRequest request) 
    return new ResponseEntity<ErrorModel>(new ErrorModel().message(e.getMessage()), HttpStatus.NOT_FOUND);


前 3 个异常都被捕获并按应有的方式处理,但底部的异常由默认的 Spring-Boot ExceptionHandler 处理。这是我在控制器中抛出的自定义异常:

public ResponseEntity<?> deleteActor(@ApiParam(value = "Used to identify a single actor.", required = true) @PathVariable("actor_id") Integer actorId, @RequestHeader("Accept") String accept) throws Exception 
Actor actor = actorRepository.findOne(actorId);
if (actor == null) 
    throw new NotFoundException(404, "Not found");

actorRepository.delete(actorId);
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);

我试过抛出这样的***异常之一:

public ResponseEntity<?> readActor(@ApiParam(value = "Used to identify a single actor.", required = true) @PathVariable("actor_id") Integer actorId, @RequestHeader("Accept") String accept) throws Exception 
    Actor actor = actorRepository.findOne(actorId);
    if (actor == null) 
        throw new NumberFormatException("");
    
    return new ResponseEntity<Actor>(actor, HttpStatus.OK);

这些处理得很好......

tomcat 日志也显示了这一点:

2017-06-05 11:30:20.080  INFO 9076 --- [           main] .m.m.a.ExceptionHandlerExceptionResolver : Detected @ExceptionHandler methods in responseEntityExceptionHandler

例外:

public class NotFoundException extends ApiException 
private int code;
public NotFoundException (int code, String msg) 
    super(code, msg);
    this.code = code;


异常继承自这个基类:

public class ApiException extends Exception
private int code;
public ApiException (int code, String msg) 
    super(msg);
    this.code = code;


关于为什么自定义异常避免被 ExceptionHandler 检测的任何想法?

如果有必要,我很乐意提供更多信息。

【问题讨论】:

【参考方案1】:

对于这种特殊情况,答案是使用Exception 而不是RuntimeException,因为 NotFoundException 只继承自 Exception。

其他值得注意的事情:

要捕获所有异常,可以使用@ExceptionHandler(Exception.class)

如果对异常使用通用名称,请始终检查您是否导入了正确的名称。

【讨论】:

我添加了您的建议,由于某种原因,它捕获了前 3 个异常,但没有捕获底部异常。让一个函数捕获所有异常也不是理想的行为。我宁愿现在捕获特定的,所以我可以返回自定义错误消息。 检查了,我正在导入正确的 NotFoundException :/,我也尝试抛出和捕获更一般的 ApiException,但没有成功。 好的,我最后一次尝试是在 handleApiException 中使用 Exception 而不是 RuntimeException:protected ResponseEntity handleApiException(Exception e, WebRequest request) return new ResponseEntity(new ErrorModel().消息(e.getMessage()), HttpStatus.NOT_FOUND); 天哪,你说的太对了!当然,它不会作为 RuntimeException 被捕获......它不是一个!非常感谢您发现:D 不客气。我可以更新上面的答案并将其标记为已解决吗?

以上是关于Spring Boot @ControllerAdvice 部分工作,不适用于自定义异常的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 2Spring Boot CLI

为啥 Spring Boot 应用程序 pom 同时需要 spring-boot-starter-parent 和 spring-boot-starter-web?

《02.Spring Boot连载:Spring Boot实战.Spring Boot核心原理剖析》

spring-boot-quartz, 依赖spring-boot-parent

spring-boot系列:初试spring-boot

Spring Boot:Spring Boot启动原理分析