《springboot实战》第六章 实现自定义全局异常处理

前言

springboot实现自定义全局异常处理,以及统一返回数据。

1、分析

首先,实现全局异常的流程
在这里插入图片描述
从图中可以看到,实现全局异常会需要这样几个类:

  • 自定义异常接口类
  • 自定义异常枚举类
  • 自定义异常类
  • 自定义异常处理类
  • 自定义全局响应类

2、创建所需类

2.1、为了代码解耦,创建一个接口类出来,定义自定义接口所需要的方法

/**
 * Http状态信息接口
 */
public interface HttpStatusInfoInterface {

    int getCode();

    String getMessage();

}

2.2、定义一个枚举类,实现上述接口,重写上述接口的两个方法来操作这个枚举类内部的各个具体枚举值

后续方便管理所有错误枚举的错误信息以及code码,通过构造方法传入code值和message或者直接传入一个枚举值都行

/**
 * Http状态码
 */
public enum HttpStatusEnum implements HttpStatusInfoInterface{

    //定义状态枚举值
    SUCCESS(200 , "成功!"),
    BODY_NOT_MATCH(400 , "数据格式不匹配!"),
    NOT_FOUND(404 , "访问资源不存在!"),
    INTERNAM_SERVER_ERROR(500 , "服务器内部错误!"),
    SERVER_BUSY(503 , "服务器正忙,请稍后再试!"),
    REQUEST_METHOD_SUPPORT_ERROR(10001 , "当前请求方法不支持!"),
    REQUEST_DATA_NULL(10002 , "当前请求参数为空!"),
    USER_NOT_EXISTS(10003 , "该用户不存在!"),
    USER_INVALID(10004 , "当前登录信息已生效,请重新登录!"),
    PASSWORD_ERROR(10005 , "密码错误!"),
    USER_NAME_LOCK(10006 , "该账号已被锁定!");

    //状态码
    private int code;

    //提示信息
    private String message;

    //构造方法
    HttpStatusEnum(int code , String message) {
        this.code = code;
        this.message = message;
    }

    @Override
    public int getCode() {
        return this.code;
    }

    @Override
    public String getMessage() {
        return this.message;
    }

}

2.3、自定义一个异常类

就像空指针异常类、IO流异常类一样。此处自定义的异常类属于异常类,所有肯定是要继承一个异常类的,此处需要继承RuntimeException,原因如下:
RuntimeException相比Exception来讲,他是在程序运行时才会爆出异常,在编译时是不会出现异常的,这就表示,如果你throw了一个RuntimeException,不需要做额外操作;而throw一个Exception,程序会要求你try-catch,否则你根本启动不了程序,程序会提示(必须对其进行捕获或声明以便抛出)

import com.xxxx.springbootmybatis.common.HttpStatusEnum;
import lombok.Data;

@Data
public class HttpException extends RuntimeException{

    //错误码
    private int code;

    //错误信息
    private String message;

    // 默认构造函数
    public HttpException() {
        super();
    }

    public HttpException(HttpStatusEnum httpStatusEnum) {
        super(String.valueOf(httpStatusEnum.getCode()));
        this.code = httpStatusEnum.getCode();
        this.message = httpStatusEnum.getMessage();
    }

}

2.4、封装统一返回类

封装返回值类BaseResponse类和RespGenerator类都是属于规范方法返回值结构体的类,也有利于一致化后端所有接口的返回结构,方便前端读取所需要的数据。
HttpResult类:规定返回值结构。
HttpResultGenerator类:将逻辑处理后的数据包装转换成HttpResult类进行返回给前端。

import lombok.Data;

/**
 * http 统一返回类
 * @param <T>
 */
@Data
public class HttpResult<T> {

    private Integer code;

    private String message;

    private T data;

    //构造方法
    public HttpResult(Integer code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    //默认构造函数
    public HttpResult() {
        super();
    }
}

public class HttpResultGenerator {

    //正常返回时调用方法
    public static HttpResult success(Object data) {
        return new HttpResult(HttpStatusEnum.SUCCESS.getCode() , "接口调用成功!" , data);
    }


    //失败时调用方法(入参是异常枚举)
    public static HttpResult fail(HttpStatusEnum httpStatusEnum) {
        return new HttpResult(httpStatusEnum.getCode() , httpStatusEnum.getMessage() , null);
    }

    //失败时调用方法(提供给GlobalExceptionHandler类使用)
    public static HttpResult fail(int code ,  String message) {
        return new HttpResult(code , message , null);
    }

}

2.5、自定义异常处理类

@RestControllerAdvice注解是@ResponseBody和@ControllerAdvice的组合。

@ResponseBody注解:通常用来将java对象转成JSON对象,返回给前端JSON数据。
@ControllerAdvice注解:结合方法型注解@ExceptionHandler,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的。
@ExceptionHandler注解统一处理某一类异常,从而能够减少代码重复率和复杂度,value值为什么异常类型,就处理什么异常类型的逻辑。

import lombok.extern.slf4j.Slf4j;
import com.xxxx.springbootmybatis.common.HttpResult;
import com.xxxx.springbootmybatis.common.HttpResultGenerator;
import com.xxxx.springbootmybatis.common.HttpStatusEnum;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 自定义异常处理类
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
	
    //处理自定义异常
    @ExceptionHandler(value = HttpException.class)
    public HttpResult<Object> baseExceptionHandler(HttpException e) {
        log.error("发生业务异常!原因是:{}" , e.getMessage());
        return HttpResultGenerator.fail(e.getCode() , e.getMessage());
    }

    //处理空指针异常
    @ExceptionHandler(value = NullPointerException.class)
    public HttpResult<Object> exceptionHandler(Exception e) {
        log.error("发生异常!原因是:{}" , e);
        return HttpResultGenerator.fail(HttpStatusEnum.INTERNAM_SERVER_ERROR);
    }

}

3、测试

新建一个测试controller。

3.1、测试自定义异常全局处理效果

@Slf4j
@RestController
@CrossOrigin("*")
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/loginTest")
    public HttpResult loginTest(@RequestParam(value="name" ,required=false) String userName,
                                @RequestParam(value="pwd" ) String password ) {
        // URL: http://127.0.0.1/user/loginone?userName=zs&pwd=123
        log.info("userName:{} , password:{}" , userName , password);
        if(StringUtils.isEmpty(userName)) {
            throw new HttpException(HttpStatusEnum.USER_NOT_EXISTS);
        } else {
            return HttpResultGenerator.success("登录校验成功");
        }
    }
}

3.2、用postman测试,若username没有传值,会抛出自定义异常

在这里插入图片描述

3.3、控制台结果

2023-04-19 17:47:51.411 |-INFO  [http-nio-80-exec-3] com.hqyj.springbootmybatis.controller.UserController [54] -| userName: , password:123
2023-04-19 17:47:51.411 |-ERROR [http-nio-80-exec-3] com.hqyj.springbootmybatis.common.exception.GlobalExceptionHandler [21] -| 发生业务异常!原因是:该用户不存在!

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ROS学习第十二节——话题通信控制小乌龟

1.基操一下 首先打开小乌龟程序和键盘控制程序 rosrun turtlesim turtlesim_node rosrun turtlesim turtle_teleop_key 查看话题列表 rostopic list 打开计算图查看具体是那个话题在起作用 rqt_graph 从上图可以看到两个节点之间的话题是 /turtle1/cmd_vel 使用以下命令获…

linux及openEuler破解root密码

第一步&#xff1a;开机的时候按键盘的字母 E 键&#xff0c; 进入引导模式 第二步&#xff1a;进入引导模式 &#xff1a;找到linux这一行&#xff0c;按键盘上的end 键&#xff0c;跳转到行尾&#xff0c;输入&#xff1a; init/bin/sh 修改完后&#xff0c;按键盘上的 ctr…

哪种无线耳机音质最好?盘点2023四款好音质蓝牙耳机

随着蓝牙技术的发展&#xff0c;近几年人们对于蓝牙耳机的需求也在不断增加。但&#xff0c;蓝牙耳机自始至终都是用来听的&#xff0c;所以音质对于一款蓝牙耳机来说还是很重要的。下面&#xff0c;我来给大家推荐四款好音质蓝牙耳机&#xff0c;可以当个参考。 一、南卡小音舱…

JavaEE-轻松了解网络原理之TCP协议

目录 TCP协议TCP协议数据格式TCP原理确认应答超时重传连接管理三次握手四次挥手 滑动窗口流量控制拥塞控制延迟应答捎带应答面向字节流异常问题 TCP协议 TCP&#xff0c;即Transmission Control Protocol&#xff0c;传输控制协议. TCP协议数据格式 16位源端口号与16位目的端…

Doris(8):数据导入(Load)之Insert Into

Insert Into 语句的使用方式和 MySQL 等数据库中 Insert Into 语句的使用方式类似。但在 Doris 中&#xff0c;所有的数据写入都是一个独立的导入作业。所以这里将 Insert Into 也作为一种导入方式介绍。 主要的 Insert Into 命令包含以下两种&#xff1b; INSERT INTO tbl S…

微服务 - Redis缓存 · 数据结构 · 持久化 · 分布式 · 高并发

一、分布式解决 Session 的问题 在单站点中&#xff0c;可以将在线用户信息存储在Session中&#xff0c;随时变更获取信息&#xff1b;在多站点分布式集群如何做到Session共享呢&#xff1f;架设一个Session服务&#xff0c;供多服务使用。 频繁使用的数据存在DB端&#xff0…

如何使用镭速保护云存储数据安全

近年来&#xff0c;随着云计算的发展&#xff0c;远程系统上的数据存储变的越来越重要。云存储是一个以数据存储和管理为核心的云计算系统&#xff0c;给我们提供了一种全新的数据信息存储模式。但是&#xff0c;可以从全球任何地方访问和检索相同的数据。所需要的只是一个简单…

protobuf序列化原理、安装与应用

目录 protobuf序列化 protobuf的原理 protobuf 的安装 编译message文件 应用protobuf protobuf序列化 protobuf是一种比json和xml等序列化工具更加轻量和高效的结构化数据存储格式&#xff0c;性能比json和xml真的强很多&#xff0c;毕竟google出品。 官网&#xff1a;https:…

第八章 法律关系

目录 第一节 法律关系的概念 一、法律关系的定义与特征 二、法律关系的种类 &#xff08;一&#xff09;纵向&#xff08;隶属&#xff09;的法律关系和横向&#xff08;平权&#xff09;的法律关系 &#xff08;二&#xff09;单向&#xff08;单务&#xff09;法律关系、双…

Dear ImGui结合CMake实现基于GLFW和OpenGL3的入门级hello world代码

Dear ImGui结合CMake实现基于GLFW和OpenGL3的入门级hello world代码 如需转载请标明出处&#xff1a;https://blog.csdn.net/itas109 技术交流&#xff1a;129518033 环境&#xff1a; OS: windows 10 / Ubuntu 22.04 imgui: 1.89.5 glw: 3.3.8前言 Dear ImGui 是一个 用于…

outlook邮箱pc/mac客户端下载 含最新版

新的 Outlook for Windows or mac 为 Outlook 应用带来了最新功能、智能辅助功能和新的新式简化设计。 你可以根据自己的风格定制它&#xff0c;并使用新的 Outlook for Windows/mac 执行更多操作&#xff01; 览版&#xff0c;与我们一起开始旅程&#xff0c;并帮助我们塑造新…

leetcode142. 环形链表 II

给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数…

python 打包新方案

首先是打包一个最简单的python 代码使用 pyinstaller import os #直接读取文件获得python.exe 路径 # 待执行python路径 with open("path_run.txt","r",encoding"utf-8") as f:python_exe,pyf.readlines() os.system("{} {}".format(p…

什么牌子的蓝牙耳机音质最好?盘点2023音质最好的蓝牙耳机

近几年&#xff0c;蓝牙耳机在日常生活中的出现频率越来越高&#xff0c;不管是运动、听歌、追剧、玩游戏等等都能看到蓝牙耳机的身影。接下来&#xff0c;我来给大家盘点几款音质好的蓝牙耳机&#xff0c;感兴趣的朋友可以了解一下。 一、南卡小音舱Lite2蓝牙耳机 参考价&…

服务器版本的表白墙

目录 1.步骤 2.提供两个接口: 3.流程 4.代码 1.前端代码 2.sql创建表 3.后端代码 MessageServlet.java DBUtil.java 1.步骤 1.约定前后端交互的接口 2.开发服务器代码 a.编写servlet处理前端发来的请求 b.编写数据库代码,存储获取关键的数据 3.开发客户端代码 a.基于…

zabbix搭建

1.环境 本实验使用一台centos7主机&#xff0c;关闭了firewalld和selinux服务&#xff0c;zabbix版本为5.0版本&#xff0c;mysql使用版本为5.7版本 若要搭建6.0以上版本的zabbix&#xff0c;则需要使用mysql 8.0以上的版本 其它版本的zabbix可参考zabbix官网:Download and…

shell编程入门 第一章 基本语法

shell编程的语法主要分为五个环节&#xff0c;分别是变量&#xff0c;字符串&#xff0c;运算符&#xff0c;流程控制&#xff0c;函数五大部分 shell编程的基础语法 一 变量1.1 shell变量名1.2 使用shell变量1.3只读变量1.4 删除变量 二 字符串2.1 定义时最好用双引号2.2获取字…

Maven打包跳过测试的5种方式

Maven打包跳过测试的5种方式 1、命令行方式跳过测试 我们可以通过使用命令将项目打包&#xff0c;添加跳过测试的命令就可以了&#xff0c;可以用两种命令来跳过测试&#xff1a; -DskipTeststrue mvn package -DskipTeststrue-DskipTeststrue&#xff0c;不执行测试用例&a…

斩获“双金”!玻色量子在中国移动第七届创客马拉松大赛脱颖而出

​4月7日&#xff0c;中国移动第七届创客马拉松大赛总决赛在厦门圆满落幕。此次大赛以“能力无界 智算同行”为主题&#xff0c;经过近4000个创新项目的层层选拔&#xff0c;玻色量子凭借“相干量子计算设备”项目脱颖而出&#xff0c;成功摘取“双金”&#xff1a;总决赛全球通…

HttpServletRequest的介绍和方法以及代码实战

目录 HttpServletRequest HttpServletRequest 介绍 HttpServletRequest 常用方法 代码实战 HTML部分 Java部分 web.xml配置 请求转发 为什么需要请求转发 请求转发说明 请求转发原理示意图 代码实战 HTML部分 CheckServlet部分 ManageServlet 部分 xml部分 请求…