Java 当找不到匹配的处理程序时,如何调用SpringMVC拦截器
我有一个简单的Spring Boot 2.1应用程序,带有Spring拦截器和Java 当找不到匹配的处理程序时,如何调用SpringMVC拦截器,java,spring,spring-boot,interceptor,exceptionhandler,Java,Spring,Spring Boot,Interceptor,Exceptionhandler,我有一个简单的Spring Boot 2.1应用程序,带有Spring拦截器和@RestControllerAdvice 我的要求是在所有情况下调用Spring拦截器,包括发生异常时 对于自定义异常,会调用拦截器处理程序方法,例如preHandle()和afterCompletion()。但是,对于由ResponseEntityExceptionHandler处理的异常,不会调用Spring拦截器(我需要ResponseEntityExceptionHandler的方法来创建一个自定义respo
@RestControllerAdvice
我的要求是在所有情况下调用Spring拦截器,包括发生异常时
对于自定义异常,会调用拦截器处理程序方法,例如preHandle()
和afterCompletion()
。但是,对于由ResponseEntityExceptionHandler
处理的异常,不会调用Spring拦截器(我需要ResponseEntityExceptionHandler
的方法来创建一个自定义responseBy
以发回,但是,我还需要触发拦截器的完成后()
用于审计目的)
例如,如果使用补丁
HTTP方法发出REST请求,则它只执行PersonControllerExceptionHandler.handleHttpRequestMethodNotSupported()
,并且不调用PersonInterceptor
异常处理程序:
@RestControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class PersonControllerExceptionHandler extends ResponseEntityExceptionHandler {
private final static Logger LOGGER = LoggerFactory.getLogger(PersonControllerExceptionHandler.class);
@ExceptionHandler(value = {PersonException.class })
public ResponseEntity<Object> handlePersonException(PersonException exception) {
LOGGER.info("Person exception occurred");
return new ResponseEntity<Object>(new Person("Bad Age", -1),
HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(value = {Exception.class })
public ResponseEntity<Object> handleException(Exception exception) {
LOGGER.info("Exception occurred");
return new ResponseEntity<Object>(new Person("Unknown Age", -100),
HttpStatus.INTERNAL_SERVER_ERROR);
}
@Override
public ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
LOGGER.info("handleHttpRequestMethodNotSupported()...");
return new ResponseEntity<>(new Person("Argh!", 900), HttpStatus.METHOD_NOT_ALLOWED);
}
}
@Order(Ordered.HIGHEST_PRECEDENCE)
public class PersonInterceptor extends HandlerInterceptorAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(PersonInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
LOGGER.info("PersonInterceptor#preHandler()...");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
LOGGER.info("PersonInterceptor#postHandler()...");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
LOGGER.info("PersonInterceptor#afterCompletion()...");
if (ex != null) {
LOGGER.error("afterCompletion(): An exception occurred", ex);
}
}
}
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new PersonInterceptor()).addPathPatterns("/person/*");
}
}
@RestController
@RequestMapping("/")
public class PersonController {
private final static Logger LOGGER = LoggerFactory.getLogger(PersonController.class);
@Autowired
private PersonService personService;
@GetMapping(path = "/person/{age}", produces = MediaType.APPLICATION_JSON_VALUE)
public Person getPerson(@PathVariable("age") Integer age) throws PersonException {
LOGGER.info("Age: {}", age);
return personService.getPerson(age);
}
}
注册拦截器:
@RestControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class PersonControllerExceptionHandler extends ResponseEntityExceptionHandler {
private final static Logger LOGGER = LoggerFactory.getLogger(PersonControllerExceptionHandler.class);
@ExceptionHandler(value = {PersonException.class })
public ResponseEntity<Object> handlePersonException(PersonException exception) {
LOGGER.info("Person exception occurred");
return new ResponseEntity<Object>(new Person("Bad Age", -1),
HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(value = {Exception.class })
public ResponseEntity<Object> handleException(Exception exception) {
LOGGER.info("Exception occurred");
return new ResponseEntity<Object>(new Person("Unknown Age", -100),
HttpStatus.INTERNAL_SERVER_ERROR);
}
@Override
public ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
LOGGER.info("handleHttpRequestMethodNotSupported()...");
return new ResponseEntity<>(new Person("Argh!", 900), HttpStatus.METHOD_NOT_ALLOWED);
}
}
@Order(Ordered.HIGHEST_PRECEDENCE)
public class PersonInterceptor extends HandlerInterceptorAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(PersonInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
LOGGER.info("PersonInterceptor#preHandler()...");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
LOGGER.info("PersonInterceptor#postHandler()...");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
LOGGER.info("PersonInterceptor#afterCompletion()...");
if (ex != null) {
LOGGER.error("afterCompletion(): An exception occurred", ex);
}
}
}
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new PersonInterceptor()).addPathPatterns("/person/*");
}
}
@RestController
@RequestMapping("/")
public class PersonController {
private final static Logger LOGGER = LoggerFactory.getLogger(PersonController.class);
@Autowired
private PersonService personService;
@GetMapping(path = "/person/{age}", produces = MediaType.APPLICATION_JSON_VALUE)
public Person getPerson(@PathVariable("age") Integer age) throws PersonException {
LOGGER.info("Age: {}", age);
return personService.getPerson(age);
}
}
控制器:
@RestControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class PersonControllerExceptionHandler extends ResponseEntityExceptionHandler {
private final static Logger LOGGER = LoggerFactory.getLogger(PersonControllerExceptionHandler.class);
@ExceptionHandler(value = {PersonException.class })
public ResponseEntity<Object> handlePersonException(PersonException exception) {
LOGGER.info("Person exception occurred");
return new ResponseEntity<Object>(new Person("Bad Age", -1),
HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(value = {Exception.class })
public ResponseEntity<Object> handleException(Exception exception) {
LOGGER.info("Exception occurred");
return new ResponseEntity<Object>(new Person("Unknown Age", -100),
HttpStatus.INTERNAL_SERVER_ERROR);
}
@Override
public ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
LOGGER.info("handleHttpRequestMethodNotSupported()...");
return new ResponseEntity<>(new Person("Argh!", 900), HttpStatus.METHOD_NOT_ALLOWED);
}
}
@Order(Ordered.HIGHEST_PRECEDENCE)
public class PersonInterceptor extends HandlerInterceptorAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(PersonInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
LOGGER.info("PersonInterceptor#preHandler()...");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
LOGGER.info("PersonInterceptor#postHandler()...");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
LOGGER.info("PersonInterceptor#afterCompletion()...");
if (ex != null) {
LOGGER.error("afterCompletion(): An exception occurred", ex);
}
}
}
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new PersonInterceptor()).addPathPatterns("/person/*");
}
}
@RestController
@RequestMapping("/")
public class PersonController {
private final static Logger LOGGER = LoggerFactory.getLogger(PersonController.class);
@Autowired
private PersonService personService;
@GetMapping(path = "/person/{age}", produces = MediaType.APPLICATION_JSON_VALUE)
public Person getPerson(@PathVariable("age") Integer age) throws PersonException {
LOGGER.info("Age: {}", age);
return personService.getPerson(age);
}
}
起初我认为这与@Ordered
有关,但尝试各种场景时,我给PersonInterceptor
一个比@RestControllerAdvice
更高的优先级会产生同样的不良结果(反之亦然)
在深入研究Spring框架之后,似乎如果找不到处理程序,就会将异常抛出回DispatcherServlet#doDispatch()
,该异常进入catch
块,因此,它会跳过拦截器映射过程,包括afterCompletion()
(我使用Spring5.1
。作为跟踪执行路径的示例):
HandlerExecutionChain
HandlerMapping
;失败的是RequestMappingHandlerMapping
修补程序getPerson()
,而是获取getPerson()
,无法找到匹配的模式在没有处理程序匹配的情况下,我是否缺少触发拦截器的
afterCompletion()
?这是一个非常古老且非常破碎的spring功能,既不是RestControllerAdvice,也不是ControllerAdvice或ErrorController(已弃用)当涉及404处理时,按照预期工作。遗憾的是,这一直是这个标志性的spring错误。谢谢。您建议在spring框架中使用什么来处理全局和容器错误呢?我不认为有人反对。