场景:
SpringBoot项目中,定义了
全局异常捕获类
,但是当在Filter
校验Token失败后抛出异常
时,无法捕获异常
。
原因分析:
SpringBoot中,通过@ControllerAdvice+@ExceptionHandler实现的
全局异常捕获类
,只捕获Controller层的异常
,众所周知,Filter是在Controller层之前。
解决方案:
1.新增异常过滤器Filter,将异常转移到Controller
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
/**
* <p> @Title ExceptionFilter
* <p> @Description 异常过滤器
*
* @author ACGkaka
* @date 2021/6/17 9:53
*/
@Slf4j
@Component
public class ExceptionFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (Exception e) {
// 异常捕获,发送到error controller
request.setAttribute("filter.error", e);
//将异常分发到/error/exthrow控制器
request.getRequestDispatcher("/error/exthrow").forward(request, response);
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
2.实例化ExceptionFilter
import cn.demo.project.common.filter.AccessTokenFilter;
import cn.demo.project.common.filter.ExceptionFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* <p> @Title FilterConfig
* <p> @Description 过滤器配置类
*
* @author ACGkaka
* @date 2021/6/16 18:08
*/
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean exceptionFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new ExceptionFilter());
registration.setName("ExceptionFilter");
//此处尽量小,要比其他Filter靠前
registration.setOrder(-1);
return registration;
}
}
3.实现Controller接收过过滤器发来的异常
@RestController
public class ErrorController {
/**
* 重新抛出异常
*/
@RequestMapping("/error/exthrow")
public void rethrow(HttpServletRequest request) {
throw ((Exception) request.getAttribute("filter.error"));
}
}
4.用全局异常处理器接收异常
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* <p> @Title GlobalExceptionHandler
* <p> @Description 全局异常捕获
*
* @author ACGkaka
* @date 2021/4/30 17:27
*/
@RestControllerAdvice(annotations = RestController.class)
public class GlobalExceptionHandler {
/**
* 捕获自定义异常,返回json信息
* @param req HttpServletRequest
* @param exception 自定义异常
* @return 异常信息
*/
@ExceptionHandler({RuntimeException.class})
@ResponseBody
public Map<String, Object> errorHandle(HttpServletRequest req, RuntimeException exception) {
return initResultMap(req.getRequestURI(), 500, exception);
}
/**
* 捕获系统异常
*
* @param exception 系统异常
* @return 异常信息
*/
@ExceptionHandler({Exception.class})
@ResponseBody
public Map<String, Object> errorHandle(HttpServletRequest req, Exception exception) {
exception.printStackTrace();
return initResultMap(req.getRequestURI(), 500, exception);
}
/**
* 初始化返回Map
*
* @param url 请求地址
* @param code 状态码
* @param exception 异常
* @return Map
*/
private Map<String, Object> initResultMap(String url, int code, Exception exception) {
Map<String, Object> map = new HashMap<>();
map.put("code", code);
map.put("exception",exception);
map.put("message", exception.getMessage());
map.put("url", url);
return map;
}
}
整理完毕,完结撒花~
参考文章:https://www.icode9.com/content-4-842478.html