common--全局异常处理器

简介: 微服务相关统一处理

一、介绍

正常的Web应用开发时,需要考虑到应用运行发生异常时或出现错误时如何来被处理,例如捕获必要的异常信息,记录日志方便日后排错,友好的用户响应输出等等.而应用程序发生错误,有可能是应用自身的问题,也有可能是客户端操作的问题.在我们的项目中全局异常处理非常重要。

二、自定义异常

对不同的异常类型定义异常类,继承Exception。

image.png

 *  @Description 自定义异常超类
 *  @Author gc.x
 *
 */
public class BaseException extends RuntimeException {
}

/**
 * @Description 客户端异常

 */
@Getter
public class BizException extends BaseException {

    private CodeEnum codeEnum;  //状态码
    private String errorMessage;  //错误详细信息

    public BizException(String errorMessage) {
       this.codeEnum = CodeEnum.ILLEGAL_REQUEST;
       this.errorMessage = errorMessage;
    }

    public BizException(CodeEnum codeEnum, String errorMessage) {
        this.codeEnum = codeEnum;
        this.errorMessage = errorMessage;
    }
}

创建自定义状态码枚举类,例如:
image.png

三、全局异常处理器

/**
 * @Description 全局异常处理器
 * @Author gc.x
 */
@Slf4j
@RestControllerAdvice
public class WebExceptionHandler {

    /**
     * 服务名
     */
    @Value("${spring.application.name}")
    private String serverName;

    /**
     * 错误信息前缀
     */
    private String errorMessagePrefix;

    @PostConstruct
    public void init() {
        this.errorMessagePrefix = "(" + this.serverName + "服务>) ";
    }

    /**
     * @Description 处理系统内部异常(未知异常, 入空指针, 索引越界)
     */
    @ExceptionHandler(value = {Exception.class})
    public Object handlerException(Exception e, HttpServletRequest request, HttpServletResponse response) {
        log.error("请求路径uri={},系统内部出现异常:{}", request.getRequestURI(), e);
        handleFeign(request, response, CodeEnum.SYSTEM_INNER_ERROR);
        return ResultSet.error(CodeEnum.SYSTEM_INNER_ERROR, errorMessagePrefix + e.toString(), "服务器繁忙,请稍后再试");
    }

    /**
     * @Description 非法请求异常(SpringAOP)
     */
    @ExceptionHandler(value = {
            HttpMediaTypeNotAcceptableException.class,
            HttpMediaTypeNotSupportedException.class,
            HttpRequestMethodNotSupportedException.class,
            MissingServletRequestParameterException.class,
            NoHandlerFoundException.class,
            MissingPathVariableException.class,
            HttpMessageNotReadableException.class
    })
    public ResultSet<?> handlerSpringAOPException(Exception exception, HttpServletRequest request, HttpServletResponse response) {
        log.error("非法请求异常:{}", exception.getMessage());
        handleFeign(request, response, CodeEnum.ILLEGAL_REQUEST);
        return ResultSet.error(CodeEnum.ILLEGAL_REQUEST, errorMessagePrefix + exception.getMessage(), exception.getMessage());
    }

    /**
     * @Description 非法请求异常(@ DateTimeFormat注解抛出异常)
     */
    @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
    public ResultSet<?> handlerSpringAOPException(MethodArgumentTypeMismatchException e, HttpServletRequest request, HttpServletResponse response) {
        log.error("非法请求异常:{}", e.getMessage());
        handleFeign(request, response, CodeEnum.ILLEGAL_REQUEST);
        return ResultSet.error(CodeEnum.ILLEGAL_REQUEST, errorMessagePrefix + e.getMessage(), e.getMessage());
    }

    @ExceptionHandler(DeleteException.class)
    public ResultSet<?> handleDeleteException(DeleteException e, HttpServletRequest request, HttpServletResponse response) {
        log.error("删除验证失败:{}", e.getDeleteValidFailures());
        handleFeign(request, response, CodeEnum.DELETE_VALID);
        return ResultSet.custom(CodeEnum.DELETE_VALID, e.getDeleteValidFailures());
    }

    @ExceptionHandler(BatchException.class)
    public ResultSet<?> handleBatchException(BatchException e, HttpServletRequest request, HttpServletResponse response) {
        log.error("批量操作失败:{}", e.getBatchInfo());
        handleFeign(request, response, CodeEnum.BATCH_OP);
        return ResultSet.custom(CodeEnum.BATCH_OP, e.getBatchInfo());
    }

    /**
     * @Description 非法请求(处理spring validation参数校验抛出异常1)
     */
    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public ResultSet<?> handlerMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request, HttpServletResponse response) {
        //获取异常字段及对应的异常信息
        StringBuilder stringBuilder = new StringBuilder();
        Class<?> target = e.getBindingResult().getTarget().getClass();
        e.getBindingResult().getAllErrors().stream()
                .map(error -> {
                    if (error instanceof FieldError) {
                        FieldError t = (FieldError) error;
                        ApiModelProperty property = null;
                        try {
                            property = target.getDeclaredField(t.getField()).getAnnotation(ApiModelProperty.class);
                        } catch (NoSuchFieldException noSuchFieldException) {
                            noSuchFieldException.printStackTrace();
                        }
                        String name = (property == null ? t.getField() : Optional.of(property.value()).orElse(t.getField()));
                        return "[" + name + "]-[" + t.getRejectedValue() + "]=>" + t.getDefaultMessage() + " ";
                    } else {
                        return error.getDefaultMessage();
                    }
                }).forEach(stringBuilder::append);
        String errorMessage = stringBuilder.toString();

        log.error("请求参数异常:{}", errorMessage);
        handleFeign(request, response, CodeEnum.ILLEGAL_REQUEST);
        return ResultSet.error(CodeEnum.ILLEGAL_REQUEST, errorMessagePrefix + errorMessage, errorMessage);
    }

    /**
     * @Description 非法请求异常(处理spring validation参数校验抛出异常2)
     */
    @ExceptionHandler(value = {ConstraintViolationException.class})
    public ResultSet<?> handlerConstraintViolationException(ConstraintViolationException e, HttpServletRequest request, HttpServletResponse response) {
        String errorMessage = e.getLocalizedMessage();
        log.error("非法请求异常:{}", errorMessage);
        handleFeign(request, response, CodeEnum.ILLEGAL_REQUEST);
        return ResultSet.error(CodeEnum.ILLEGAL_REQUEST, errorMessagePrefix + e.getMessage(), errorMessage);
    }

    /**
     * @Description 处理业务异常
     */
    @ExceptionHandler(value = {BizException.class})
    public ResultSet<?> handlerCustomException(BizException e, HttpServletRequest request, HttpServletResponse response) {
        String errorMessage = e.getErrorMessage();
        log.error("客户端异常:{}", errorMessage);
        handleFeign(request, response, e.getCodeEnum());
        return ResultSet.error(e.getCodeEnum(), errorMessagePrefix + errorMessage, errorMessage);
    }

    /**
     * @Description 处理系统异常
     */
    @ExceptionHandler(value = {ServerException.class})
    public ResultSet<?> handlerServerException(ServerException e, HttpServletRequest request, HttpServletResponse response) {
        String errorMessage = e.getErrorMessage();
        log.error("服务端异常:{}", errorMessage);
        handleFeign(request, response, e.getCodeEnum());
        return ResultSet.error(e.getCodeEnum(), errorMessagePrefix + e.getMessage(), errorMessage);
    }

    // 处理feign调用时异常,不进行返回封装,按原内容直接抛出
    private void handleFeign(HttpServletRequest request, HttpServletResponse response, CodeEnum codeEnum) {
        if (StringUtils.isNotEmpty(request.getHeader(Global.FEIGN))) {
            response.setStatus(codeEnum.getCode());
        }
    }
}
目录
相关文章
|
6月前
|
安全 Java 数据库连接
Security自定义全局AuthenticationManager
Security自定义全局AuthenticationManager
198 1
|
6月前
|
Java
SpringBoot全局异常@RestControllerAdvice全局异常
SpringBoot全局异常@RestControllerAdvice全局异常
33 0
|
缓存 JSON Java
【Java】SpringCloud Gateway自定义过滤器中获取ServerHttpRequest的body中的数据为NULL的问题
【Java】SpringCloud Gateway自定义过滤器中获取ServerHttpRequest的body中的数据为NULL的问题
568 0
定义全局异常和全局异常处理器
定义全局异常和全局异常处理器
ts解决依赖引入报错:无法找到模块“xxxxxx”的声明文件的报错问题
ts解决依赖引入报错:无法找到模块“xxxxxx”的声明文件的报错问题
1878 0
springMvc56-全局异常
springMvc56-全局异常
91 0
SpringMVC - 全局异常
SpringMVC - 全局异常
112 0
SpringMVC - 全局异常
|
SQL JSON Java
Mybaties分页插件使用, 参数校验以及全局异常处理
本文教你快速进行Mybaties分页插件使用, 参数校验以及全局异常处理
|
存储 Java 微服务
common--全局日志处理
操作日志和微服务场景日志统一处理
242 0
common--全局日志处理
common--全局返回
controller层全局实体类包装返回
237 0