有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Spring引导未使用@ControllerAdvice覆盖异常

我想从控制器建议方面抛出一个标准的自定义异常,但由于某些原因,我的自定义异常没有被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如何处理异常的内容


共 (2) 个答案

  1. # 1 楼答案

    这并不是ControllerAdvice的目的

    发生了什么事

    • 您抛出非法标识符异常
    • 你可以在你的控制器广告中看到它
    • 您的handleException未完成,因为您抛出了MyCustomException
    • 这将在DispatcherServlet中引发一个异常,原始异常(IllegaliIdentifierException)作为根本原因

    你该怎么办

    控制器建议用于在发生错误时返回有效的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的方法将成功完成(返回响应)
    • 调度员对你很满意
    • 最初的异常不会成为新错误的根本原因,现在已被成功吞没
    • 客户机接收到带有HTTP错误代码的消息“Exception:test which Exception”(我选择了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);
        }
    }
    
  2. # 2 楼答案

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

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

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

    由于您的RequestMapping正在查找/,我认为其他方法正在处理您的http请求,这也解释了hibernate错误消息,因为1<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