当前位置: 代码网 > it编程>编程语言>Java > SpringBoot的全局异常拦截实践过程

SpringBoot的全局异常拦截实践过程

2025年12月12日 Java 我要评论
在 spring boot 中,可以通过使用 @controlleradvice 注解和 @exceptionhandler 注解来实现全局异常拦截。@restcontrolleradvice@res

在 spring boot 中,可以通过使用 @controlleradvice 注解和 @exceptionhandler 注解来实现全局异常拦截。

@restcontrolleradvice

@restcontrolleradvice 是 spring framework 提供的注解,用于定义全局异常处理类,并且结合 @exceptionhandler 注解来处理异常。与 @controlleradvice 不同的是,@restcontrolleradvice 默认情况下会将返回值转换为 json 格式。

@restcontrolleradvice
public class globalexceptionhandler {
    
  //.....拦截异常方法

}

@responsestatus(...)

@responsestatus(httpstatus.bad_request) 是一个注解,用于在异常处理方法上指定特定的http状态码。当该异常被抛出时,将返回指定的http状态码给客户端。

@restcontrolleradvice
public class globalexceptionhandler {
    
  //.....拦截异常方法
  /**
     * 缺少请求体异常处理器
     * @param e 缺少请求体异常 使用get方式请求 而实体使用@requestbody修饰
     */
    @responsestatus(httpstatus.bad_request)
    public responseresult parameterbodymissingexceptionhandler(httpmessagenotreadableexception e) {
        string requesturi = httpservletrequest.getrequesturi();
        log.error("请求地址'{}',请求体缺失'{}'", requesturi, e.getmessage());
        return responseresult.errorresult(httpcodeenum.system_error.getcode(), syserror);
    }
}

@exceptionhandler(...)

@exceptionhandler(...) 是一个异常处理注解,用于捕获请求的异常。当客户端发送的请求消息无法被框架正确解析时,将抛出该异常并调用对应的异常处理方法。

@restcontrolleradvice
public class globalexceptionhandler {
    
  //.....拦截异常方法
  /**
     * 缺少请求体异常处理器
     * @param e 缺少请求体异常 使用get方式请求 而实体使用@requestbody修饰
     */
    @responsestatus(httpstatus.bad_request)
    @exceptionhandler(httpmessagenotreadableexception.class)
    public responseresult parameterbodymissingexceptionhandler(httpmessagenotreadableexception e) {
        string requesturi = httpservletrequest.getrequesturi();
        log.error("请求地址'{}',请求体缺失'{}'", requesturi, e.getmessage());
        return responseresult.errorresult(httpcodeenum.system_error.getcode(), syserror);
    }
}

runtimeexception

runtimeexception 是 java 提供的一个运行时异常类。与受检查异常不同,运行时异常不需要在方法声明中显式地声明或捕获,并且在运行时抛出时也不需要强制捕获或处理。所以我们可以在全局异常捕获中去捕获这个异常

public class businessexception extends runtimeexception {

    private int code;
    //使用枚举构造
    public businessexception(httpcodeenum httpcodeenum){
        super(httpcodeenum.getmsg());
        this.code=httpcodeenum.getcode();
    }
    //使用自定义消息体
    public businessexception(httpcodeenum httpcodeenum, string msg){
        super(msg);
        this.code=httpcodeenum.getcode();
    }

    //根据异常构造
    public businessexception(httpcodeenum httpcodeenum, throwable msg){
        super(msg);
        this.code=httpcodeenum.getcode();
    }


}

 上述代码定义了一个名为 businessexception 的自定义异常类,它继承自 runtimeexception

这个自定义异常类具有以下特点:

  1. 包含了一个 code 字段,用于表示异常的错误码。
  2. 提供了不同的构造方法,以方便在抛出异常时指定错误码和错误信息。
  • businessexception(httpcodeenum httpcodeenum) 构造方法使用枚举类型 httpcodeenum 来设置异常的错误码和错误信息。
  • businessexception(httpcodeenum httpcodeenum, string msg) 构造方法使用自定义的错误信息来设置异常的错误码和错误信息。
  • businessexception(httpcodeenum httpcodeenum, throwable msg) 构造方法使用其他异常的实例来设置异常的错误码,并可选地提供通过 throwable 获取的错误信息。

httpcodeenum枚举类

我们还需要一个类表示 http 响应的状态码和对应的消息 ,以下为基本的举例查考。

public enum httpcodeenum {
    // 成功
    success(200, "操作成功"),
    // 登录
    need_login(401, "需要登录后操作"),
    no_operator_auth(403, "无权限操作"),
    system_error(500, "出现错误"),
    username_exist(501, "用户名已存在"),
    phonenumber_exist(502, "手机号已存在"), email_exist(503, "邮箱已存在"),
    require_username(504, "必需填写用户名"),
    content_not_null(506, "评论内容不能为空"),
    file_type_error(507, "文件类型错误"),
    username_not_null(508, "用户名不能为空"),
    nickname_not_null(509, "昵称不能为空"),
    password_not_null(510, "密码不能为空"),
    email_not_null(511, "邮箱不能为空"),
    nickname_exist(512, "昵称已存在"),
    login_error(505, "用户名或密码错误");
    int code;
    string msg;

    httpcodeenum(int code, string errormessage) {
        this.code = code;
        this.msg = errormessage;
    }

    public int getcode() {
        return code;
    }

    public string getmsg() {
        return msg;
    }
}

上述代码定义了一个 httpcodeenum 枚举类,用于表示 http 响应的状态码和对应的消息。

这个枚举类具有以下特点:

  1. 包含一组枚举常量,每个常量代表一个 http 响应状态。
  2. 每个常量都有一个整型的 code 和一个字符串类型的 msg,分别表示状态码和对应的消息。
  3. 提供了相应的构造方法、获取 code 和 msg 的方法。

responseresult类

该类的主要作用是封装接口返回的数据,统一格式化输出,方便前端调用和展示。

import lombok.data;

import java.io.serializable;
@data
public class responseresult<t> implements serializable {
    private boolean success;
    private integer code;
    private string msg;
    private t data;

    public responseresult() {
        this.success=true;
        this.code = httpcodeenum.success.getcode();
        this.msg = httpcodeenum.success.getmsg();
    }

    public responseresult(integer code, t data) {
        this.code = code;
        this.data = data;
    }

    public responseresult(integer code, string msg, t data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public responseresult(integer code, string msg) {
        this.code = code;
        this.msg = msg;
    }

    public static responseresult errorresult(int code, string msg) {
        responseresult result = new responseresult();
        return result.error(code, msg);
    }

    public static responseresult okresult() {
        responseresult result = new responseresult();
        return result;
    }

    public static responseresult okresult(int code, string msg) {
        responseresult result = new responseresult();
        return result.ok(code, null, msg);
    }




    public static responseresult sethttpcodeenum(httpcodeenum enums) {
        return okresult(enums.getcode(), enums.getmsg());
    }


    public responseresult<?> error(integer code, string msg) {
        this.success=false;
        this.code = code;
        this.msg = msg;
        return this;
    }

    public responseresult<?> ok(integer code, t data) {
        this.success=true;
        this.code = code;
        this.data = data;
        return this;
    }

    public responseresult<?> ok(integer code, t data, string msg) {
        this.success=true;
        this.code = code;
        this.data = data;
        this.msg = msg;
        return this;
    }

    public responseresult<?> ok(t data) {
        this.success=true;
        this.data = data;
        return this;
    }


}

全局异常捕获

全局异常捕获是一种处理应用程序中未处理的异常的机制,它可以统一处理应用程序中的异常,避免异常导致程序崩溃或向用户显示不友好的错误信息。我们可以通过上述的解释去捕获异常,定义code类型枚举返回responseresult给前端

import com.example.demo.util.httpcodeenum;
import com.example.demo.util.responseresult;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.http.httpstatus;
import org.springframework.http.converter.httpmessagenotreadableexception;
import org.springframework.util.collectionutils;
import org.springframework.validation.fielderror;
import org.springframework.validation.objecterror;
import org.springframework.web.httprequestmethodnotsupportedexception;
import org.springframework.web.bind.methodargumentnotvalidexception;
import org.springframework.web.bind.missingservletrequestparameterexception;
import org.springframework.web.bind.annotation.exceptionhandler;
import org.springframework.web.bind.annotation.responsestatus;
import org.springframework.web.bind.annotation.restcontrolleradvice;

import javax.servlet.http.httpservletrequest;
import java.util.list;

@restcontrolleradvice
public class globalexceptionhandler {

    private static final logger log = loggerfactory.getlogger(globalexceptionhandler.class);

    @autowired
    private httpservletrequest httpservletrequest;

    private final string syserror="系统出错";

    /**
     * 缺少请求体异常处理器
     * @param e 缺少请求体异常 使用get方式请求 而实体使用@requestbody修饰
     */
    @responsestatus(httpstatus.bad_request)
    @exceptionhandler(httpmessagenotreadableexception.class)
    public responseresult parameterbodymissingexceptionhandler(httpmessagenotreadableexception e) {
        string requesturi = httpservletrequest.getrequesturi();
        log.error("请求地址'{}',请求体缺失'{}'", requesturi, e.getmessage());
        return responseresult.errorresult(httpcodeenum.system_error.getcode(), syserror);
    }

    /*
     * @description:  捕获请求方法异常,比如post接口使用了get
     */
    @responsestatus(httpstatus.method_not_allowed)
    @exceptionhandler(httprequestmethodnotsupportedexception.class)
    public responseresult methodnotallowedhandler(httprequestmethodnotsupportedexception e) {
        string requesturi = httpservletrequest.getrequesturi();
        log.error("请求地址'{}',请求方法不被允许'{}'", requesturi, e.getmessage());
        return responseresult.errorresult(httpcodeenum.system_error.getcode(), syserror);
    }

    // get请求的对象参数校验异常
    @responsestatus(httpstatus.bad_request)
    @exceptionhandler({missingservletrequestparameterexception.class})
    public responseresult bindexceptionhandler(missingservletrequestparameterexception e) {
            string requesturi = httpservletrequest.getrequesturi();
        log.error("请求地址'{}',get方式请求参数'{}'必传", requesturi, e.getparametername());
            return responseresult.errorresult(httpcodeenum.system_error.getcode(), syserror);
    }
    // post请求的对象参数校验异常
    @responsestatus(httpstatus.bad_request)
    @exceptionhandler({methodargumentnotvalidexception.class})
    public responseresult methodargumentnotvalidhandler(methodargumentnotvalidexception e) {
        string requesturi = httpservletrequest.getrequesturi();
        log.error("请求地址'{}',post方式请求参数异常'{}'", requesturi, e.getmessage());
            list<objecterror> allerrors = e.getbindingresult().getallerrors();
            return responseresult.errorresult(httpcodeenum.system_error.getcode(), getvalidexceptionmsg(allerrors));
    }

    // 业务类异常
    @responsestatus(httpstatus.internal_server_error)
    @exceptionhandler(businessexception.class)
    public responseresult businessexceptionhandler(businessexception e) {
        string requesturi = httpservletrequest.getrequesturi();
        system.out.println(e);
        log.error("请求地址'{}',捕获业务类异常'{}'", requesturi,e.getmessage());
        return responseresult.errorresult(httpcodeenum.system_error.getcode(), e.getmessage());
    }
    // 运行时异常
    @responsestatus(httpstatus.internal_server_error)
    @exceptionhandler(runtimeexception.class)
    public responseresult runtimeexceptionhandler(runtimeexception e) {
        string requesturi = httpservletrequest.getrequesturi();
        log.error("请求地址'{}',捕获运行时异常'{}'", requesturi, e.getmessage());
        return responseresult.errorresult(httpcodeenum.system_error.getcode(), e.getmessage());
    }
    // 系统级别异常
    @responsestatus(httpstatus.internal_server_error)
    @exceptionhandler(throwable.class)
    public responseresult throwableexceptionhandler(throwable e) {
        string requesturi = httpservletrequest.getrequesturi();
        log.error("请求地址'{}',捕获系统级别异常'{}'", requesturi,e.getmessage());
        return responseresult.errorresult(httpcodeenum.system_error.getcode(), e.getmessage());
    }



    private string getvalidexceptionmsg(list<objecterror> errors) {
        if(!collectionutils.isempty(errors)){
            stringbuilder sb = new stringbuilder();
            errors.foreach(error -> {
                if (error instanceof fielderror) {
                    sb.append(((fielderror)error).getfield()).append(":");
                }
                sb.append(error.getdefaultmessage()).append(";");
            });
            string msg = sb.tostring();
            msg = msg.substring(0, msg.length() -1);
            return msg;
        }
        return null;
    }

}

测试

入参不正确时

发出请求

返回结果

捕获异常

运行时错误

发起请求

返回结果

捕获异常

业务异常

发送请求

返回结果

捕获异常

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com