我的技术学习物语果然有问题
(最后更新 )

异常处理

常用的全局异常处理。

自定义异常类(配合结果类)

/**
 * @author yww
 * @since 2021/10/9
 **/
@Getter
@AllArgsConstructor
public class GlobalException extends RuntimeException {

    /**
     * 错误码
     */
    private Integer code = FAILED.getCode();

    /**
     * 错误信息
     */
    private final String message;

    public GlobalException(String message) {
        this.message = message;
    }

    public GlobalException(ResultCode resultCode) {
        this.code = resultCode.getCode();
        this.message = resultCode.getMessage();
    }

}

这里需要注意的是,自定义异常需要继承RuntimeException(运行时异常)。

定义全局异常处理

/**
 *  <p>
 *     全局异常处理
 *  </p>
 *
 * @author yww
 * @since 2021/10/10
 **/
@Slf4j
@RestControllerAdvice
public class ControllerAdviceHandler {

    /**
     * 处理自定义的服务异常信息
     * 统一处理GlobalException异常,异常处理顺序是从小异常到大异常。
     *
     * @param e 服务异常
     * @return 异常信息
     */
    @ExceptionHandler(value = GlobalException.class)
    public <T> Result<T> globalExceptionHandler(GlobalException e, HttpServletRequest request) {
        log.error(">> global exception: {}, {}, {}", request.getRequestURI(), e.getCode(), e.getMessage());
        String errMessage = e.getMessage();
        // 防止空的错误信息
        if (StringUtils.isBlank(errMessage)) {
            errMessage = "服务器繁忙";
        }
        return Result.failure(e.getCode(), errMessage);
    }

    /**
     * 异常信息
     *
     * @param e 服务异常
     * @return 异常信息
     */
    @ExceptionHandler(value = Exception.class)
    public <T> Result<T> defaultErrorHandler(Exception e, HttpServletRequest request) {
        log.error(">> 服务器内部错误 " + request.getRequestURI(), e.getMessage());
        return Result.failure(500, "服务器繁忙");
    }

}

@RestControllerAdvice注解其实是@ControllerAdvice和@ResponseBody的合并。

@ControllerAdvice通常配合@ExceptionHandler来捕抓异常信息。

@ControllerAdvice可以捕抓到系统抛出的异常,然后使用@ExceptionHandler匹配具体处理异常信息。

特殊的异常处理

有些异常是不会走全局异常处理的,即不会被捕捉到,比如在过滤器中的异常,这种异常是没有经过controller的,所以发生了异常,也不会通过被上述的方式捕捉到。

以下是一个捕捉Token过滤器异常的例子。

/**
 * <p>
 *      Token身份验证过滤器
 * </p>
 *
 * @author yww
 * @since 2022/10/20
 */
@Slf4j
public class TokenAuthenticationFilter extends BasicAuthenticationFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
        try {
            .....
            // 处理Token验证的异常
        } catch (AlgorithmMismatchException | SignatureVerificationException | TokenExpiredException
                 | MissingClaimException | IncorrectClaimException e) {
            errorHandler(request, response, e);
        }
    }

    /**
     * 处理异常信息
     *
     * @param request  请求
     * @param response 响应
     * @param e        异常
     */
    private void errorHandler(HttpServletRequest request, HttpServletResponse response, Exception e) {
        if (e instanceof AlgorithmMismatchException) {
            resolver.resolveException(request, response, null, new AlgorithmMismatchException(e.getMessage()));
            return;
        }
        if (e instanceof TokenExpiredException) {
            resolver.resolveException(request, response, null, new TokenExpiredException(
                    e.getMessage(),
                    ((TokenExpiredException) e).getExpiredOn())
            );
            return;
        }
        if (e instanceof MissingClaimException) {
            resolver.resolveException(request, response, null, new MissingClaimException(
                    ((MissingClaimException) e).getClaimName())
            );
            return;
        }
        if (e instanceof IncorrectClaimException) {
            resolver.resolveException(request, response, null, new IncorrectClaimException(
                    e.getMessage(),
                    ((IncorrectClaimException) e).getClaimName(),
                    ((IncorrectClaimException) e).getClaimValue())
            );
            return;
        }
        if (e instanceof JWTVerificationException) {
            resolver.resolveException(request, response, null, new JWTVerificationException(
                    e.getMessage(),
                    e.getCause())
            );
        }
    }

}