由于异常不是从控制器而是从过滤器中引发的,所以 @ControllerAdvice 捕获不到它。
因此,在到处查找后我找到的最佳解决方案是为这些内部错误创建一个过滤器:
public class ExceptionHandlerFilter extends OncePerRequestFilter {
@Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
filterChain.doFilter(request, response);
} catch (JwtException e) {
setErrorResponse(HttpStatus.BAD_REQUEST, response, e);
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
setErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, response, e);
}
}
public void setErrorResponse(HttpStatus status, HttpServletResponse response, Throwable ex){
response.setStatus(status.value());
response.setContentType("application/json");
ApiError apiError = new ApiError(status, ex);
try {
String json = apiError.convertToJson();
System.out.println(json);
response.getWriter().write(json);
} catch (IOException e) {
e.printStackTrace();
}
}
}
将其添加到您的配置中,我正在使用WebSecurityConfigurerAdapter实现:
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
httpSecurity
.addFilterBefore(exceptionHandlerFilterBean(), JwtAuthenticationTokenFilter.class);
错误类:
public class ApiError {
private HttpStatus status;
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
private LocalDateTime timestamp;
private String message;
private String debugMessage;
private ApiError() {
timestamp = LocalDateTime.now();
}
public ApiError(HttpStatus status) {
this();
this.status = status;
}
public ApiError(HttpStatus status, Throwable ex) {
this();
this.status = status;
this.message = "Unexpected error";
this.debugMessage = ex.getLocalizedMessage();
}
public ApiError(HttpStatus status, String message, Throwable ex) {
this();
this.status = status;
this.message = message;
this.debugMessage = ex.getLocalizedMessage();
}
public String convertToJson() throws JsonProcessingException {
if (this == null) {
return null;
}
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper.writeValueAsString(this);
}
}