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());
        }
    }
}
目录
相关文章
|
Arthas 缓存 Java
在 Windows 下的 Arthas 快速安装 | 学习笔记
快速学习在 Windows 下的 Arthas 快速安装
在 Windows 下的 Arthas 快速安装 | 学习笔记
|
4月前
|
JSON API 数据库
手机空号检测API:接口技术详解
介绍号码有效性检测技术,涵盖空号识别原理、高并发架构设计及Python集成示例,助力企业提升电销、风控等场景的运营效率,降低无效号码带来的资源浪费。
714 0
|
NoSQL 关系型数据库 MySQL
docker部署jumpserver及入门
docker部署jumpserver及入门
|
9月前
|
Java 开发者 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——什么是AOP
本文介绍了Spring Boot中的切面AOP处理。AOP(Aspect Oriented Programming)即面向切面编程,其核心思想是分离关注点。通过AOP,程序可以将与业务逻辑无关的代码(如日志记录、事务管理等)从主要逻辑中抽离,交由专门的“仆人”处理,从而让开发者专注于核心任务。这种机制实现了模块间的灵活组合,使程序结构更加可配置、可扩展。文中以生活化比喻生动阐释了AOP的工作原理及其优势。
530 0
|
应用服务中间件 Linux nginx
Mac os 安装 nginx 教程(success)
这篇文章是关于如何在Mac OS系统上使用Homebrew安装nginx及其依赖,并解决安装过程中可能出现的权限问题。
1763 0
Mac os 安装 nginx 教程(success)
|
机器学习/深度学习 算法
生成对抗网络(Generative Adversarial Networks,简称GANs)
生成对抗网络(GANs)由Ian Goodfellow等人于2014年提出,是一种通过生成器和判别器的对抗训练生成逼真数据样本的深度学习模型。生成器创造数据,判别器评估真实性,两者相互竞争优化,广泛应用于图像生成、数据增强等领域。
1695 1
|
Java Spring
获取spring工厂中bean对象的两种方式
获取spring工厂中bean对象的两种方式
177 1
|
Java Spring 开发者
解锁 Spring Boot 自动化配置的黑科技:带你走进一键配置的高效开发新时代,再也不怕繁琐设置!
【8月更文挑战第31天】Spring Boot 的自动化配置机制极大简化了开发流程,使开发者能专注业务逻辑。通过 `@SpringBootApplication` 注解组合,特别是 `@EnableAutoConfiguration`,Spring Boot 可自动激活所需配置。例如,添加 JPA 依赖后,只需在 `application.properties` 配置数据库信息,即可自动完成 JPA 和数据源设置。这一机制基于多种条件注解(如 `@ConditionalOnClass`)实现智能配置。深入理解该机制有助于提升开发效率并更好地解决问题。
284 0
|
前端开发 网络架构
计算机网络——第一章时延部分深入学习、相关习题及详细解析
计算机网络——第一章时延部分深入学习、相关习题及详细解析
811 0
|
关系型数据库 MySQL 数据库连接
FreeSWITCH通过mod_mariadb原生连接MySQL
FreeSWITCH通过mod_mariadb原生连接MySQL
1069 0

热门文章

最新文章