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

发布于:2025-07-20 ⋅ 阅读:(22) ⋅ 点赞:(0)

1. 创建自定义异常类

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. 创建全局异常处理器

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. 创建统一错误响应体

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. 异常错误提示枚举

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状态码动态设置

  • 易于扩展和维护


网站公告

今日签到

点亮在社区的每一天
去签到