我们如何在 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;
}
我目前正在尝试为 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;
}