Spring Boot 全局异常处理

文章目录

  • Spring Boot 异常处理
    • 一. 异常处理
      • 1.1 全局异常处理类
      • 1.2 自定义异常类
      • 1.3 接口编写
    • 二. 过滤器异常处理
      • 2.1 工具类
      • 2.2 自定义处理类
      • 2.3 注入bean配置
      • 2.4 测试
    • 三. 拦截器异常处理
      • 3.1 自定义拦截器
      • 3.2 添加拦截器
      • 3.3 测试

Spring Boot 异常处理

RESTful API 调用时发生异常,需要拦截Exception,并转换成前端能处理统一响应的格式

一. 异常处理

通过Spring MVC 提供的注解@ControllerAdvice + @ExceptionHandler,来实现指定异常类的异常处理,转换成统一R响应

1.1 全局异常处理类

GlobalExceptionHandler

异常捕获:

  1. Validator 异常捕获处理
  2. ServiceException 异常捕获处理
  3. Exception 异常默认处理
/**
 * 全局异常处理类
 *
 * @author zhanghp
 * @date 2022-07-21 14:12
 */
@RestControllerAdvice
@AllArgsConstructor
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 自定义全局异常处理调用方法
     *
     * @param req servlet request
     * @param ex 异常信息
     * @return R
     */
    public  R<?> allExceptionHandler(HttpServletRequest req, Throwable ex){
        if (ex instanceof ServiceException) {
            return serviceExceptionHandler((ServiceException) ex);
        }
        return exceptionHandler(ex);
    }

    /**
     * 自定义异常处理
     *
     * @param ex 异常信息
     * @return R
     */
    @ExceptionHandler(ServiceException.class)
    public R<?> serviceExceptionHandler(ServiceException ex){
        log.warn("[serviceException]");
        return fail(INTERNAL_SERVER_ERROR.getCode(), ex.getMessage());
    }

    /**
     * 默认异常处理,兜底处理
     *
     * @param ex 异常信息
     * @return R
     */
    @ExceptionHandler(Exception.class)
    public R<?> exceptionHandler(Throwable ex){
        log.warn("[exception]");
        return fail(INTERNAL_SERVER_ERROR.getCode(), ex.getMessage());
    }
}

1.2 自定义异常类

ServiceException

说明:封装个性化异常处理

/**
 * @author zhanghp
 * @date 2022-07-22 17:49
 */
public class ServiceException extends RuntimeException{

    /**
     * 错误码
     */
    private Integer code;

    /**
     * 错误信息
     */
    private String msg;

    public ServiceException(ErrorCode errorCode){
        this.code = errorCode.getCode();
        this.msg = errorCode.getMsg();
    }

    public ServiceException(Integer code, String msg){
        this.code = code;
        this.msg = msg;
    }

    public ServiceException(){}

}

1.3 接口编写

ExController

调用即可,这里不做演示了

/**
 * @author zhanghp
 * @date 2022-07-21 14:14
 */
@RestController
@SuppressWarnings("all")
public class ExController {

    @GetMapping(value = "/ex", produces = "application/json; charset=utf-8")
    public R ex() {
        throw new ServiceException(400, "自定义异常");
    }
}

二. 过滤器异常处理

2.1 工具类

ServiceUtils

/**
 * @author zhanghp
 * @date 2022-07-22 16:39
 */
public class ServletUtils {

    /**
     * 渲染数据
     *
     * @param response servlet response
     * @param object 数据
     */
    public static void writeJson(HttpServletResponse response, Object object){
        String json = JsonUtils.toJsonString(object);
        ServletUtil.write(response, json, MediaType.APPLICATION_JSON_VALUE);
    }
}


JsonUtils

/**
 * @author zhanghp
 * @date 2022-07-22 16:42
 */
public class JsonUtils {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 数据 -》json string
     *
     * @param object 数据
     * @return json string
     */
    @SneakyThrows
    public static String toJsonString(Object object) {
        return objectMapper.writeValueAsString(object);
    }
}


2.2 自定义处理类

过滤器的异常被拦截后,走不到全局异常处理类里,所以在其里面catch异常并统一处理
MyFilter

/**
 * @author zhanghp
 * @date 2022-07-22 16:01
 */
@Component
@RequiredArgsConstructor
public class MyFilter extends OncePerRequestFilter {

    private final GlobalExceptionHandler globalExceptionHandler;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        try {
            System.out.println("123");
//            int i = 1/0;
        } catch (Exception e) {
            R<?> r = globalExceptionHandler.allExceptionHandler(e);
            ServletUtils.writeJson(response, r);
            return;
        }
        chain.doFilter(request, response);
    }
}


2.3 注入bean配置

FilterConfig

/**
 * @author zhanghp
 * @date 2022-07-22 16:24
 */
@Component
public class FilterConfig implements WebMvcConfigurer {

    /**
     * 创建过滤器实例
     *
     * @param filter 过滤器
     * @param order  过滤顺序
     * @param     继承Filter
     * @return FilterRegistrationBean
     */
    public static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) {
        FilterRegistrationBean<T> bean = new FilterRegistrationBean<>(filter);
        bean.setOrder(order);
        return bean;
    }

    /**
     * 添加MyFilter Bean
     *
     * @param globalExceptionHandler 自定义全局异常
     * @return 过滤器bean
     */
    @Bean
    public FilterRegistrationBean<MyFilter> demoFilter(GlobalExceptionHandler globalExceptionHandler) {
        return createFilterBean(new MyFilter(globalExceptionHandler), 1);
    }
}


2.4 测试

调用1.3接口编写的Controller即可


三. 拦截器异常处理

拦截器的异常也不走全局异常,在过滤时,直接抛出了,也拦截不到,所以在其里面catch异常并返回,做到统一处理

过滤器异常处理方式大径相庭,给大家写简单写一下

3.1 自定义拦截器

MyInterceptor

/**
 * @author zhanghp
 * @date 2022-07-22 15:51
 */
@Component
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}


3.2 添加拦截器

InterceptorConfig

/**
 * @author zhanghp
 * @date 2022-07-22 15:58
 */
@Component
public class InterceptorConfig implements WebMvcConfigurer {
    @Autowired
    private MyInterceptor filter;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加拦截器
        registry.addInterceptor(filter);
    }
}


3.3 测试

调用1.3接口编写的Controller即可


源码:https://gitee.com/zhp1221/ruoyi/tree/master/lab_01_web_module/lab_02_unified_handle

你可能感兴趣的:(ruoyi,spring,boot,java,spring)