Spring Boot3自定义异常及全局异常捕获

news2024/11/29 22:31:54

 

⛰️个人主页:     蒾酒

🔥系列专栏:《spring boot实战》

🌊山高路远,行路漫漫,终有归途。


目录

前置条件

目的

主要步骤

定义自定义异常类

创建全局异常处理器

手动抛出自定义异常


前置条件

已经初始化好一个spring boot项目且版本为3X,项目可正常启动。

作者版本为3.2.2

初始化教程:

新版idea(2023)创建spring boot3项目-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_62262918/article/details/135785412?spm=1001.2014.3001.5501

目的

Spring Boot应用程序开发中,会遇到各种异常有可预知的也有不可预知的,我们很少会每个过程做单独异常处理,通常会将各种类型的异常处理过程解耦出来,保证业务逻辑单一、相关异常处理单一

通常将异常进行处理,封装一下对应错误信息返回友好信息。避免把异常直接给前端、用户。

反例:异常直接返回(不友好)

正例:处理后返回提示信息(友好)

主要步骤

定义自定义异常类

下面我们定义几个自定义异常

1.账号不存在异常

import com.mijiu.commom.enumerate.ResultEnum;
import lombok.Getter;

/**
 * 账户不存在异常
 *
 * @author mijiupro
 */
@Getter
public class AccountNotFoundException extends RuntimeException {
    private final ResultEnum resultEnum;

    public AccountNotFoundException(ResultEnum resultEnum) {
        this.resultEnum = resultEnum;
    }
}

2.密码错误异常

import com.mijiu.commom.enumerate.ResultEnum;
import lombok.Getter;

/**
 * 密码错误异常
 *
 * @author mijiupro
 */
@Getter
public class PasswordErrorException extends RuntimeException {
    private final ResultEnum resultEnum;

    public PasswordErrorException(ResultEnum resultEnum) {
        this.resultEnum = resultEnum;
    }

}

3. 令牌过期异常

import com.mijiu.commom.enumerate.ResultEnum;
import lombok.Getter;

/**
 * 令牌过期异常
 *
 * @author mijiupro
 */
@Getter
public class TokenOverdueException extends RuntimeException {
    private final ResultEnum resultEnum;
    public TokenOverdueException(ResultEnum resultEnum) {
        this.resultEnum = resultEnum;
    }
}

对于各种异常的错误码以及提示内容通常使用枚举类如下:

import lombok.Getter;

/**
 * @author mijiupro
 */
@Getter
public enum ResultEnum {

    /* 成功状态码 */
    SUCCESS(1, "操作成功!"),

    /* 错误状态码 */
    FAIL(0, "操作失败!"),

    /* 参数错误:10001-19999 */
    PARAM_IS_INVALID(10001, "参数无效"),
    PARAM_IS_BLANK(10002, "参数为空"),
    PARAM_TYPE_BIND_ERROR(10003, "参数格式错误"),
    PARAM_NOT_COMPLETE(10004, "参数缺失"),

    /* 用户错误:20001-29999*/
    USER_NOT_LOGGED_IN(20001, "用户未登录,请先登录"),
    USER_LOGIN_ERROR(20002, "账号不存在或密码错误"),
    USER_ACCOUNT_FORBIDDEN(20003, "账号已被禁用"),
    USER_NOT_EXIST(20004, "用户不存在"),
    USER_HAS_EXISTED(20005, "用户已存在"),

    /* 系统错误:40001-49999 */
    FILE_MAX_SIZE_OVERFLOW(40003, "上传尺寸过大"),
    FILE_ACCEPT_NOT_SUPPORT(40004, "上传文件格式不支持"),

    /* 数据错误:50001-599999 */
    RESULT_DATA_NONE(50001, "数据未找到"),
    DATA_IS_WRONG(50002, "数据有误"),
    DATA_ALREADY_EXISTED(50003, "数据已存在"),
    AUTH_CODE_ERROR(50004, "验证码错误"),


    /* 权限错误:70001-79999 */
    PERMISSION_UNAUTHENTICATED(70001, "此操作需要登陆系统!"),

    PERMISSION_UNAUTHORIZED(70002, "权限不足,无权操作!"),

    PERMISSION_EXPIRE(70003, "登录状态过期!"),

    PERMISSION_TOKEN_EXPIRED(70004, "token已过期"),

    PERMISSION_LIMIT(70005, "访问次数受限制"),

    PERMISSION_TOKEN_INVALID(70006, "无效token"),

    PERMISSION_SIGNATURE_ERROR(70007, "签名失败");

    // 状态码
    int code;
    // 提示信息
    String message;

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

    public int code() {
        return code;
    }

    public String message() {
        return message;
    }

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

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

创建全局异常处理器

需要创建一个全局异常处理器类,用于捕获和处理所有的异常。可以使用@ControllerAdvice  或者@RestControllerAdvice注解将该类标记为全局异常处理器,并使用@ExceptionHandler 注解定义具体的异常处理方法。例如,创建一个名为 GlobalExceptionHandler 的全局异常处理器类:

import com.mijiu.commom.exception.AccountNotFoundException;
import com.mijiu.commom.exception.PasswordErrorException;
import com.mijiu.commom.exception.TokenOverdueException;
import com.mijiu.commom.result.Result;
import com.mijiu.commom.enumerate.ResultEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

/**
 * @author mijiupro
 */
@RestControllerAdvice(basePackages = "com.mijiu.controller")
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {


    // 账号不存在异常
    @ExceptionHandler(AccountNotFoundException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<String> handleAccountNotFoundException(AccountNotFoundException ex) {
        return Result.error(ex.getResultEnum());
    }


    // 密码错误异常
    @ExceptionHandler(PasswordErrorException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<String> handlePasswordErrorException(PasswordErrorException ex) {
        return Result.error(ex.getResultEnum());
    }

    // 登录状态过期异常
    @ExceptionHandler(TokenOverdueException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public Result<?> handleTokenOverdueException(TokenOverdueException ex){
        return Result.error(ex.getResultEnum());
    }



    /**
     *
     * 通用异常处理
     */
    @ExceptionHandler(Exception.class)
    public Result<String> exceptionHandler(Exception ex) {
        log.error(ex.getMessage());
        return Result.error(ResultEnum.FAIL);
    }
}

对于不可预知的异常通常直接捕获所有异常父类Exception异常即可

这段代码会触发ArithmeticException ,类似这种的不可预知异常会有很多,它们都继承自Exception所以全局拦截Exception进行处理即可。

对于异常的处理返回的信息通常用统一格式封装:

import com.mijiu.commom.enumerate.ResultEnum;
import lombok.Data;


/**
 * @author mijiupro
 */

@Data
public class Result<T> {

    // 操作代码
    Integer code;

    // 提示信息
    String message;

    // 结果数据
    T data;

    public Result(ResultEnum resultCode) {
        this.code = resultCode.code();
        this.message = resultCode.message();
    }

    public Result(ResultEnum resultCode, T data) {
        this.code = resultCode.code();
        this.message = resultCode.message();
        this.data = data;
    }
    public Result(String message) {
        this.message = message;
    }
    //成功返回封装-无数据
    public static Result<String> success() {
        return new Result<String>(ResultEnum.SUCCESS);
    }
    //成功返回封装-带数据
    public static <T> Result<T> success(T data) {
        return new Result<T>(ResultEnum.SUCCESS, data);
    }
    //失败返回封装-使用默认提示信息
    public static Result<String> error() {
        return new Result<String>(ResultEnum.FAIL);
    }
    //失败返回封装-使用返回结果枚举提示信息
    public static Result<String> error(ResultEnum resultCode) {
        return new Result<String>(resultCode);
    }
    //失败返回封装-使用自定义提示信息
    public static Result<String> error(String message) {
        return new Result<String>(message);

    }
}

手动抛出自定义异常

在业务代码中抛出对应业务自定义异常:

有参构造传递错误枚举信息(状态码+错误内容),全局异常捕获并从自定义异常类拿到相关返回信息统一封装返回。

像这样直接抛出即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1447789.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用一根网线,让Ubuntu和正点原子I.MX6ULL开发板互相ping通

1.硬件准备 准备一根网线即可 2. 让windows和I.MX6ULLping通 2.1 找根网线将I.MX6ULL和电脑连起来 2.2 让I.MX6ULL通电运行起来&#xff0c;我这里使用的是正点原子版本的内核、 2.3 进入电脑的网络连接后&#xff0c;按照如下步骤操作 2.4 将ip地址、子网掩码、默认网关…

情人节html代码

一、一个带有心形和祝福消息的页面 如果想在网页上创建一个简单的情人节祝福&#xff0c;可以使用HTML和CSS。以下是一个简单的例子&#xff0c;它创建了一个带有心形和祝福消息的页面&#xff1a; <!DOCTYPE html> <html> <head> <title>情人节…

林浩然与杨凌芸的Java奇趣冒险:System与Runtime的大挑战

林浩然与杨凌芸的Java奇趣冒险&#xff1a;System与Runtime的大挑战 Lin Haoran and Yang Lingyun’s Java Adventure: The Grand Challenge of System and Runtime 在一个阳光明媚的日子&#xff0c;程序员大侠林浩然和智慧女神杨凌芸携手闯荡Java江湖。他们的故事并非刀光剑影…

[缓存] 1. 缓存共性问题

1. 缓存的作用 为什么需要缓存呢&#xff1f;缓存主要解决两个问题&#xff0c;一个是提高应用程序的性能&#xff0c;降低请求响应的延时&#xff1b;一个是提高应用程序的并发性。 2. 缓存的分类 本地缓存&#xff0c;分布式缓存 3. 缓存数据分类 3.1 数据缓存 程序数据直接…

Vue核心基础5:数据监测、收集表单数据、过滤器

1 数据监测 【代码】 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>总结</title><scrip…

LeetCode、435. 无重叠区间【中等,贪心 区间问题】

文章目录 前言LeetCode、435. 无重叠区间【中等&#xff0c;贪心 区间问题】题目链接及分类思路贪心、区间问题 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技…

力扣 第 384 场周赛 解题报告 | 珂学家 | 贪心构造 + KMP板子

前言 整体评价 因为是新春过年&#xff0c;所以题目出的相对简单一些&#xff0c;T4和上周一样&#xff0c;是字符串匹配模板题。 T1. 修改矩阵 思路: 模拟 按要求模拟即可 class Solution {public int[][] modifiedMatrix(int[][] matrix) {int h matrix.length;int w m…

如何一键启动、停止或重启运行在服务器内的幻兽帕鲁游戏服务进程?

如果你是用腾讯云轻量应用服务器一键部署的幻兽帕鲁服务器&#xff0c;那么可以在面板一键启动、停止或重启运行在服务器内的幻兽帕鲁游戏服务进程&#xff08;注意并非对服务器整机进行操作&#xff09;&#xff0c;无需手动在服务器内部运行命令。 详细教程地址&#xff1a;h…

2024年幻兽帕鲁服务器搭建方法_图文保姆级教程

幻兽帕鲁官方服务器不稳定&#xff1f;自己搭建幻兽帕鲁服务器&#xff0c;低延迟、稳定不卡&#xff0c;目前阿里云和腾讯云均推出幻兽帕鲁专用服务器&#xff0c;腾讯云直接提供幻兽帕鲁镜像系统&#xff0c;阿里云通过计算巢服务&#xff0c;均可以一键部署&#xff0c;鼠标…

2024幻兽帕鲁服务器创建教程_阿里PK腾讯超简单

幻兽帕鲁官方服务器不稳定&#xff1f;自己搭建幻兽帕鲁服务器&#xff0c;低延迟、稳定不卡&#xff0c;目前阿里云和腾讯云均推出幻兽帕鲁专用服务器&#xff0c;腾讯云直接提供幻兽帕鲁镜像系统&#xff0c;阿里云通过计算巢服务&#xff0c;均可以一键部署&#xff0c;鼠标…

智能汽车行业产业研究报告:毫米波雷达优势明显,核心壁垒是芯片、天线阵列、波形设计

今天分享的是智能汽车系列深度研究报告&#xff1a;《智能汽车行业产业研究报告&#xff1a;毫米波雷达优势明显&#xff0c;核心壁垒是芯片、天线阵列、波形设计》。 &#xff08;报告出品方&#xff1a;国泰君安证券&#xff09; 报告共计&#xff1a;67页 毫米波雷达被广泛…

mmdetection使用自己的voc数据集训练模型实战

一.自己数据集整理 将labelimg格式数据集进行整理 1.1. 更换图片后缀为jpg import os import shutilroot_path/media/ai-developer/imgfileos.listdir(root_path)for img in file:if img.endswith(jpeg) or img.endswith(JPG) or img.endswith(png):img_pathos.path.join(root…

关于显卡、显卡驱动、cuda、cuDNN等的区别

关于显卡、显卡驱动、cuda、cuDNN等的区别 刚接触AI或机器学习框架时&#xff0c;经常会被这几个概念搞混&#xff0c;尤其是显卡驱动、cuda、cuDNN这个三个软的东西&#xff1b;此外&#xff0c;NVCC、cudatoolkit又是什么呢&#xff1f; 1. 显卡(GPU) 显卡就是硬件&#xff…

C# winfrom中NPOI操作EXCEL

前言 1.整个Excel表格叫做工作表&#xff1a;WorkBook&#xff08;工作薄&#xff09;&#xff0c;包含的叫页&#xff08;工作表&#xff09;&#xff1a;Sheet&#xff1b;行&#xff1a;Row&#xff1b;单元格Cell。 2.忘了告诉大家npoi是做什么的了&#xff0c;npoi 能够读…

揭秘产品迭代计划制定:从0到1打造完美迭代策略

产品迭代计划是产品团队确保他们能够交付满足客户需求的产品以及实现其业务目标的重要工具。开发一个成功的产品迭代计划需要仔细考虑产品的目标、客户需求、市场趋势和可用资源。以下是帮助您创建产品迭代计划的一些步骤&#xff1a;建立产品目标、收集客户反馈、分析市场趋势…

Vue3快速上手(五)ref之对象类型的响应式数据

一、ref之对象类型的响应式数据 1.1 基本语法 import { ref } from vuelet x ref(初始值)console.log(xxx --> , x.value);x为一个RefImpl对象&#xff0c;该对象的value属性为实际值&#xff0c;在script里需要操作x.value来改变数据的值&#xff0c;在页面里则可以直接…

计算机网络——09Web-and-HTTP

Web and HTTP 一些术语 Web页&#xff1a;由一些对象组成对象可以是HTML文件、JPEG图像&#xff0c;JAVA小程序&#xff0c;声音剪辑文件等Web页含有一个基本的HTML文件&#xff0c;该基本HTML文件又包含若干对象的引用&#xff08;链接&#xff09;通过URL对每个对象进行引用…

C语言每日一题(56)平衡二叉树

力扣网 110 平衡二叉树 题目描述 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,…

LabVIEW智能温度监控系统

LabVIEW智能环境监测系统 介绍了一个基于LabVIEW的智能环境监测系统的开发过程。该系统在实时监测和分析环境参数&#xff0c;如温度、湿度、气体浓度等&#xff0c;以提供精确的数据支持&#xff0c;确保环境安全与健康。通过高效的数据处理和友好的用户界面&#xff0c;系统…

单链表基础知识点

单链表的读取 对于单链表实现获取第i个元素的数据的操作 GetElem&#xff0c;在算法上&#xff0c;相对要麻烦一些。 获得链表第i个数据的算法思路: 声明一个结点p指向链表第一个结点&#xff0c;初始化j从1开始;当j<i时&#xff0c;就遍历链表&#xff0c;让p的指针向后移…