Spring Boot 不使用@ControllerAdvice 覆盖异常

Fed*_*zza 5 java spring spring-mvc spring-boot

我想从控制器建议方面抛出一个标准的自定义异常,但由于某种原因,我的自定义异常没有被 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"));
    }
}
Run Code Online (Sandbox Code Playgroud)

控制器

@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);
}
Run Code Online (Sandbox Code Playgroud)

使用 @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());
    }
}
Run Code Online (Sandbox Code Playgroud)

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

{timestamp=1473963128439, status=500, error=Internal Server Error, exception=org.hibernate.metamodel.relational.IllegalIdentifierException, message=test whatever exception, path=/exception/}
Run Code Online (Sandbox Code Playgroud)

我期待有这样的事情:

exception=com.myapp.MyCustomException
Run Code Online (Sandbox Code Playgroud)

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

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

ale*_*xbt 3

这并不完全是 ControllerAdvice 的目的。

怎么了

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

你应该做什么

控制器建议旨在在发生错误时返回有效的 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());
    }
}
Run Code Online (Sandbox Code Playgroud)

因此:

  • 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);
    }
}
Run Code Online (Sandbox Code Playgroud)