《Spring Boot应用进阶:打造优雅的错误处理机制与全局异常拦截器》

news2024/9/28 21:40:02

文章目录

    • 自定义异常类AppException
    • 封装业务有关的枚举类AppExceptionCodeMsg
    • 全局异常拦截器Handler
    • 响应类模板Resp
    • 案例展示 || Demo
      • 项目结构
      • pom依赖
      • DemoController
      • 实际执行结果
    • Demo案例Git地址 | Gitee

本文主要介绍自己在工作中在处理抛出异常类和封装响应类处理的模板总结。

对于后端程序员来说,抛出异常和返回响应别提有多重要了对吧。其实在真正的企业级开发中,这步工作也不需要你去做,公司都给你封装好了的,你直接用就行。由于我最近从0到1负责了一个完整的项目,在最近的后期优化过程中,我需要考虑重新设计 自定义异常类与统一响应,所以特此总结该文,以供学习。

自定义异常类AppException

自定义异常类AppException需要继承至 RuntimeException运行时异常。

public class AppException extends RuntimeException{

    private int code = 500;
    private String msg = "服务器异常";


    public AppException(AppExceptionCodeMsg appExceptionCodeMsg){
        super();
        this.code = appExceptionCodeMsg.getCode();
        this.msg = appExceptionCodeMsg.getMsg();

    }

    public AppException(int code,String msg){
        super();
        this.code = code;
        this.msg = msg;

    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

}

封装业务有关的枚举类AppExceptionCodeMsg

利用枚举类将常用的业务异常进行配置,封装:

INVALID_CODE(10000,"验证码无效"),
USERNAME_NOT_EXISTS(10001,"用户名不存在"),
USER_CREDIT_NOT_ENOUTH(10002,"用户积分不足");

这样做的好处是,配置灵活,不需要去硬编码。

完整的枚举类如下:

//这个枚举类中定义的都是跟业务有关的异常
public enum AppExceptionCodeMsg {

    INVALID_CODE(10000,"验证码无效"),
    USERNAME_NOT_EXISTS(10001,"用户名不存在"),
    USER_CREDIT_NOT_ENOUTH(10002,"用户积分不足");
    ;

    private int code ;
    private String msg ;

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }


    AppExceptionCodeMsg(int code, String msg){
        this.code = code;
        this.msg = msg;
    }

}

全局异常拦截器Handler

这个拦截器的作用就是在抛出异常之前进行拦截,先判断是不是要抛出你自定义的异常,如果不是则放行。

@ControllerAdvice
public class GlobalExceptionHandler {


    @ExceptionHandler(value = {Exception.class})
    @ResponseBody
    public <T> Resp<T> exceptionHandler(Exception e){
        //这里先判断拦截到的Exception是不是我们自定义的异常类型
        if(e instanceof AppException){
            AppException appException = (AppException)e;
            return Resp.error(appException.getCode(),appException.getMsg());
        }

        //如果拦截的异常不是我们自定义的异常(例如:数据库主键冲突)
        return Resp.error(500,"服务器端异常");
    }
}

响应类模板Resp

其实这个响应类模板网上到处都是,自己也可以随意找到,以下是我的模板:

public class Resp<T> {

    //服务端返回的错误码
    private int code = 200;
    //服务端返回的错误信息
    private String msg = "success";
    //我们服务端返回的数据
    private T data;

    private Resp(int code,String msg,T data){
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public static <T> Resp success(T data){
        Resp resp = new Resp(200, "success", data);
        return resp;
    }

    public static <T> Resp success(String msg,T data){
        Resp resp = new Resp(200,msg, data);
        return resp;
    }

    public static <T> Resp error(AppExceptionCodeMsg appExceptionCodeMsg){
        Resp resp = new Resp(appExceptionCodeMsg.getCode(), appExceptionCodeMsg.getMsg(), null);
        return resp;
    }
    public static <T> Resp error(int code,String msg){
        Resp resp = new Resp(code,msg, null);
        return resp;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public T getData() {
        return data;
    }

}

案例展示 || Demo

接下来我将用一个SpringBoot项目综合上述异常类与响应类综合展示具体情况,看官们也可以自行下载demo直接在自己的电脑上跑起来学习。

项目结构

│  pom.xml
├─src
│  ├─main
│  │  ├─java
│  │  │  └─com
│  │  │      └─linghu
│  │  │          └─demo
│  │  │              │  DemoApplication.java
│  │  │              │
│  │  │              ├─controller
│  │  │              │      DemoController.java
│  │  │              │
│  │  │              ├─exception
│  │  │              │      AppException.java
│  │  │              │      AppExceptionCodeMsg.java
│  │  │              │      GlobalExceptionHandler.java
│  │  │              │
│  │  │              └─resp
│  │  │                      Resp.java
│  │  │
│  │  └─resources
│  │          application.yml
│  │
│  └─test
│      └─java

pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>exceptiondemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

DemoController

web层api代码设计如下:

@RestController
public class DemoController {
    @GetMapping("demo")
    public Resp<String> demo1(String name){

        if("ok".equals(name)){
            return Resp.success("succ");
        }
        if("err".equals(name)){
            //抛业务相关的异常
            throw new AppException(AppExceptionCodeMsg.USERNAME_NOT_EXISTS);
        }

        if("errcode".equals(name)){
            throw new AppException(AppExceptionCodeMsg.INVALID_CODE);
        }
        if("0".equals(name)){
            int i=1/0;
        }

        //检查用户积分是否足够,如果不够,就抛出异常
        if("notenough".equals(name)){
            throw new AppException(AppExceptionCodeMsg.USER_CREDIT_NOT_ENOUTH);
        }

        return Resp.success("default");
    }

    @GetMapping("list")
    public Resp<List> list(){
        List<String> list = Arrays.asList("zhangsan","lisi","wangwu");

        return Resp.success(list);
    }
}

实际执行结果

在这里插入图片描述

大家可以自行下载代码跑一跑学习一下。

Demo案例Git地址 | Gitee

该教程其实很简单,欢迎大家下载学习!

完整Demo如下:
《Exception_Auto_Demo》

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

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

相关文章

首屏优化之:SSR(服务端渲染)

引言 今天我们来聊一下首屏优化之SSR-服务端渲染&#xff08;Server-Side Rendering&#xff09;。 可能很多朋友并不了解什么是 SSR&#xff0c;包括在工作中写的网站是什么类型的也不太清楚&#xff0c;是 CSR 还是 SSR&#xff1f;作者在阅读过大量的文章之后&#xff0c;…

数据结构:二叉树OJ题篇 手把手带你入门数据结构~

文章目录 前言一、单值二叉树二、检查两颗树是否相同三、对称二叉树四、另一颗树的子树五、二叉树的前序遍历六、二叉树的后序遍历七、二叉树中序遍历八、二叉树的构建及遍历九、二叉树选择题1.二叉树性质2. 二叉树选择题1. 某⼆叉树共有 399 个结点&#xff0c;其中有 199 个度…

vLLM (6) - Scheduler BlockSpaceManager

系列文章目录 vLLM (1) - Qwen2推理&部署 vLLM (2) - 架构总览 vLLM (3) - Sequence & SequenceGroup vLLM (4) - LLMEngine上篇 vLLM (5) - LLMEngine下篇 vLLM (6) - Scheduler & BlockSpaceManager 文章目录 系列文章目录前言一、Scheduler1.概述2.Scheduler._…

Cannot solve model: no CPLEX runtime found.【macOS系统下问题解决】

最近在研究电能优化的策略时&#xff0c;运行别人代码出现了 Cannot solve model: no CPLEX runtime found. 1. 下载cplex # !pip install cplex12.8 #指定版本 !pip install cplex #下载最新的版本2. 下载docplex !pip install docplex3. 重启Jupyter或者你的项目…

C++之STL—常用排序算法

sort (iterator beg, iterator end, _Pred) // 按值查找元素&#xff0c;找到返回指定位置迭代器&#xff0c;找不到返回结束迭代器位置 // beg 开始迭代器 // end 结束迭代器 // _Pred 谓词 random_shuffle(iterator beg, iterator end); // 指定范围内的元素随机调…

Qt(9.28)

widget.cpp #include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {QPushButton *btn1 new QPushButton("登录",this);this->setFixedSize(640,480);btn1->resize(80,40);btn1->move(200,300);btn1->setIcon(QIcon("C:…

Secret Configmap

应用启动过程中可能需要一些敏感信息&#xff0c;比如访问数据库的用户名&#xff0c;密码或者秘钥&#xff0c;讲这些信息直接保存在容器镜像中显然不合适&#xff0c;kubernetes提供的解决方案就是Secret Secret会以密文的方式存储数据&#xff0c;避免了直接在配置文件中保…

基于php的医院信息管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

NLP:BERT的介绍

1. BERT 1.1 Transformer Transformer架构是一种基于自注意力机制(self-attention)的神经网络架构&#xff0c;它代替了以前流行的循环神经网络和长短期记忆网络&#xff0c;已经应用到多个自然语言处理方向。   Transformer架构由两个主要部分组成&#xff1a;编码器(Encod…

《向量数据库指南》——Zilliz Cloud Serverless版震撼发布:弹性伸缩,成本直降50倍

在数据驱动的时代背景下,向量数据库作为处理复杂非结构化数据(如图像、视频、音频及文本等)的关键技术,正逐步成为推动人工智能、机器学习以及大数据分析等领域发展的核心力量。随着数据量的爆炸性增长和查询需求的多样化,如何高效地管理并利用这些数据成为了企业和开发者…

如何回答:count(*) 和 count(1)的区别

感谢Java面试教程的Java多线程文章&#xff0c;点击查看>原文 在SQL查询中&#xff0c;count(*) 和 count(1) 都是用于统计表中行数的聚合函数&#xff0c;它们的主要区别在于语法和执行效率上。 语法上的区别&#xff1a; count(*)&#xff1a;直接统计表中的所有行数&…

RabbitMQ的各类工作模式介绍

简单模式 P: ⽣产者, 也就是要发送消息的程序 C: 消费者,消息的接收者 Queue: 消息队列, 图中⻩⾊背景部分. 类似⼀个邮箱, 可以缓存消息; ⽣产者向其中投递消息, 消费者从其中取出消息.特点: ⼀个⽣产者P&#xff0c;⼀个消费者C, 消息只能被消费⼀次. 也称为点对点(Point-to-…

[CKA]CKA预约和考试

CKA预约和考试 一、预约 1、登录Linux Foundation https://trainingportal.linuxfoundation.org/learn/dashboard 2、首页点 "Resume"进行预约 3、进入考试准备界面后&#xff0c;按要求分别验证 Agree to Global Candidate Agreement&#xff08;同意全球候选人协…

nodejs逐字读取文件示例

像chatpGPT显示文字一样.主要是服务器流式返回数据.前端用for await读取response.body <button id"fetchjson" onclick"FetchJSON()">fetch json看console与network</button> <button id"fetchstream" onclick"FetchStrea…

基于php的民宿预订管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

[SAP ABAP] SELECT-OPTIONS

基本语法 SELECT-OPTIONS <sel> FOR <f>. 示例1 输出结果&#xff1a; 点击右边的 按钮&#xff0c;将弹出多项数值输入界面&#xff0c;如下图所示 示例2 数据准备 学生表(ZDBT_STU_437) 学生表(ZDBT_STU_437)数据明细 输出结果&#xff1a; OBLIGATORY参数用于…

RTA-OS Port Guide学习(三)-基于S32K324 OS

文章目录 前言HardwareSupported DevicesRegister UsageInitializationModificationRequired OS resourcesInterruptsInterrupt Priority LevelsAllocation of ISRs to Interrupt VectorsVector TableWriting Category 1 Interrupt HandlersWriting Category 2 Interrupt Handl…

ECCV`24 | 高保真目标修复新SOTA!复旦智象开源CAT-Diffusion,语义视觉双一致

文章链接&#xff1a;https://arxiv.org/pdf/2409.08260 Github链接&#xff1a;https://github.com/Nnn-s/CATdiffusion 总结速览 解决的问题: 单一U-Net在所有去噪步骤中对齐文本提示和视觉对象不足以生成期望的对象。 扩散模型的复杂采样空间中无法保证对对象生成的可控性…

基于php的助农生鲜销售系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

Elasticsearch7.7设置账号密码时的逻辑矛盾问题和文章相关评论

一、Elasticsearch7.7设置账号密码时的逻辑矛盾问题 publish:June 19, 2020 -Friday 2019年1月30日&#xff0c;外媒又报道了一起Elasticsearch数据泄露事件&#xff01;2019年1月份的至少有6起Elasticsearch数据泄露事件了。原因何在&#xff0c;很简单&#xff0c;开发者在服…