@ExceptionHandler or HandlerExceptionResolver?如何优雅处理全局异常?【享学Spring MVC】(下)

简介: @ExceptionHandler or HandlerExceptionResolver?如何优雅处理全局异常?【享学Spring MVC】(下)

如何优雅统一处理Filter异常


因为我们无法通过@ControllerAdvice+@ExceptionHandler的方式去处理Filter过滤器抛出的异常(理由希望读者自己能明白),所以此处我提供较为优雅的处理方式作为参考。

传统Spring MVC


指导思想步骤:


  1. catch住Filter所有异常
  2. 把Exception放进请求attr属性里
  3. 把该请求forward转发到专门处理错误的Controller里
  4. 该Controller里拿出异常throw出去,从而便可交给全局异常统一处理了


附参考代码:

Filter:


@Component("helloFilter")
@WebFilter(urlPatterns = "/*")
public class HelloFilter extends OncePerRequestFilter {
    @Override
    protected void initFilterBean() throws ServletException {
        System.out.println("HelloFilter初始化...");
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            System.out.println(1 / 0);
            filterChain.doFilter(request, response);
        } catch (Exception e) { // 捕获所有异常做转发用
            request.setAttribute(ErrorController.EXCEPTION_ATTR, e);
            request.getRequestDispatcher(ErrorController.ERROR_URL).forward(request, response);
        }
    }
}


ErrorController:


@Slf4j
@RestController
public class ErrorController {
    public static final String ERROR_URL = "/do/filter/errors";
    public static final String EXCEPTION_ATTR = ErrorController.class.getName() + ".error";
    /**
     * 把Filter里的异常同意交给全局异常处理
     */
    @GetMapping(value = "/do/filter/errors")
    public void doFilterErrors(HttpServletRequest request) throws Exception {
        throw Exception.class.cast(request.getAttribute(EXCEPTION_ATTR));
    }
}


GlobalExceptionHandler:全局异常处理


@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
    // 处理所有不可知的异常,作为全局的兜底
    @ExceptionHandler(Exception.class)
    Object handleException(Exception e) {
        log.error(e.getMessage(), e);
        return "hello error";
    }
}


Spring Boot


本文针对性的特别提出了SpringBoot case下的解决方案。因为SpringBoot它会把所有的异常情况都转换为请求/error,所以扩展它还是容易些的:

Filter:没必要自己catch了,交给SpringBoot全局处理即可


@Component("helloFilter")
@WebFilter(urlPatterns = "/*")
public class HelloFilter extends OncePerRequestFilter {
    @Override
    protected void initFilterBean() throws ServletException {
        System.out.println("HelloFilter初始化...");
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        System.out.println(1 / 0);
        filterChain.doFilter(request, response);
    }
}


@RestController
public class MyErrorController extends BasicErrorController {
    // 最终使用的是此构造函数,所以魔方着只需要使用它即可
    // return new BasicErrorController(errorAttributes, this.serverProperties.getError(), this.errorViewResolvers);
    public MyErrorController(ErrorAttributes errorAttributes, ServerProperties serverProperties) {
        super(errorAttributes, serverProperties.getError());
    }
    @RequestMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Map<String, Object>> errorJson(HttpServletRequest request) {
        HttpStatus status = getStatus(request);
        if (status == HttpStatus.NO_CONTENT) {
            return new ResponseEntity<>(status);
        }
        Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
        body.put("myErrorType", "this is my diy error");
        return new ResponseEntity<>(body, status);
    }
}


image.png


相关阅读:

web九大组件之—HandlerExceptionResolver异常处理器使用详解【享学Spring MVC】


总结


本文呼吁,在实际生产中,请务必重视对异常的处理,我想表达的包含两层含义:


1.什么时候该抛异常,什么情况下它不是异常。(异常会使得JVM停顿,所以异常的使用请不要泛滥)


2.对于异常的统一处理,请务必要分而治之。不是所有异常都叫Exception~

    1. 合理的处理异常,这对于微服务架构在服务治理层面具有重要的意义,这也是对一个优秀架构师的考验之一


本文推荐多使用@ExceptionHandler方式去处理异常,因为它不仅书写方便、容易管理,而且还有缓存,效率也稍高一些。

Tips:@ExceptionHandler仅能处理HandlerMethod方式的异常。理论上是还可以有非HandlerMethod的控制处理器的,但实际上真的还有吗?还有吗?有吗?


相关文章
|
19天前
|
设计模式 前端开发 Java
步步深入SpringMvc DispatcherServlet源码掌握springmvc全流程原理
通过对 `DispatcherServlet`源码的深入剖析,我们了解了SpringMVC请求处理的全流程。`DispatcherServlet`作为前端控制器,负责请求的接收和分发,处理器映射和适配负责将请求分派到具体的处理器方法,视图解析器负责生成和渲染视图。理解这些核心组件及其交互原理,有助于开发者更好地使用和扩展SpringMVC框架。
31 4
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
142 2
|
2月前
|
Dubbo Java 应用服务中间件
深入探讨了“dubbo+nacos+springboot3的native打包成功后运行出现异常”的原因及解决方案
本文深入探讨了“dubbo+nacos+springboot3的native打包成功后运行出现异常”的原因及解决方案。通过检查GraalVM版本兼容性、配置反射列表、使用代理类、检查配置文件、禁用不支持的功能、查看日志文件、使用GraalVM诊断工具和调整GraalVM配置等步骤,帮助开发者快速定位并解决问题,确保服务的正常运行。
60 1
|
3月前
|
JSON 前端开发 Java
SSM:SpringMVC
本文介绍了SpringMVC的依赖配置、请求参数处理、注解开发、JSON处理、拦截器、文件上传下载以及相关注意事项。首先,需要在`pom.xml`中添加必要的依赖,包括Servlet、JSTL、Spring Web MVC等。接着,在`web.xml`中配置DispatcherServlet,并设置Spring MVC的相关配置,如组件扫描、默认Servlet处理器等。然后,通过`@RequestMapping`等注解处理请求参数,使用`@ResponseBody`返回JSON数据。此外,还介绍了如何创建和配置拦截器、文件上传下载的功能,并强调了JSP文件的放置位置,避免404错误。
|
3月前
|
Java API Spring
springBoot:注解&封装类&异常类&登录实现类 (八)
本文介绍了Spring Boot项目中的一些关键代码片段,包括使用`@PathVariable`绑定路径参数、创建封装类Result和异常处理类GlobalException、定义常量接口Constants、自定义异常ServiceException以及实现用户登录功能。通过这些代码,展示了如何构建RESTful API,处理请求参数,统一返回结果格式,以及全局异常处理等核心功能。
|
3月前
|
前端开发 Java 应用服务中间件
【Spring】Spring MVC的项目准备和连接建立
【Spring】Spring MVC的项目准备和连接建立
66 2
|
3月前
|
Java 关系型数据库 数据库连接
SpringBoot项目使用yml文件链接数据库异常
【10月更文挑战第3天】Spring Boot项目中数据库连接问题可能源于配置错误或依赖缺失。YAML配置文件的格式不正确,如缩进错误,会导致解析失败;而数据库驱动不匹配、连接字符串或认证信息错误同样引发连接异常。解决方法包括检查并修正YAML格式,确认配置属性无误,以及添加正确的数据库驱动依赖。利用日志记录和异常信息分析可辅助问题排查。
382 10
|
3月前
|
Java 关系型数据库 MySQL
SpringBoot项目使用yml文件链接数据库异常
【10月更文挑战第4天】本文分析了Spring Boot应用在连接数据库时可能遇到的问题及其解决方案。主要从四个方面探讨:配置文件格式错误、依赖缺失或版本不兼容、数据库服务问题、配置属性未正确注入。针对这些问题,提供了详细的检查方法和调试技巧,如检查YAML格式、验证依赖版本、确认数据库服务状态及用户权限,并通过日志和断点调试定位问题。
237 6
|
3月前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
230 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
4月前
|
XML 缓存 前端开发
springMVC02,restful风格,请求转发和重定向
文章介绍了RESTful风格的基本概念和特点,并展示了如何使用SpringMVC实现RESTful风格的请求处理。同时,文章还讨论了SpringMVC中的请求转发和重定向的实现方式,并通过具体代码示例进行了说明。
springMVC02,restful风格,请求转发和重定向