【问题标题】:Spring boot not overriding Exception using @ControllerAdviceSpring Boot 不使用 @ControllerAdvice 覆盖异常
【发布时间】:2017-01-23 21:06:15
【问题描述】:

我想从控制器建议方面抛出一个标准的自定义异常,但由于某种原因,我的自定义异常没有被 spring boot (1.3.3-RELEASE) 捕获。

这是我的代码:

我的测试

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(MyApplication.class)
@WebIntegrationTest("server.port:9000") 
public class ControllerTest {
    private final String URL = "http://localhost:9000";

    @Test
    public void testCustomExceptionResponse() {
        // Invoke my controller generating some exception
        Map error = restTemplate.getForObject(URL+"/exception/", Map.class);
        assertTrue(error.get("exception").contains("MyCustomException"));
    }
}

控制器

@RequestMapping(value = "/", method = RequestMethod.GET)
public List<Object> findAll() throws Exception {
    // generate whatever exception here
    if (1<2) throw new IllegalIdentifierException("test whatever exception");
    return ccRepository.findByActive(true);
}

带有@ControllerAdvice注解的GlobalExceptionHandler

@ControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    // Catch whatever exception to throw my custom exception
    @ExceptionHandler(Exception.class)
    public void handleException(Exception ex) throws Exception {
        logger.error("Exception Occured: ", ex);
        throw new MyCustomException(ex.getLocalizedMessage());
    }
}

我已经调试了代码并且正在执行handleException方法,但是奇怪的是抛出了MyCustomException,但是控制器响应却返回了抛出的原始异常:

{timestamp=1473963128439, status=500, error=Internal Server Error, exception=org.hibernate.metamodel.relational.IllegalIdentifierException, message=test whatever exception, path=/exception/}

我希望有这样的东西:

exception=com.myapp.MyCustomException

据我所知,控制器建议是捕获控制器中的所有异常以绑定一些逻辑(在我的情况下是记录器)的通用方法,然后我使用自定义异常来定制意外异常.

我是否缺少有关 Spring Boot 如何处理异常的任何信息?

【问题讨论】:

  • 你是否在测试中使用SpringJUnit4ClassRunner runner?
  • @ChrisThompson,是的,刚刚更新了测试
  • 在测试中您要求/exception,但日志显示path=/creditcards/,所以也许您正在查看日志的错误部分?还是路由不正确?
  • @tonakai,对不起...我已经复制/粘贴/修改了,忘记修改日志了。
  • @PauChorro 没用

标签: java spring spring-mvc spring-boot


【解决方案1】:

这不完全是 ControllerAdvice 的目的。

发生了什么

  • 你抛出 IllegalIdentifierException
  • 您可以在 ControllerAdvice 中找到它
  • 你的 handleException 没有完成,因为你抛出了 MyCustomException
  • 这会在 DispatcherServlet 中引发异常,根本原因是您的原始异常 (IllegalIdentifierException)。

你应该怎么做

Controller Advice 旨在在发生错误时返回有效的 Http 响应。

例如,您可以将其更改为:

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleException(Exception ex) throws Exception {
        System.out.println("Exception Occured: " + ex);
        return ResponseEntity
                .status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body("Exception: " + ex.getLocalizedMessage());
    }
}

因此:

  • ControllerAdvice 的方法将成功完成(返回响应);
  • DispatcherServlet 很乐意为您服务。
  • 最初的异常不会成为新错误的根本原因,现在已被成功吞没
  • 客户端收到带有 HTTP 错误代码的消息“异常:测试任何异常”(我选择了 HttpStatus.INTERNAL_SERVER_ERROR)。

你可以用MockMvc进行测试:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Launcher.class)
@WebAppConfiguration
public class ControllerTest {
    @Autowired
    private WebApplicationContext webApplicationContext;
    
    @Test
    public void testCustomExceptionResponse() throws Exception {
        MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        
        mockMvc.perform(MockMvcRequestBuilders.get("/your/uri"))
        .andExpect(MockMvcResultMatchers.status().isInternalServerError())
        .andExpect(MockMvcResultMatchers.content().string("Exception: test whatever exception"));
        
        assertTrue(true);
    }
}

【讨论】:

  • 感谢您的回答。我会将其标记为已解决,因为它实际上教会了我正确的行为。但是,我找到了一种通过覆盖 ErrorAttributes 来解决我的问题的不同方法。如果发生一些特定的事情,我只是覆盖异常,我认为它比使用 ControllerAdivce 更好。你怎么看
【解决方案2】:

我刚刚根据您的代码创建了一个示例项目,请尝试更改此行:

Map error = restTemplate.getForObject("/exception/", Map.class);

Map error = restTemplate.getForObject("http://localhost:9000/", Map.class); 

由于您的RequestMapping 正在寻找/,我认为其他方法正在处理您的http 请求,这也解释了休眠错误消息,因为1&lt;2 一直返回true。

我的日志如下所示:

2016-09-15 22:21:32.101 ERROR 7688 --- [nio-9000-exec-1] tonakai.GlobalExceptionHandler       : Exception Occured: 

tonakai.IllegalIdentifierException: test whatever exception
    at tonakai.SampleController.findAll(SampleController.java:19) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_102]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_102]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_102]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_102]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221) ~[spring-web-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet

【讨论】:

  • 不幸的是,这并没有解决问题。如果您在测试用例中检查对象映射错误,您将拥有带有 IllegalIdentifierException 的异常字段,并且它应该有 MyCustomException。问题是这个assertTrue(error.get("exception").contains("MyCustomExceptio‌​n")); 不起作用
猜你喜欢
  • 2016-11-22
  • 2023-03-25
  • 1970-01-01
  • 2020-09-22
  • 2021-06-07
  • 2016-03-25
  • 2017-11-06
  • 2020-06-05
  • 1970-01-01
相关资源
最近更新 更多