【问题标题】:Custom Exception in Spring boot Application FailsSpring Boot 应用程序中的自定义异常失败
【发布时间】:2020-08-17 00:27:55
【问题描述】:

我正在尝试在发生异常时自定义我的响应对象(默认情况下,它将显示上下文路径和其他技术细节作为响应)。我发现我们可以使用@ControllerAdvice 注解来实现这一点。

但我遇到的问题是,每当发生 HttpMessageNotReadableException 时,我都想抛出一个自定义异常。我尝试了类似下面的东西。但是 Spring 应用程序无法启动。

@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {

@ExceptionHandler(value = {HttpMessageNotReadableException.class})
    protected ResponseEntity<ExceptionResDto> handleException(){
        ExceptionResDto response = new ExceptionResDto();
        .......
        return new ResponseEntity<ExceptionResDto>(response, new HttpHeaders(), HttpStatus.BAD_REQUEST);
    }

但如果我做了这样的事情,它会起作用!!! (重写当前可用的方法来捕获 HttpMessageNotReadableException)

@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
    .... //customized code
        return new ResponseEntity<Object>(response, new HttpHeaders(), status);
}

我的问题是 @ExceptionHandler(value = {CustomException.class}) 仅用于自定义异常?不能习惯现有的更一般的例外吗?为了定制这样的通用异常,我们是否总是需要重写它们原有的异常处理方法?

以下是日志结果。

(AbstractAutowireCapableBeanFactory.java:409)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1620)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
    ... 49 common frames omitted
2020-05-03 14:38:41.565 [main] ERROR o.s.boot.SpringApplication -
                Application startup failed 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'handlerExceptionResolver' defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerExceptionResolver]: Factory method 'handlerExceptionResolver' threw exception; nested exception is java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class org.springframework.http.converter.HttpMessageNotReadableException]: {protected org.springframework.http.ResponseEntity lk.crm.dialog.config.CustomExceptionHandler.myHandleException(), public final org.springframework.http.ResponseEntity org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler.handleException(java.lang.Exception,org.springframework.web.context.request.WebRequest)}
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1067)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:314)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151)
    at lk.crm.dialog.Application.main(Application.java:17)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.base/java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerExceptionResolver]: Factory method 'handlerExceptionResolver' threw exception; nested exception is java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class org.springframework.http.converter.HttpMessageNotReadableException]: {protected org.springframework.http.ResponseEntity lk.crm.dialog.config.CustomExceptionHandler.myHandleException(), public final org.springframework.http.ResponseEntity org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler.handleException(java.lang.Exception,org.springframework.web.context.request.WebRequest)}
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
    ... 26 common frames omitted
Caused by: java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class org.springframework.http.converter.HttpMessageNotReadableException]: {protected org.springframework.http.ResponseEntity lk.crm.dialog.config.CustomExceptionHandler.myHandleException(), public final org.springframework.http.ResponseEntity org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler.handleException(java.lang.Exception,org.springframework.web.context.request.WebRequest)}
    at org.springframework.web.method.annotation.ExceptionHandlerMethodResolver.addExceptionMapping(ExceptionHandlerMethodResolver.java:109)
    at org.springframework.web.method.annotation.ExceptionHandlerMethodResolver.<init>(ExceptionHandlerMethodResolver.java:76)
    at org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.initExceptionHandlerAdviceCache(ExceptionHandlerExceptionResolver.java:269)
    at org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.afterPropertiesSet(ExceptionHandlerExceptionResolver.java:245)
    at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.addDefaultHandlerExceptionResolvers(WebMvcConfigurationSupport.java:883)
    at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration.configureHandlerExceptionResolvers(WebMvcAutoConfiguration.java:428)
    at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.handlerExceptionResolver(WebMvcConfigurationSupport.java:826)
    at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration$$EnhancerBySpringCGLIB$$901be0b6.CGLIB$handlerExceptionResolver$41(<generated>)
    at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration$$EnhancerBySpringCGLIB$$901be0b6$$FastClassBySpringCGLIB$$b8bb3bfc.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356)
    at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration$$EnhancerBySpringCGLIB$$901be0b6.handlerExceptionResolver(<generated>)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.base/java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
    ... 27 common frames omitted

【问题讨论】:

    标签: java spring spring-boot exception


    【解决方案1】:

    为什么要在异常处理程序中抛出另一个异常? 我猜你想要的是在一个中心位置(你的处理程序)捕获抛出的异常,也许用更多的细节记录错误(我肯定会建议这样做),并用总结的细节给客户一个即时的响应。

    不要抛出另一个异常,而是抛出一个自定义异常模型,该模型包含您希望以 json 格式返回的内容。

        public class CustomExceptionModel{
    
        private String message
        private HttpStatus httpStatus
        private ZonedTime timestamp
    
        public Custom{ExceptionModel (String message, HttpStatus httpStatus){
    this.message = message;
    this.httpStatus = httpStatus;
    this.timeStamp = ZonedTime.now();
        }
        }
    

    你的处理程序应该是这样的

    @ExceptionHandler(value = {HttpMessageNotReadableException.class})
        protected ResponseEntity<ExceptionResDto> handleException(HttpMessageNotReadableException ex){
           log.severe("Put details here ;) ");
            return new ResponseEntity<CustomExceptionModel>(new CustomExceptionModel(ex.getMessage(), ex.getStatus()), HttpStatus.BAD_REQUEST);
        }
    

    这将完全按照您需要的内容将 Json 作为异常抛出。我建议使用时间戳,一条具有非常普遍原因的消息(我的意思不是整个堆栈跟踪。您可以将其放在您的 log.severe () 例如和 httpStatuscode 中。我知道状态代码也添加到 responseEntity 对象中,但是我喜欢让它显示在 json 中。

    更新: 我刚刚看到您将异常处理方法称为“handleException”。当您正确扩展 ResponseEntityExceptionhandler 时,您已经是一个以相同方式命名的方法。所以春天很困惑。尝试重命名您的异常处理方法。我更喜欢使用异常的名称,并在其前面加上句柄,如 handleHttpMethodNotReadableException。 希望这会有所帮助

    【讨论】:

    • 感谢您的回复。我不想在我的 @ExceptionHandler 体内抛出异常。相反,我想要像你提到的那样的确切场景。但是如果我想出一个像上面这样的解决方案,spring 应用程序将无法启动。有什么想法吗?
    • 你能提供日志吗?
    • 有点冗长。我从应用程序失败的地方添加了日志。更新了我的问题。
    • 我已经更改了我的异常处理方法的名称。但仍然得到同样的错误。顺便说一句,没有称为handleException的spring异常处理方法。有一个叫做handleExceptionInternal。
    猜你喜欢
    • 1970-01-01
    • 2023-03-04
    • 2019-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    • 2014-12-16
    • 2021-07-10
    相关资源
    最近更新 更多