我们如何在 HandlerInterceptorAdapter 中 postHandle 异常?

How can we postHandle an exception in HandlerInterceptorAdapter?

我目前正在尝试为 spring 启动实现一个自定义的错误处理程序,我已经完成了以下操作:

 public class ExceptionHandler extends HandlerInterceptorAdapter {

 public static Logger log = LoggerFactory.getLogger(LoggingInterceptor.class);

 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        try {
          log.info("Service {} Calling {} on {} finished with status {}",request.getRemoteUser(), request.getMethod(), request.getRequestURI(), HttpStatus.valueOf(response.getStatus()));
        } catch (Exception e) {
            // Do nothing
        } finally {
            log.error("[Spring Boot Interceptor] {} returned with {}", handler, HttpStatus.valueOf(response.getStatus()));
    }
 }

不知何故这不起作用,异常仍然抛给客户端,例如有什么方法可以捕获该方法抛出的异常并忽略它。

管理异常的一个好方法是使用 @ControllerAdvice,使用它您可以处理任何类型的异常并根据需要自定义响应。

如评论中所述,您必须添加InterceptorRegistry以注册拦截器。

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new Interceptor()).addPathPatterns("/**");
    }
}

postHandle 中的 catch 块只有在 try-catch 块中发生异常时才会执行,如下所示,

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    try {
        int error = 1/0;
    } catch (Exception e) {
        log.info("Exception will be handled inside catch block");
    } 
}

现在让我们探索 @ControllerAdvice 来管理应用程序中的异常。这两个 API 将生成异常,我们将使用 @ExceptionHandler

管理异常
@GetMapping("/exception/404")
public void generateResourceNotFound() {
    throw new ResourceNotFoundException("resource not found");
}

@GetMapping("/exception/403")
public void generateAccessDenied() {
    throw new AccessDeniedException("access denied");
}

GlobalExceptionHandler.java

import com.learning.annotations.controller.ResourceNotFoundException;
import com.learning.annotations.dto.ErrorResponseDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    public Logger log = LoggerFactory.getLogger(Interceptor.class);

    @ExceptionHandler(AccessDeniedException.class)
    public ResponseEntity<ErrorResponseDTO> handleAccessDeniedException(AccessDeniedException ex, WebRequest request) {
        ErrorResponseDTO response = new ErrorResponseDTO();
        response.setError(ex.getMessage());
        response.setMessage("You don't have authority to access the resource");
        return new ResponseEntity<>(response, HttpStatus.FORBIDDEN);
    }

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponseDTO> handleResourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
        ErrorResponseDTO response = new ErrorResponseDTO();
        response.setError(ex.getMessage());
        response.setMessage("Resource might be moved temporary or not available");
        return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
    }
}

要自定义响应,我们可以创建错误响应 DTO,如下所示,

import lombok.Data;

@Data
public class ErrorResponseDTO {
    private String message;
    private String error;
}