统一异常处理

本文介绍了一种优雅的全局异常处理方案,通过自定义异常枚举、异常对象及响应类,实现异常信息的有效管理和反馈。此方案能快速帮助开发者定位问题,提升开发效率。

看到一篇处理方式比较清爽的,单做一个记录
原地址:如何优雅的处理全局异常

前言

异常处理是项目开发中绕不过的一个环节,一个优雅的全局异常处理可以迅速反馈给开发人员这些信息

1、异常种类

2、可能导致异常的原因

3、导致异常出现的关键参数

4、异常发生的时间

5、发生异常的请求路径

这些信息有助于开发人员迅速定位、处理异常,一个优秀的项目应该尽可能的将可能发生的异常进行捕获,再通过自定义的处理流程将异常信息反馈,而不是一味的抛出异常。

异常捕获流程

通常我们可以构建message和枚举类来管理异常种类,这样可以在写代码处理异常时让程序员更高程度的关注于业务

CodeEnum错误枚举类

/**
 * @author
 */
@Getter
@AllArgsConstructor
public enum CodeEnum {

    RESOURCE_NOT_FOUNT(1001, HttpStatus.HTTP_NOT_FOUND,"未找到该资源"),
    PARAMS_FORMAT_INVALID(1002,HttpStatus.HTTP_BAD_REQUEST,"请求参数格式错误");

    /**
     * 自定义业务code
     */
    private final int code;

    /**
     * http状态码
     */
    private final int httpStatus;

    /**
     * 返回信息
     */
    private final String message;

}

基础异常对象

BaseException 是所有自定义异常的父类,它规范了异常的基本结构由 CodeEnum 和 Map(附加信息)组成

@Data
@NoArgsConstructor
public class BaseException extends RuntimeException {

    private CodeEnum codeEnum;

    private final Map<String, Object> detail = new HashMap<>();

    public BaseException(CodeEnum codeEnum) {
        this.codeEnum = codeEnum;
    }

    public BaseException(CodeEnum codeEnum, Map<String, Object> params) {
        this.codeEnum = codeEnum;
        if (!ObjectUtils.isEmpty(params)) {
            this.detail.putAll(params);
        }
    }

    public BaseException(CodeEnum codeEnum, String msg) {
        this.codeEnum = codeEnum;
        HashMap<String, String> map = new HashMap<>();
        map.put("description", msg);
        detail.putAll(map);
    }

}

ErrorResponse异常响应

定义一个异常视图对象,构建异常的基本信息,比如时间,请求路径等,该对象接收一个 BaseException 异常类。

/**
 * 异常响应类
 * @author
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ErrorResponse {
    private Integer code;
    private Integer httpStatus;
    private String message;
    private String path;
    private Instant timestamp;
    private Map<String, Object> detail = new HashMap<>();

    public ErrorResponse(BaseException e, String path) {
        this.code = e.getCodeEnum().getCode();
        this.httpStatus = e.getCodeEnum().getHttpStatus();
        this.timestamp = Instant.now();
        this.path = path;
        this.message = e.getCodeEnum().getMessage();
        if (ObjectUtils.isEmpty(e.getDetail())){
            this.detail.put("description", "");
        }else {
            this.detail.putAll(e.getDetail());
        }
   

Result全局返回对象

一个项目的请求返回对象应该做到全局统一,这样开发的时候就不用纠结到底该返回哪个对象

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
    private Boolean success;
    private T data;

    public static Result<Object> ok() {
        return new Result<>(true, null);
    }

    public static Result<String> ok(String msg) {
        return new Result<>(true, msg);
    }

    public static Result<Object> ok(Object data) {
        return new Result<>(true, data);
    }

    public static Result<Object> error() {
        return new Result<>(false, null);
    }

    public static Result<String> error(String msg) {
        return new Result<>(false, msg);
    }

    public static Result<ErrorResponse> error(ErrorResponse error) {
        return new Result<>(false, error);
    }

}

GlobalExceptionHandler异常捕获类

@RestControllerAdvice
public class GlobalExceptionHandler {

	// 表示处理BaseException.class这个类型的异常
    @ExceptionHandler(BaseException.class)
    public Result<ErrorResponse> baseException(BaseException e, HttpServletRequest request) {
        ErrorResponse errorResponse = new ErrorResponse(e,request.getRequestURI());
        return Result.error(errorResponse);
    }
}

测试

@RestController
@RequestMapping(value = "/test/ex", produces = MediaType.APPLICATION_JSON_VALUE)
public class ExceptionController {

    @GetMapping("/resource")
    public Result<Object> resource() {
        throw new BaseException(CodeEnum.RESOURCE_NOT_FOUNT);
    }

    @PostMapping("/resource")
    public Result<Object> resource(@RequestBody User user) {
        throw new BaseException(CodeEnum.PARAMS_FORMAT_INVALID,
                ImmutableMap.of("name", user.getName(),
                        "age", user.getAge(),
                        "email", user.getEmail()));
    }

    @GetMapping("/id")
    public Result<Object> test(@Param("id") String id) {
        if (id.length() > 5) {
            throw new BaseException(CodeEnum.RESOURCE_NOT_FOUNT, "The invalid id is:\r\n" + id);
        } else {
            return Result.ok();
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值