项目中使用springboot Security的时候,配置的ControllerAdvice全局异常失效了
正常使用全局异常捕获没有问题,我是这样使用的
- GlobalExceptionHanlder
//基于@ControllerAdvice注解的Controller层的全局异常统一处理
@ControllerAdvice
public class GlobalExceptionHanlder {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHanlder.class);
// Throwable是所有异常的父类
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(value = Throwable.class)
@ResponseBody
public RestResponse<Object> handler(HttpServletRequest req, Throwable throwable){
String errmsg = throwable.getMessage();
StackTraceElement[] stackTraceElements = throwable.getStackTrace();
if (stackTraceElements.length != 0){
StackTraceElement stackTraceElement = stackTraceElements[0];
errmsg += "\n" + "问题出处:" + stackTraceElement.toString();
}
logger.error(errmsg, throwable);
RestCode restCode = Exception2CodeRepo.getCode(throwable);
RestResponse<Object> response = RestResponse.error(restCode);
return response;
}
}
- Exception2CodeRepo,这类是把常出现的异常统一识别处理了
public class Exception2CodeRepo {
private static Object getType(Throwable throwable) {
try {
return FieldUtils.readDeclaredField(throwable, "type", true);
} catch (Exception e) {
return null;
}
}
public static RestCode getCode(Throwable throwable) {
if (throwable == null) {
return RestCode.UNKNOWN_ERROR_NULL;
}
RestCode restCode = exceptionType(throwable);
return restCode;
}
private static RestCode exceptionType(Throwable throwable){
/**
* HttpMediaTypeNotSupportedException
*/
String exceptionString = throwable.toString();
if (exceptionString.contains("HttpMessageConversionException")){
return RestCode.PARSMS_TYPE_ERROR;
}else if (exceptionString.contains("NullPointerException")
|| exceptionString.contains("BeanPropertyBindingResult")
|| exceptionString.contains("MissingServletRequestParameterException")
|| exceptionString.contains("MethodArgumentNotValidException")){
return RestCode.ParamsAndInstanceIsNull;
}else if (exceptionString.contains("HttpMediaTypeNotSupportedException")){
return RestCode.HttpMediaTypeNotSupportedException;
}else if (exceptionString.contains("HttpRequestMethodNotSupportedException")){
return RestCode.HttpRequestMethodNotSupportedException;
}else if (exceptionString.contains("HttpMessageNotReadableException")
|| exceptionString.contains("JsonParseException")
|| exceptionString.contains("JSONException")){
return RestCode.JsonParseException;
}else if (exceptionString.contains("DuplicateKeyException")){
return RestCode.RepeatAddData;
}else if (exceptionString.contains("MissingServletRequestPartException")){
return RestCode.NoNeedUploadFile;
}else if (exceptionString.contains("请登录")){
return RestCode.NoLogin;
}else if (exceptionString.contains("请注册")){
return RestCode.NoRegister;
}else if (exceptionString.contains("登录已过期")){
return RestCode.LoginTokenExpired;
}else if (exceptionString.contains("token无效")){
return RestCode.TokenInvalid;
}
return RestCode.UNKNOWN_ERROR;
}
}
接下来出现问题了
当你项目中使用springboot Security的时候,上面配置的全局异常失效了。这是因为Security的异常捕获覆盖了ControllerAdvice或者他们有冲突了导致失效,这个时候需要改变或者拦截Security的异常。【我在百度上,搞了好长时间,都没有找到问题,最后不得已去了google】
- 1、处理如下,修改原来的全局异常,继承OncePerRequestFilter
@Component
public class GlobalExceptionHanlderFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHanlderFilter.class);
public void handler(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Throwable throwable) throws IOException {
String errmsg = throwable.getMessage();
StackTraceElement[] stackTraceElements = throwable.getStackTrace();
if (stackTraceElements.length != 0){
StackTraceElement stackTraceElement = stackTraceElements[0];
errmsg += "\n" + "问题出处:" + stackTraceElement.toString();
}
logger.error(errmsg, throwable);
RestCode restCode = Exception2CodeRepo.getCode(throwable);
RestResponse<Object> response = RestResponse.error(restCode);
PrintWriterOut.writeOut(httpServletRequest, httpServletResponse, 200, response);
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
try {
filterChain.doFilter(httpServletRequest, httpServletResponse);
}catch (Throwable e) {
this.handler(httpServletRequest, httpServletResponse, e);
}
}
}
- 2、配置Security中的异常过滤器,直接覆盖这个bean就行。把自定义的过滤器添加进去
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new GlobalExceptionHanlderFilter());
// 任何接口路径都要执行
bean.addUrlPatterns("/*");
// 优先级最高
bean.setOrder(Integer.MIN_VALUE);
return bean;
}