iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Spring Boot如何统一处理全局异常
  • 480
分享到

Spring Boot如何统一处理全局异常

2023-06-22 02:06:43 480人浏览 薄情痞子
摘要

这篇文章给大家分享的是有关spring Boot如何统一处理全局异常的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。注解的介绍@ControllerAdvice@ControllerAdvice注解是Sp

这篇文章给大家分享的是有关spring Boot如何统一处理全局异常的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

    注解的介绍

    @ControllerAdvice

    @ControllerAdvice注解是Spring3.2中新增的注解,学名是Controller增强器,作用是给Controller控制器添加统一的操作或处理。

    这里ControllerAdvice也可以这么理解,其抽象级别应该是用于对Controller进行切面环绕的,而具体的业务织入方式则是通过结合其他的注解来实现的。@ControllerAdvice是在类上声明的注解,其用法主要有三点:

    结合方法型注解@ExceptionHandler,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的。

    结合方法型注解@InitBinder,用于request中自定义参数解析方式进行注册,从而达到自定义指定格式参数的目的。

    结合方法型注解@ModelAttribute,表示其注解的方法将会在目标Controller方法执行之前执行。

    从上面的讲解可以看出,@ControllerAdvice的用法基本是将其声明在某个bean上,然后在该bean的方法上使用其他的注解来指定不同的织入逻辑。不过这里@ControllerAdvice并不是使用aop的方式来织入业务逻辑的,而是Spring内置对其各个逻辑的织入方式进行了内置支持。

    针对声明@ExceptionHandler 、 @InitBinder或@ModelAttribute方法的类的@Component @ExceptionHandler , @InitBinder在多个@Controller类之间共享。

    使用@ControllerAdvice注解的类可以明确声明为 Spring bean 或通过类路径扫描自动检测。 所有此类 bean 都根据Ordered语义或@Order / @Priority声明进行Ordered , Ordered语义优先于@Order / @Priority声明。 然后在运行时按该顺序应用@ControllerAdvice bean。 但是请注意,实现PriorityOrdered @ControllerAdvice bean 的PriorityOrdered不高于实现Ordered @ControllerAdvice bean。 此外, Ordered不适用于范围内的@ControllerAdvice例如,如果这样的 bean 已被配置为请求范围或会话范围的 bean。 对于处理异常, @ExceptionHandler将在第一个具有匹配异常处理程序方法的通知中被选择。 对于模型的属性和数据绑定初始化, @ModelAttribute和@InitBinder方法将遵循@ControllerAdvice秩序。

    注意:对于@ExceptionHandler方法,在特定建议 bean 的处理程序方法中,根异常匹配将优先于仅匹配当前异常的原因。 但是,与较低优先级建议 bean 上的任何匹配(无论是根还是原因级别)相比,更高优先级建议上的原因匹配仍然是首选。 因此,请在具有相应顺序的优先建议 bean 上声明您的主要根异常映射。

    默认情况下, @ControllerAdvice ControllerAdvice 中的方法全局应用于所有控制器。 使用诸如annotations 、 basePackageClasses和basePackages (或其别名value )之类的选择器来定义目标控制器的更窄子集。 如果声明了多个选择器,则应用布尔OR逻辑,这意味着所选控制器应至少匹配一个选择器。 请注意,选择器检查是在运行时执行的,因此添加许多选择器可能会对性能产生负面影响并增加复杂性。

    @ExceptionHandler拦截异常并统一处理

    配合 @ExceptionHandler注解结合使用,当异常抛到controller层时,可以对异常进行统一的处理,规定返回的JSON格式或者跳转到指定的错误页面等.

    @ExceptionHandler的作用主要在于声明一个或多个类型的异常,当符合条件的Controller抛出这些异常之后将会对这些异常进行捕获,然后按照其标注的方法的逻辑进行处理,从而改变返回的视图信息。

    用于处理特定处理程序类和/或处理程序方法中的异常的注解。

    使用此注解注释的处理程序方法允许具有非常灵活的签名。 它们可能具有以下类型的参数,按任意顺序排列:

    异常参数:声明为一般异常或更具体的异常。 如果注解本身没有通过其value()缩小异常类型,这也可用作映射提示

    代码实现

    自定义异常

    public class BizException extends RuntimeException {     private static final long serialVersionUID = 1L;         protected String errorCode;        protected String errORMsg;     public BizException() {        super();    }     public BizException(FrontResult errorInfoInterface) {        super(errorInfoInterface.getCode());        this.errorCode = errorInfoInterface.getMessage();        this.errorMsg = errorInfoInterface.getMessage();    }     public BizException(FrontResult errorInfoInterface, Throwable cause) {        super(errorInfoInterface.getCode(), cause);        this.errorCode = errorInfoInterface.getCode();        this.errorMsg = errorInfoInterface.getMessage();    }     public BizException(String errorMsg) {        super(errorMsg);        this.errorMsg = errorMsg;    }     public BizException(String errorCode, String errorMsg) {        super(errorCode);        this.errorCode = errorCode;        this.errorMsg = errorMsg;    }     public BizException(String errorCode, String errorMsg, Throwable cause) {        super(errorCode, cause);        this.errorCode = errorCode;        this.errorMsg = errorMsg;    }      public String getErrorCode() {        return errorCode;    }     public void setErrorCode(String errorCode) {        this.errorCode = errorCode;    }     public String getErrorMsg() {        return errorMsg;    }     public void setErrorMsg(String errorMsg) {        this.errorMsg = errorMsg;    }     public String getMessage() {        return errorMsg;    }     @Override    public Throwable fillInStackTrace() {        return this;    } }

    统一异常处理

     import com.tfjy.arbackend.enumtool.ResultCodeEnum;import com.tfjy.arbackend.enumtool.ResutlMsgEnum;import com.tfjy.arbackend.util.FrontResult;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.WEB.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.Http.httpservletRequest;import java.io.IOException;import java.net.InetAddress;import java.net.UnknownHostException;import java.sql.SQLException; @ControllerAdvice//使用该注解表示开启了全局异常的捕获public class GlobalExceptionHandler {    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);         @ExceptionHandler(value = BizException.class)    @ResponseBody    public  FrontResult bizExceptionHandler(HttpServletRequest req, BizException e){        logger.error("URL : " + req.getRequestURL().toString());        logger.error("HTTP_METHOD : " + req.getMethod());        logger.error("发生业务异常!原因是:{}",e.getErrorMsg());        return FrontResult.getExceptionResult(e.getErrorCode(),e.getErrorMsg());    }         @ExceptionHandler(value =NullPointerException.class)    @ResponseBody    public FrontResult exceptionHandler(HttpServletRequest req, NullPointerException e)  {        logger.error("URL : " + req.getRequestURL().toString());        logger.error("HTTP_METHOD : " + req.getMethod());        logger.error("发生空指针异常!原因是:",e);        return FrontResult.getExceptionResult(ResultCodeEnum.FaiL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());    }         @ExceptionHandler(value =IndexOutOfBoundsException.class)    @ResponseBody    public FrontResult exceptionHandler(HttpServletRequest req, IndexOutOfBoundsException e){        logger.error("URL : " + req.getRequestURL().toString());        logger.error("HTTP_METHOD : " + req.getMethod());        logger.error("索引越界异常!原因是:",e);        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());    }         @ExceptionHandler(value =ClassNotFoundException.class)    @ResponseBody    public FrontResult exceptionHandler(HttpServletRequest req, ClassNotFoundException e)  {        logger.error("URL : " + req.getRequestURL().toString());        logger.error("HTTP_METHOD : " + req.getMethod());        logger.error("发生类未找到异常!原因是:",e);        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());    }          @ExceptionHandler(value = SQLException.class)    @ResponseBody    public FrontResult exceptionHandler(HttpServletRequest req, SQLException e)  {        logger.error("URL : " + req.getRequestURL().toString());        logger.error("HTTP_METHOD : " + req.getMethod());        logger.error("发生SQL异常!原因是:",e);        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());    }         @ExceptionHandler(value = IOException.class)    @ResponseBody    public FrontResult exceptionHandler(HttpServletRequest req, IOException e)  {        logger.error("URL : " + req.getRequestURL().toString());        logger.error("HTTP_METHOD : " + req.getMethod());        logger.error("发生IO异常!原因是:",e);        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());    }          @ExceptionHandler(value =Exception.class)    @ResponseBody    public FrontResult exceptionHandler(HttpServletRequest req, Exception e){        logger.error("URL : " + req.getRequestURL().toString());        logger.error("HTTP_METHOD : " + req.getMethod());        logger.error("未知异常!原因是:",e);        return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());    }}

    前端返回值类

      import com.tfjy.arbackend.enumtool.ResultCodeEnum;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor; @Data@AllArgsConstructor@NoArgsConstructorpublic class FrontResult {        private String code;        private String message;        private Object data;         public static FrontResult build(String code, String message, Object data) {        return new FrontResult(code, message, data);    }         public static FrontResult getSuccessResult(String message, Object data) {        FrontResult result = new FrontResult();        result.code = ResultCodeEnum.SUCCESS.getCode();        result.message = message;        result.data = data;        return result;    }         public static FrontResult getSuccessResultOnlyMessage(String message) {        FrontResult result = new FrontResult();        result.code = ResultCodeEnum.SUCCESS.getCode();        result.message = message;        result.data = null;        return result;    }         public static FrontResult getExceptionResult(String code, String message) {        FrontResult result = new FrontResult();        result.code = code.isEmpty() ? ResultCodeEnum.CODE_EXCEPTION.getCode() : code;        result.message = message.isEmpty() ? ResultCodeEnum.CODE_EXCEPTION.getMsg() : message;        return result;    }}
    import lombok.AllArgsConstructor; @AllArgsConstructorpublic enum ResultCodeEnum {    // 请求成功    SUCCESS("0000"),    // 请求失败    FAIL("1111"),    // excel 导入失败    EXCEL_FAIL("1000"),    // userID 为空    ID_NULL("1001"),    // 前端传的实体为空    MODEL_NULL("1002"),    // 更新失败    UPDATE_FAIL("1011"),    // 参数为空    PARAM_ERROR("400"),    // 代码内部异常    CODE_EXCEPTION("500", "代码内部异常");         private String code;     public String getCode() {        return code;    }     ResultCodeEnum(String code) {        this.code = code;    }     private String msg;     public String getMsg() {        return msg;    } }  public enum ResutlMsgEnum {     //查询成功    FIND_SUCCESS("查询成功!"),    //查询失败    FIND_FAIL("查询失败!"),     //更新成功    UPDATE_SUCCESS("更新成功"),    //更新失败    UPDATE_FAIL("更新成功"),       SEND_SUCCESS("发送成功"),     SEND_FAIL("发送失败");      private String msg;     ResutlMsgEnum(String msg) {        this.msg = msg;    }     public String getMsg() {        return msg;    }}

    测试用例

    @api(tags = {"测试controller"})@RequestMapping(value = "/testController")@RestControllerpublic class TestController {        @ApiOperation(value = "测试null")    @GetMapping(value = "getNull")    public FrontResult getNull() {        int length = 0;             String name=null;            length = name.length();          return FrontResult.build(ResultCodeEnum.SUCCESS.getCode(),                ResutlMsgEnum.EXECUTE_SUCCESS.getMsg(), length);    }}

    附:Spring Boot默认的异常处理机制

    默认情况下,Spring Boot为两种情况提供了不同的响应方式。

    一种是浏览器客户端请求一个不存在的页面或服务端处理发生异常时,一般情况下浏览器默认发送的请求头中Accept: text/html,所以Spring Boot默认会响应一个html文档内容,称作“Whitelabel Error Page”。

    Spring Boot如何统一处理全局异常

    另一种是使用Postman等调试工具发送请求一个不存在的url或服务端处理发生异常时,Spring Boot会返回类似如下的json格式字符串信息

    {    "timestamp": "2018-05-12T06:11:45.209+0000",    "status": 404,    "error": "Not Found",    "message": "No message available",    "path": "/index.html"}

    原理也很简单,Spring Boot 默认提供了程序出错的结果映射路径/error。这个/error请求会在BasicErrorController中处理,其内部是通过判断请求头中的Accept的内容是否为text/html来区分请求是来自客户端浏览器(浏览器通常默认自动发送请求头内容Accept:text/html)还是客户端接口的调用,以此来决定返回页面视图还是 JSON 消息内容。

    相关BasicErrorController中代码如下:

    Spring Boot如何统一处理全局异常

    感谢各位的阅读!关于“Spring Boot如何统一处理全局异常”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

    --结束END--

    本文标题: Spring Boot如何统一处理全局异常

    本文链接: https://www.lsjlt.com/news/301858.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • MySQL怎么更新字段长度
      要更新MySQL表中的字段长度,可以使用ALTER TABLE语句。以下是更新字段长度的示例: ALTER TABLE table_...
      99+
      2024-05-14
      mysql
    • sql如何修改表字段长度
      要修改表字段的长度,可以使用ALTER TABLE语句,然后使用MODIFY COLUMN来修改字段的长度。以下是一个示例: ALT...
      99+
      2024-05-14
      sql
    • mysql数据量太大如何解决
      有几种方法可以解决MySQL数据量过大的问题: 数据库分区:将数据库表按照某种规则进行分区,分成多个小表,可以提高查询速度和管理...
      99+
      2024-05-14
      mysql
    • MySQL单表数据量过大如何解决
      在MySQL中,当单表的数据量过大时,可以采取以下几种方法来解决问题: 使用索引:在表的字段上创建适当的索引,可以提高查询效率,...
      99+
      2024-05-14
      mysql
    • mysql导出数据量过大如何解决
      当导出的数据量过大时,可以尝试以下方法来解决问题: 使用数据库工具:使用数据库管理工具如Navicat或MySQL Workbe...
      99+
      2024-05-14
      mysql
    • mysql中log_bin的作用是什么
      在MySQL中,log_bin是二进制日志文件的名称,用于记录所有对数据库进行更改的操作,如插入、更新、删除等。这些二进制日志文件可...
      99+
      2024-05-14
      mysql
    • mysql中log_bin的特点有哪些
      log_bin是MySQL的二进制日志文件,用于记录所有对数据库的修改操作,包括插入、更新、删除等。 log_bin文件是M...
      99+
      2024-05-14
      mysql
    • mysql rpm包安装的方法是什么
      要在Linux系统上安装MySQL RPM包,可以按照以下步骤操作: 下载MySQL的RPM包:你可以从MySQL官方网站下载适...
      99+
      2024-05-14
      mysql
    • mysql rpm包安装后怎么使用
      安装MySQL RPM包后,您可以通过以下步骤来使用MySQL: 启动MySQL服务:使用以下命令来启动MySQL服务: sud...
      99+
      2024-05-14
      mysql
    • lxml中怎么处理XML命名空间默认值
      在lxml中处理XML命名空间的默认值可以通过使用xpath()方法和register_namespace()方法来实现。...
      99+
      2024-05-14
      lxml
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作