SpringBoot全局异常处理实战详解

一、引言

在企业级项目中,为了保证业务流程正常运行,需要对一些可能出现异常的代码做一些处理,但随着业务的发展,针对异常处理的代码将越来越庞大,就会出现以下弊端:

  • 大量重复的try-catch代码块,难以维护。
  • Controller层直接将异常信息返回给前端,不够友好。
  • API接口请求的失败返回信息不统一,加大了前端异常处理的复杂度。

为了解决上面的问题,我们需要配置全局异常处理,首先解耦业务代码与异常处理代码,让代码结构更清晰;其次,通过设置结构统一的异常响应信息,降低前端处理失败响应的难度;最后,自定义返回的提示信息,便于用户或前端理解。

二、核心注解介绍

2.1 @RestControllerAdvice:rest请求拦截器

@RestControllerAdvice@ControllerAdvice@ResponseBody组成,这两者是Spring MVC框架提供的注解,前者是基于AOP的概念,只能标记在类上,可以将其理解为一个拦截器,它允许你对拦截的控制器追加处理逻辑,我们可以利用这一特点处理控制器所抛出的异常。

java 复制代码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice {
    @AliasFor(
        annotation = ControllerAdvice.class
    )
    String name() default "";
    /**
    * 省略后续代码内容
    **/
}

2.2 @ExceptionHandler:异常处理器

@ExceptionHandler也是Spring MVC框架提供的注解,只能标记在方法上,注解的内部包含一个value属性,用来定义一个特定的异常类,当Controller控制器抛出了value中定义的异常,Spring MVC会从被标记了@RestControllerAdvice注解的类中找到这个被@ExceptionHandler所标记的异常处理方法,找到后,就会执行这个自定义的异常处理方法。

2.3 异常处理流程

当我们定义了标记@RestControllerAdvice的全局异常处理类,并在类中创建了@ExceptionHandler标记的异常处理方法后,当用户发起API调用抛出异常,Spring MVC就会找到处理特定异常的方法,执行并返回自定义的异常信息给用户。

三、操作四步走:构建全局异常处理器

3.1 创建格式统一的响应体

创建一个响应实体类Result,包含code、msg、data属性,编写success、errror方法,分别返回表示成功和失败的响应数据

java 复制代码
package com.example.springexception.common;
import java.util.HashMap;

/**
* 消息体
*/
public class Result extends HashMap<String,Object> {
    private static final long serialVersionUID = 1L;

    private static final String CODE = "code"; //状态码
    private static final String MSG = "msg"; //响应描述
    private static final String DATA = "data"; //响应数据

    public Result(){}
    public Result(int code,String msg,Object data){
        super.put(CODE,code);
        super.put(MSG,msg);
        super.put(DATA,data);
    }

    /**
* 请求成功返回数据
*  @param  msg
*  @param  data
*  @return
 */
public static Result success(String msg,Object data){
        return new Result(200,msg,data);
    }

    /**
* 请求成功返回提示
*  @param  msg
*  @return
 */
public static Result success(String msg){
        return success(msg,null);
    }

    /**
* 请求失败返回数据
*  @param  msg
*  @param  data
*  @return
 */
public static Result error(String msg,Object data){
        return new Result(500,msg,data);
    }

    /**
* 请求失败返回提示
*  @param  msg
*  @return
 */
public static Result error(String msg){
        return error(msg,null);
    }
}

3.2 创建一个自定义异常

编写一个ServiceException异常类,表示业务异常,如果发生异常,交给后续定义的全局异常处理器处理这个异常。

java 复制代码
 /**
* 自定义业务异常
*/
@Data
public class ServiceException extends RuntimeException{
    private static final long serialVersionUID = 1L;
    /**
* 错误提示
*/
private String message;

    public ServiceException(String message){
        this.message = message;
    }
}

自定义异常需要继承RuntimeException类,表示运行时异常,添加一个message属性用来测试返回异常信息。

3.3 创建一个API接口,用来测试

Controller中编写一个getRandom接口,表示一个获取1000以内随机数的接口,在接口中判断本次获取的随机数是否>=500,如果条件成立正常返回成功数据,否则抛出ServiceException异常。需要注意的是:这里只是为了测试,所以直接在 Controller 层抛出异常,在正常开发过程中,一般会在业务层抛出业务相关的异常。

java 复制代码
@RestController
public class TestController {
    /**
* 获取随机数接口
*  @return
 */
@GetMapping("/random")
    public Result getRandom(){
        Random random = new Random();
        int boundInt = random.nextInt(1000);
        if(boundInt<500){
            throw new ServiceException("随机数小于500,请重新生成"+boundInt);
        }
        return Result.success("获取随机数API",boundInt);
    }
}

3.4 最后编写全局异常处理器(核心)

创建 GlobalExceptionHandler 类,在类上标注 @RestControllerAdvice注解让SpringMVC自动扫描拦截这个处理器,编写一个handlerServiceException方法并标记注解@ExceptionHandler(ServiceException.class),表示这个方法用来处理ServiceException类型的异常。

java 复制代码
 /**
* 全局异常处理器
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(ServiceException.class)
    public Result handlerServiceException(ServiceException e){
        return Result.error(e.getMessage());
    }
}

四、启动项目,测试

4.1 请求成功返回信息

json 复制代码
{
  "msg": "获取随机数API",
  "code": 200,
  "data": 891
}

4.2 请求失败返回信息

json 复制代码
{
  "msg": "随机数小于500,请重新生成441",
  "code": 500,
  "data": null
}

到此,就完成了全局异常处理器的简单构建,以上内容是构建全局异常处理器的流程,可以在此基础上针对自己的业务对处理器或自定义异常进行功能细化。

五、总结

SpringBoot全局异常处理的实现,是现代Web开发中不可或缺的一环。通过 @RestControllerAdvice@ExceptionHandler 两个注解的组合,我们能够将分散的异常处理逻辑集中化管理,构建出一个清晰、健壮的后端异常处理体系。

核心步骤可归纳为:

  1. 创建格式统一的响应体
  2. 创建自定义异常
  3. 创建全局异常处理器

遵循"已知异常明确提示,未知异常日志记录并友好兜底"的最佳实践,不仅能极大提升代码的可维护性,更能为前后端协作提供统一的接口契约,最终打造出用户体验更佳、稳定性更高的应用服务。

相关推荐
王中阳Go4 小时前
跳槽必看のMySQL索引:B+树原理揭秘与索引优缺点分析
后端
文心快码BaiduComate4 小时前
来WAVE SUMMIT,文心快码升级亮点抢先看!
前端·后端·程序员
码农阿豪4 小时前
EasyVoice与cpolar:构建私域有声平台的本地化方案
java·voice
布列瑟农的星空4 小时前
html中获取容器部署的环境变量
运维·前端·后端
用户298698530144 小时前
如何在 C# 中将 Word 转换为 PostScript?
后端
AAA修煤气灶刘哥4 小时前
MQ 可靠性血泪史:从丢消息到稳如老狗,后端 er 必看避坑指南
后端·spring cloud·rabbitmq
Java微观世界4 小时前
final的隐藏技能:从代码规范到线程安全,你用对了吗?
后端
该用户已不存在5 小时前
Node.js 做 Web 后端优势为什么这么大?
javascript·后端·node.js
叫我阿柒啊5 小时前
从全栈开发到云原生:一位Java工程师的实战经验分享
java·spring boot·redis·云原生·kafka·vue·全栈开发