当前位置: 首页 > article >正文

SpringBoot自定义异常处理机制

说明:在完整的项目结构中,我们通常会创建一个自定义的异常处理机制,在系统可能出现异常的地方手动抛出这些异常,可以快速定位到异常代码片段,提供项目的可维护性。

本文介绍在SpringBoot项目中,搭建一套自定义异常处理机制。

统一响应结果

首先,创建一个统一响应结果类,如下,用于统一后台的返回结果,请求成功返回数据,请求失败返回错误信息;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * 后端统一返回结果
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 编码:1成功 0和其他数字为失败
     */
    private Integer code;

    /**
     * 错误信息
     */
    private String msg;

    /**
     * 数据
     */
    private T data;


    /**
     * 成功并返回
     *
     * @param <T>
     * @return
     */
    public static <T> Result<T> success() {
        Result<T> result = new Result<T>();
        result.code = 1;
        return result;
    }

    /**
     * 成功并返回数据
     *
     * @param object
     * @param <T>
     * @return
     */
    public static <T> Result<T> success(T object) {
        Result<T> result = new Result<T>();
        result.data = object;
        result.code = 1;
        return result;
    }

    /**
     * 失败,并返回信息
     *
     * @param msg
     * @param <T>
     * @return
     */
    public static <T> Result<T> error(String msg) {
        Result result = new Result();
        result.msg = msg;
        result.code = 0;
        return result;
    }
}

然后,创建两个接口,用于用户登录,根据ID查找用户,如下:

(controller层)

import com.hezy.pojo.entity.User;
import com.hezy.pojo.vo.Result;
import com.hezy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/exception")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/login")
    public Result login(@RequestBody User user){
        return userService.login(user);
    }

    @GetMapping("/get")
    public Result get(Integer id){
        return userService.getUser(id);
    }
}

(Service实现类,其中TODO表示待完成的部分)

import cn.hutool.core.util.ObjUtil;
import com.hezy.pojo.entity.User;
import com.hezy.pojo.vo.Result;
import com.hezy.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Override
    public Result login(User user) {
        // 对user进行校验
        if (!ObjUtil.isAllNotEmpty(user, user.getUsername(), user.getPassword())) {
            return Result.error("非法参数异常");
        }

        // TODO 根据用户名查询数据库,校验该用户是否存在
        if (true) {
            return Result.error("该用户不存在");
        }

        // TODO 保存用户信息到数据库
        
        return Result.success(user);
    }

    @Override
    public Result getUser(Integer id) {
        // 对id进行校验
        if (id == null || id < 0) {
            return Result.error("非法参数异常");
        }

        // TODO 根据用户名查询数据库, 校验用户是否存在
        if (true) {
            return Result.error("该用户不存在");
        }

        return Result.success(new User(id, "张三", "123456"));
    }
}

(用户实体类)

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * id
     */
    private Integer id;

    /**
     * 账号
     */
    private String username;

    /**
     * 密码
     */
    private String password;
}

启动项目,运行;

在这里插入图片描述

(测试登录接口,因为在if里面写死了,所以返回错误信息)

在这里插入图片描述


(测试获取用户对象接口,因为在if里面写死了,所以返回错误信息)

在这里插入图片描述

异常枚举

接下来,对上面的异常进行统一处理。

首先,创建一个异常的枚举类,里面包含了异常状态码,异常信息等,如下:

/**
 * 异常枚举类
 */
public enum ExceptionEnum {

    PARAM_EXCEPTION(10001, "非法参数异常"),

    PARAM_LACK(10002, "参数不全异常"),

    UNKNOW_EXCEPTION(99999, "未知异常");

    private int status;

    private String message;

    ExceptionEnum(int status, String message) {
        this.status = status;
        this.message = message;
    }

    public int getStatus() {
        return status;
    }

    public String getMessage() {
        return message;
    }
}

自定义异常

创建一个自定义异常类,继承RuntimeException类,如下:

import com.hezy.enums.ExceptionEnum;

/**
 * 自定义异常
 */
public class MyException extends RuntimeException{

    /**
     * 异常枚举
     */
    private ExceptionEnum exceptionEnum;

    public MyException(ExceptionEnum exceptionEnum) {
        super(exceptionEnum.getMessage());
        this.exceptionEnum = exceptionEnum;
    }

    public ExceptionEnum getExceptionEnum() {
        return exceptionEnum;
    }

    /**
     * 手动抛出异常
     * @param exceptionEnum
     * @return
     */
    public static MyException throwException(ExceptionEnum exceptionEnum){
        return new MyException(exceptionEnum);
    }
}

再创建一个异常的controller,自定义捕获对应的异常,并打印信息;

import com.hezy.enums.ExceptionEnum;
import com.hezy.pojo.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
public class GlobalException {

    /**
     * 自定义异常
     * @param e
     * @return
     */
    @ExceptionHandler(MyException.class)
    public Result handleException(MyException e){
        log.error(e.getMessage());
        return Result.builder()
                .code(0)
                .msg(e.getExceptionEnum().getMessage())
                .build();
    }

    /**
     * 全局异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e){
        log.error(e.getMessage());
        return Result.builder()
                .code(0)
                .msg(ExceptionEnum.UNKNOW_EXCEPTION.getMessage())
                .build();
    }
}

最后,对前面业务实现类里面的代码进行修改,当参数校验错误时,直接抛出异常,如下:

import cn.hutool.core.util.ObjUtil;
import com.hezy.enums.ExceptionEnum;
import com.hezy.exception.MyException;
import com.hezy.pojo.entity.User;
import com.hezy.pojo.vo.Result;
import com.hezy.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Override
    public Result login(User user) {
        // 对user进行校验,其中user、username、password,都不能为空
        if (!ObjUtil.isAllNotEmpty(user, user.getUsername(), user.getPassword())) {
            throw new MyException(ExceptionEnum.PARAM_LACK);
        }

        // TODO 根据用户名查询数据库,校验该用户是否存在
        if (true) {
            return Result.error("该用户不存在");
        }

        // TODO 保存用户信息到数据库

        return Result.success(user);
    }

    @Override
    public Result getUser(Integer id) {
        // id == null,参数不全异常
        if (id == null) {
            throw new MyException(ExceptionEnum.PARAM_LACK);
        }

        // id < 0,非法参数异常
        if (id < 0) {
            throw new MyException(ExceptionEnum.PARAM_EXCEPTION);
        }

        // TODO 根据用户名查询数据库, 校验用户是否存在
        if (true) {
            return Result.error("该用户不存在");
        }

        return Result.success(new User(id, "张三", "123456"));
    }
}

启动项目,测试;

(当user中的username为空时)

在这里插入图片描述

在这里插入图片描述

(当获取对象的id < 0时)

在这里插入图片描述

在这里插入图片描述

当发生其他未知异常时,如post请求的接口,我们使用get方式发送时;

在这里插入图片描述

就会被全局异常捕获到,并在控制台打印报错信息;

在这里插入图片描述

如果此时,需要新增一个异常,只需要在ExceptionEnum(异常枚举类)中新增一个枚举项即可,如下:

(新增一个登录异常)

/**
 * 异常枚举类
 */
public enum ExceptionEnum {

    PARAM_EXCEPTION(10001, "非法参数异常"),

    PARAM_LACK(10002, "参数不全异常"),
    
    LOGIN_EXCEPTION(10003, "登录异常"),

    UNKNOW_EXCEPTION(99999, "未知异常");

    private int status;

    private String message;

    ExceptionEnum(int status, String message) {
        this.status = status;
        this.message = message;
    }

    public int getStatus() {
        return status;
    }

    public String getMessage() {
        return message;
    }
}

总结

通过异常枚举类 + 自定义异常类 + SpringBoot的异常处理注解,可以实现对项目量身定做一套异常处理机制,根据项目中出现的异常,来返回对应的异常信息,非常方便。


http://www.kler.cn/news/157021.html

相关文章:

  • GEE:使用拉普拉斯(Laplacian)算子对遥感图像进行卷积操作
  • 英语语法学习 - 每周更新学英语知识点
  • 小米秒享3--非小米电脑
  • 基于YOLOv8深度学习的安全帽目标检测系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战
  • python之ddddocr快速识别
  • 茄子科技张韶全:跨多云大数据平台DataCake在OceanBase的实践
  • 2024最新版软件测试八股文(文档)
  • AI浪潮下,非科班出身还有机会入行程序开发领域么?
  • jquery学习笔记
  • 12.04 二叉树中等题
  • Vue3组合式API
  • DevEco Studio将常用内容设为代码模板 通过快捷键调出
  • 网工学习8-配置 STP 协议(一)
  • 【陈老板赠书活动 - 19期】-2023年以就业为目的学习Java还有必要吗?
  • 【数组】-Lc27-移除元素(相向双指针)
  • android studio 打开flutter项目 出现 dart sdk is not configured
  • navicat premium 历史版本下载地址
  • AI代码助手:写代码“如虎添翼”
  • 自动化集成有哪些典型应用场景?
  • 【程序员的养生指南--散文篇】
  • 毕业项目分享
  • LabVIEW开发工业设备远程在线状态监测
  • 如何有效进行测试执行进度计划
  • 力扣374周赛
  • 前端开发学习 (四) 自定义按键修饰符
  • Redis5新特性-stream
  • 鸿蒙开发笔记
  • fbprophet 安装流程
  • 探索人工智能领域——每日20个名词详解【day7】
  • Win10安装ROS2遇到的小问题