企业级异常处理方案:Spring Boot自定义异常全局拦截实战

1. 创建自定义异常类

java 复制代码
public class ApproveException  extends Exception {
    public ApproveException() {
    }

    public ApproveException(String message) {
        super(message);
    }
}


public class HandleException extends Exception {

    public HandleException() {
    }

    public HandleException(String message) {
        super(message);
    }
}

public class QueryException extends Exception {

    public QueryException() {
    }

    public QueryException(String message) {
        super(message);
    }
}

2. 创建全局异常处理器

java 复制代码
package jnpf.exception;

import cn.dev33.satoken.exception.IdTokenInvalidException;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import jnpf.base.ActionResult;
import jnpf.base.ActionResultCode;
import jnpf.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RestControllerAdvice
public class ResultException {
    @ResponseBody
    @ExceptionHandler(value = LoginException.class)
    public ActionResult loginException(LoginException e) {
        return ActionResult.fail(ActionResultCode.Fail.getCode(), e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(value = ImportException.class)
    public ActionResult loginException(ImportException e) {
        return ActionResult.fail(ActionResultCode.Fail.getCode(), e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(value = DataException.class)
    public ActionResult dataException(DataException e) {
        return ActionResult.fail(ActionResultCode.Fail.getCode(), e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(value = RuntimeException.class)
    public ActionResult dataException(RuntimeException e) {
        return ActionResult.fail(ActionResultCode.Fail.getCode(), e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(value = IllegalArgumentException.class)
    public ActionResult dataException(IllegalArgumentException e) {
        return ActionResult.fail(ActionResultCode.Fail.getCode(), e.getMessage());
    }


    @ResponseBody
    @ExceptionHandler(value = WorkFlowException.class)
    public ActionResult workFlowException(WorkFlowException e) {
        if (e.getCode() == 200) {
            List<Map<String, Object>> list = JsonUtil.getJsonToListMap(e.getMessage());
            return ActionResult.success(list);
        } else {
            return ActionResult.fail(e.getMessage());
        }
    }

    @ResponseBody
    @ExceptionHandler(value = WxErrorException.class)
    public ActionResult wxErrorException(WxErrorException e) {
        return ActionResult.fail(e.getError().getErrorCode(), "操作过于频繁");
    }

    @ResponseBody
    @ExceptionHandler(NotPermissionException.class)
    public ActionResult<Void> handleNotPermissionException(NotPermissionException e) {
        return ActionResult.fail(ActionResultCode.Fail.getCode(), "没有访问权限,请联系管理员授权");
    }

    @ResponseBody
    @ExceptionHandler(NotRoleException.class)
    public ActionResult<Void> handleNotRoleException(NotRoleException e) {
        return ActionResult.fail(ActionResultCode.ValidateError.getCode(), "没有访问权限,请联系管理员授权");
    }

    @ResponseBody
    @ExceptionHandler(NotLoginException.class)
    public ActionResult<Void> handleNotLoginException(NotLoginException e) {
        return ActionResult.fail(ActionResultCode.SessionOverdue.getCode(), "认证失败,无法访问系统资源");
    }

    @ResponseBody
    @ExceptionHandler(IdTokenInvalidException.class)
    public ActionResult<Void> handleIdTokenInvalidException(IdTokenInvalidException e) {
        return ActionResult.fail(ActionResultCode.SessionOverdue.getCode(), "无效内部认证,无法访问系统资源");
    }
}

3. 创建统一错误响应体

java 复制代码
package jnpf.base;

import com.fasterxml.jackson.annotation.JsonInclude;

import jnpf.base.vo.PageListVO;
import jnpf.base.vo.PaginationVO;
import jnpf.constant.MsgCode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.util.List;


@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ActionResult<T> {

    @Schema(description = "状态码")
    private Integer code;

    @Schema(description = "返回信息")
    private String msg;

    @Schema(description = "返回数据")
    private T data;


    public static <T> ActionResult<T> success() {
        ActionResult<T> jsonData = new ActionResult<>();
        jsonData.setCode(200);
        jsonData.setMsg(MsgCode.SU000.get());
        return jsonData;
    }

    public static <T> ActionResult<T> success(String msg) {
        ActionResult<T> jsonData = new ActionResult<>();
        jsonData.setCode(200);
        jsonData.setMsg(msg);
        return jsonData;
    }

    public static <T> ActionResult<T> success(T object) {
        ActionResult<T> jsonData = new ActionResult<>();
        jsonData.setData(object);
        jsonData.setCode(200);
        jsonData.setMsg(MsgCode.SU000.get());
        return jsonData;
    }

    public static <T> ActionResult<T> success(String msg, T object) {
        ActionResult<T> jsonData = new ActionResult<>();
        jsonData.setData(object);
        jsonData.setCode(200);
        jsonData.setMsg(msg);
        return jsonData;
    }


    public static <T> ActionResult<T> fail(Integer code, String message) {
        ActionResult<T> jsonData = new ActionResult<>();
        jsonData.setCode(code);
        jsonData.setMsg(message);
        return jsonData;
    }

    public static ActionResult<String> fail(String msg, String data) {
        ActionResult<String> jsonData = new ActionResult<>();
        jsonData.setMsg(msg);
        jsonData.setData(data);
        return jsonData;
    }

    public static <T> ActionResult<T> fail(String msg) {
        ActionResult<T> jsonData = new ActionResult<>();
        jsonData.setMsg(msg);
        jsonData.setCode(400);
        return jsonData;
    }


    public static <T> ActionResult<PageListVO<T>> page(List<T> list, PaginationVO pagination) {
        ActionResult<PageListVO<T>> jsonData = new ActionResult<>();
        PageListVO<T> vo = new PageListVO<>();
        vo.setList(list);
        vo.setPagination(pagination);
        jsonData.setData(vo);
        jsonData.setCode(200);
        jsonData.setMsg(MsgCode.SU000.get());
        return jsonData;
    }

    public static <T> ActionResult<DataInterfacePageListVO<T>> page(List<T> list, PaginationVO pagination, String dataProcessing) {
        ActionResult<DataInterfacePageListVO<T>> jsonData = new ActionResult<>();
        DataInterfacePageListVO<T> vo = new DataInterfacePageListVO<>();
        vo.setList(list);
        vo.setPagination(pagination);
        vo.setDataProcessing(dataProcessing);
        jsonData.setCode(200);
        jsonData.setData(vo);
        jsonData.setMsg(MsgCode.SU000.get());
        return jsonData;
    }

}

4. 异常错误提示枚举

java 复制代码
public enum ActionResultCode {

    /**
     * 成功
     */
    Success(200, "成功"),
    /**
     * 失败
     */
    Fail(400, "失败"),
    /**
     * 验证错误
     */
    ValidateError(401, "验证错误"),
    /**
     * 异常
     */
    Exception(500, "异常"),
    /**
     * 登录过期提示
     */
    SessionOverdue(600, "登录过期,请重新登录"),
    /**
     * 踢出提示
     */
    SessionOffLine(601, "您的帐号在其他地方已登录,被强制踢出"),
    /**
     * token失效
     */
    SessionError(602, "Token验证失败");

    private int code;
    private String message;

    ActionResultCode(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

关键点说明:

  1. @ControllerAdvice:标记为全局异常处理器

  2. @ExceptionHandler:指定处理的异常类型

  3. 响应实体 :使用ActionResult可自定义HTTP状态码

  4. 异常优先级:Spring会匹配最具体的异常处理器

  5. 错误信息:包含时间戳、错误码、消息和请求路径

这样实现的全局异常处理器具有以下优点:

  • 统一处理控制器层所有异常

  • 支持自定义异常类型和错误码

  • 返回结构化的错误信息

  • 分离业务逻辑与错误处理

  • 支持HTTP状态码动态设置

  • 易于扩展和维护

相关推荐
Baron X15 分钟前
Eclipse Temurin 21 (JRE) Alpine 镜像获取、离线导入与推送操作
java·docker·eclipse·temurin
用户98883218717423 分钟前
别把 IOptionsSnapshot 注入单例:从生命周期看 .NET 配置读取
后端
姜鱼问生25 分钟前
别再 chmod 777 了,用 ACL 给它开一扇窗
后端·算法·架构
孙浩君28 分钟前
我用 Spring Boot + xterm.js 写了个终端风格互动叙事游戏引擎:游戏即文件,上传一个 JSON 就能玩
java
仿生joe会梦见漫天的大雪吗29 分钟前
CTF Misc 工具选型指南:按题型分类的工具、原理与限制
后端·安全
南丘山29 分钟前
一个 VARCHAR(1) 的字段,卡住了整条 DTU 数据链路
后端
南丘山33 分钟前
多租户隔离失效,我踩过的 3 个坑
后端
IT_陈寒34 分钟前
Java缓存踩坑记:明明设置了过期时间,怎么还是读到脏数据?
前端·人工智能·后端
用户86629784800834 分钟前
数据库报错"坏块"别急着删库重来,试试 KingbaseES 的离线修复工具
后端
jose36 分钟前
URL 里多写了一个端口,为什么请求还能调通?
java·后端