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的异常处理注解,可以实现对项目量身定做一套异常处理机制,根据项目中出现的异常,来返回对应的异常信息,非常方便。

猜你喜欢

转载自blog.csdn.net/qq_42108331/article/details/134778472