注解实现自定义异常抛出

背景
  公司项目数据源并非DB,目前已经对该数据源的表数据操作进行封装复用,但此数据源创建、删除、修改操作只会返回布尔值,业务逻辑中如果是此数据源操作出现问题,需返回前端异常信息为此数据源操作异常,因为数据表繁多,业务逻辑判断中也会出现很多抛出自定义异常的重复代码。为了减少不必要代码的产生,需要将异常抛出下沉,不在业务逻辑中重复抛出异常的方法。

实现思路
  受限于数据源,每个表都会写一个单独的Manager.java去处理一些数据二次转换以及封装问题,此数据源创建、删除、修改操作对于底层都是数据字段的set操作,如果想要异常描述更清晰,只能在Manager.java中实现异常处理,而不是更底层的方法。

1. 创建一个注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExceptionThrow {

    /**
     * 被操作资源表
     * @return {@link ResourceTypeEnum}
     */
    ResourceTypeEnum resourceType();

    /**
     * 操作
     * @return {@link OperationEnum}
     */
    OperationEnum operation();

    /**
     * 要抛出异常的类型,默认mb操作失败异常
     * @return {@link GlobalExceptionEnum}
     */
    GlobalExceptionEnumexception() default GlobalExceptionEnum.mb_set_fail;

    /**
     * 数据源
     * @return {@link DataSourceEnum}
     */
    DataSourceEnum dataSource() default DataSourceEnum.MB;


    enum OperationEnum {
        select, create, delete, update
    }

    enum DataSourceEnum {
        MB, DB
    }

2. 创建一个注解处理类

@Aspect
@Component
@Slf4j
public class ExceptionThrowAspect {

    @Around(@annotation(ExceptionThrow))
    public Object aroundMibCut(ProceedingJoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method == null) {
            log.warn("ExceptionThrowAspect method is null!!!");
            return new Object();
        }
        ExceptionThrow exceptionThrow = method.getAnnotation(ExceptionThrow.class);
        Object dataId = null;
        // 方法参数值
        Object[] args = joinPoint.getArgs();
        Object obj = new Object();
        try {
            obj = joinPoint.proceed();
            Parameter[] parameters = method.getParameters();
            //  遍历出id的值
            for (int i = 0; i < parameters.length; i++) {
                if ("id".equals(parameters[i].getName())) {
                    dataId = args[i];
                    break;
                }
            }
        } catch (Throwable e) {
            e.printStackTrace();
            log.warn("ExceptionThrowAspect for do ({}) exception:{}", signature.getName(), e.getMessage());
        }
        throwException(obj, dataId, exceptionThrow);
        return obj;
    }

    /**
     * 格式化异常的信息描述
     *
     * @param obj            方法逻辑结果
     * @param dataId         mb/db数据主键
     * @param exceptionThrow {@link ExceptionThrow} 操作类型
     */
    private void throwException(Object obj, Object dataId, ExceptionThrow exceptionThrow) {
        // 不同数据源抛出异常的条件
        boolean throwException = ExceptionThrow.DataSourceEnum.MB== exceptionThrow.dataSource() ? !((boolean) obj) : obj == null;
        if (throwException && dataId != null) {
            String template = "{} {}, "+ exceptionThrow.dataSource().name() +" id is {} !";
            String msg = StrUtil.format(template, exceptionThrow.operation(), exceptionThrow.resourceType().name(), dataId);
            throw new OtnGlobalException(exceptionThrow.exception(), msg);
        }
    }

有特殊异常处理的方法可以使用该注解。水平有限,欢迎指教。

posted @   突然冷成狗  阅读(442)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示