SpringBoot AOP实现日志或告警(高级)


总结:技术点 动态代理 + 模版方法模式 + 线程池异步处理/MQ

其中代理模式使用jdk动态代理

一、目的

实现:客户订单全局消息提醒业务员
涉及业务:客户订单、产品包、出库结算、客留存、结算单预处理、字印任务等6个模块;
未来涉及:采购订单、委外订单、订单核销等
归纳:全局信息的处理;如权限或日志等类似这样的需求

二、难点:如何实现不同接口不同入参的数据转换?

1.定义注解的转换类,将不同的业务转换成相同的消息或日志,再进行入库
2.采用SpEL表达式进行实现

三、代码实现

1.定义 切点注解接口

说明:通过此接口作用在目标方法上,作为切入点

/**
 * descr
 *
 * @author: bjh
 * @date: 2023/9/5
 **/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OrderMessageOperate {

    /**
     * 客户订单操作类型:1.根据客户订单ID 2.根据客户订单编号
     *
     * @return 描述
     */
    String operateType() default "";

    /**
     * 根据不同操作类型实现不同的convert进行转换
     *
     * @return 转换子类
     */
    Class<? extends OrderMessageConvert> convert();
}

2.定义 转换接口和模版方法

说明:将不同入参转换为消息或DO进行入库
当前业务:目前订单状态的变更需要通知业务员和业务员领导,所以这里返回为list类型;业务上也出现了一对多的情况,如一个结算单对应同一个客户的多个订单,每个订单需要通知相应的业务员和领导,这里也是需要转为list

/**
 * descr 不同业务转为相同的订单消息对象
 *
 * @author: bjh
 * @date: 2023/9/5
 **/
public interface OrderMessageConvert<Param> {

    /**
     * 入参转标准模型
     *
     * @param param
     * @return
     */
    List<OrderMessageDO> convert(Param param);
}

3.定义 切面类

说明:切面包含多个切点类(如pointCut)和多种增强方式(即横切逻辑 如@Arround,@Before,@AfterReturning,@AfterThrowing等)
技术:@Aspect默认使用jdk动态代理;

/**
 * descr
 *
 * @author: bjh
 * @date: 2023/9/5
 **/
@Aspect
@Component
public class OrderMessageAspect {

    // 异步线程执行
    private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            1, 1,
            1, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100));

    /**
     * 1.定义切入点
     * 2.横切逻辑
     * 3.植入(spring)
     */
    @Pointcut("@annotation(cn.iocoder.yudao.module.wh.aop.customerorder.OrderMessageOperate)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // 执行切入点方法,拿到返回结果 ???
        final Object result = proceedingJoinPoint.proceed();
        this.threadPoolExecutor.execute(() -> {
            try {
                final MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
                final OrderMessageOperate annotation = methodSignature.getMethod().getAnnotation(OrderMessageOperate.class);
                final OrderMessageConvert orderMessageConvert = annotation.convert().newInstance();
                final List<OrderMessageDO> orderMessageDOS = orderMessageConvert.convert(proceedingJoinPoint.getArgs()[0]);
                for (OrderMessageDO orderMessageDO : orderMessageDOS) {
                    orderMessageDO.setOperateType(annotation.operateType());
                }
                if (ObjectUtil.isNotNull(orderMessageDOS)) {
                    SpringUtil.getBean(OrderMessageService.class).insertBatchOrderMessage(orderMessageDOS);
                }
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        });
        return result;
    }
}

4.定义 转换实现类

说明:根据不同切入接口定义不同的转换类,如下

1.图
在这里插入图片描述

2.举两代码例子
代码1


/**
 * descr    通过客户订单Create对象进行转换
 *
 * @author: bjh
 * @date: 2023/9/5
 **/
public class CustomerOrderCreateConvert implements OrderMessageConvert<CustomerOrderCreateReqVO> {

    @Override
    public List<OrderMessageDO> convert(CustomerOrderCreateReqVO orderCreateReqVO) {
        final CustomerOrderService customerOrderService = SpringUtil.getBean(CustomerOrderService.class);
        final CustomerOrderRespVO orderRespVO = customerOrderService.getCustomerOrderByOrderNo(orderCreateReqVO.getOrderNo(), true);
        return SpringUtil.getBean(OrderMessageService.class).convertByCustomerOrderId(orderRespVO.getId());
    }
}

代码2


/**
 * descr    通过客户订单ID进行转换
 *
 * @author: bjh
 * @date: 2023/9/5
 **/
public class CustomerOrderIdConvert implements OrderMessageConvert<Long> {

    @Override
    public List<OrderMessageDO> convert(Long customerOrderId) {
        return SpringUtil.getBean(OrderMessageService.class).convertByCustomerOrderId(customerOrderId);
    }
}

5.业务方法使用注解

说明:下面代码中OrderOperateConstant.ORDER_CREATE_OPT/ORDER_TO_PICK_OPT是常量类型,定义操作类型(新增/修改/审核等)

代码1

 @PostMapping("/create")
    @Operation(summary = "创建客户订单")
    @PreAuthorize("@ss.hasPermission('wh:customer-order:create')")
    @OrderMessageOperate(operateType = OrderOperateConstant.ORDER_CREATE_OPT, convert = CustomerOrderCreateConvert.class)
    public CommonResult<Long> createCustomerOrder(@Valid @RequestBody CustomerOrderCreateReqVO createReqVO) {
        return success(customerOrderService.createCustomerOrder(createReqVO));
    }

代码2

@PutMapping("/allow-to-pick")
    @Operation(summary = "与客户沟通可拣货")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('wh:customer-order:allow-to-pick')")
    @OrderMessageOperate(operateType = OrderOperateConstant.ORDER_TO_PICK_OPT, convert = CustomerOrderIdConvert.class)
    public CommonResult<Boolean> allowToPickOrder(@RequestParam("id") Long id) {
        return success(this.customerOrderService.allowToPickOrder(id));
    }

6.常量类和枚举

说明:
疑问:有了枚举为什么还要定义一个常量类,getKey不就完事了吗?
我的想法:增加一个常量类,在维护代码时ctrl+鼠标左键可以直接定位到引用的代码行;同样的操作getkey会列出所有选项让我们去选,枚举实例特别多的时候,选准确耗时多,我个人不习惯这种感觉。所以就增加了常量类

常量类:


/**
 * descr
 *
 * @author: bjh
 * @date: 2023/9/5
 **/
public interface OrderOperateConstant {
    String ORDER_PREPOSSESS_OPT = "01";
    String ORDER_TO_PICK_OPT = "02";
    String ORDER_RETURN_RECEIVE_OPT = "03";
    String ORDER_RETURN_OPT = "04";
    String ORDER_RECEIVE_OPT = "05";
    String ORDER_TRANSFER_OPT = "06";
    String ORDER_APPLY_OPT = "07";
    String ORDER_REMAIN_OPT = "08";
    String ORDER_DISCARD_OPT = "09";
    String ORDER_DELIVERED_OPT = "10";
    String ORDER_DELIVERABLE_OPT = "11";
    String ORDER_PACKING_OPT = "12";
    String ORDER_SYNC_OPT = "13";
    String ORDER_INFIRM_OPT = "14";
    String ORDER_CREATE_OPT = "15";
    String ORDER_UPDATE_OPT = "16";
    String ORDER_APPLY_CONFIRM_OPT = "17";

    String PACK_CREATE_OPT = "18";
    String PACK_UPDATE_OPT = "19";
    String PACK_DELETE_OPT = "20";
    String PACK_CONFIRM_OPT = "21";
    String PACK_INFIRM_OPT = "22";
    String PACK_DISCARD_OPT = "23";
    String PACK_TO_SALE_OPT = "24";
    String PACK_SALE_RECEIVE_OPT = "25";
    String PACK_SALE_RETURN_OPT = "26";
    String PACK_RECEIVE_OPT = "27";

    String SALE_BILL_CREATE_OPT = "28";
    String SALE_BILL_UPDATE_OPT = "29";
    String SALE_BILL_DELETE_OPT = "30";
    String SALE_BILL_CONFIRM_OPT = "31";
    String SALE_BILL_INFIRM_OPT = "32";
    String SALE_BILL_DISCARD_OPT = "33";
    String SALE_BILL_DELIVERY_APPLY_OPT = "34";
    String SALE_BILL_DELIVERY_CONFIRM_OPT = "35"; // todo 审核问题
    String SALE_BILL_UPLOAD_OPT = "36";
    String SALE_BILL_DELIVERED_OPT = "37";

    String MARKING_BILL_CREATE_OPT = "38";
    String MARKING_BILL_UPDATE_OPT = "39";
    String MARKING_BILL_DELETE_OPT = "40";
    String MARKING_BILL_CONFIRM_OPT = "41";
    String MARKING_BILL_INFIRM_OPT = "42";
    String MARKING_BILL_DISCARD_OPT = "43";
    String MARKING_BILL_MARKING_OPT = "44";
    String MARKING_BILL_FINISH_OPT = "45";

    String SALE_PREPOSSESSING_CREATE_OPT = "46";
    String SALE_PREPOSSESSING_UPDATE_OPT = "47";
    String SALE_PREPOSSESSING_DELETE_OPT = "48";
    String SALE_PREPOSSESSING_CONFIRM_OPT = "49";
    String SALE_PREPOSSESSING_INFIRM_OPT = "50";
    String SALE_PREPOSSESSING_DISCARD_OPT = "51";
}

枚举:


/**
 * descr
 *
 * @author: bjh
 * @date: 2023/9/5
 **/
public enum OrderOperateEnum {
    ORDER_PREPOSSESS_OPT(OrderOperateConstant.ORDER_PREPOSSESS_OPT, "结算预处理"),
    ORDER_ALLOW_TO_PICK_OPT(OrderOperateConstant.ORDER_TO_PICK_OPT, "客户沟通可拣货"),
    ORDER_RETURN_RECEIVE_OPT(OrderOperateConstant.ORDER_RETURN_RECEIVE_OPT, "接受退回产品包"),
    ORDER_RETURN_OPT(OrderOperateConstant.ORDER_RETURN_OPT, "结算台退回产品包"),
    ORDER_RECEIVE_OPT(OrderOperateConstant.ORDER_RECEIVE_OPT, "字印部接收"),
    ORDER_TRANSFER_OPT(OrderOperateConstant.ORDER_TRANSFER_OPT, "调拨产品包到字印部门"),
    ORDER_APPLY_OPT(OrderOperateConstant.ORDER_APPLY_OPT, "客留存延期申请"),
    ORDER_REMAIN_OPT(OrderOperateConstant.ORDER_REMAIN_OPT, "客留存"),
    ORDER_DISCARD_OPT(OrderOperateConstant.ORDER_DISCARD_OPT, "客户订单作废"),
    ORDER_DELIVERED_OPT(OrderOperateConstant.ORDER_DELIVERED_OPT, "客户订单出货接口(老庙)"),
    ORDER_DELIVERABLE_OPT(OrderOperateConstant.ORDER_DELIVERABLE_OPT, "客户订单可出货接口(老庙)"),
    ORDER_PACKING_OPT(OrderOperateConstant.ORDER_PACKING_OPT, "客户订单备货接口(老庙)"),
    ORDER_SYNC_OPT(OrderOperateConstant.ORDER_SYNC_OPT, "客户订单同步(老庙)"),
    ORDER_INFIRM_OPT(OrderOperateConstant.ORDER_INFIRM_OPT, "取消拣货(老庙)"),
    ORDER_CREATE_OPT(OrderOperateConstant.ORDER_CREATE_OPT, "客户订单创建"),
    ORDER_UPDATE_OPT(OrderOperateConstant.ORDER_UPDATE_OPT, "客户订单修改"),
    ORDER_APPLY_CONFIRM_OPT(OrderOperateConstant.ORDER_APPLY_CONFIRM_OPT, "延期申请审核"),

    PACK_CREATE_OPT(OrderOperateConstant.PACK_CREATE_OPT, "产品包创建"),
    PACK_UPDATE_OPT(OrderOperateConstant.PACK_UPDATE_OPT, "产品包修改"),
    PACK_DELETE_OPT(OrderOperateConstant.PACK_DELETE_OPT, "产品包删除"),
    PACK_CONFIRM_OPT(OrderOperateConstant.PACK_CONFIRM_OPT, "产品包审核"),
    PACK_INFIRM_OPT(OrderOperateConstant.PACK_INFIRM_OPT, "产品包反审"),
    PACK_DISCARD_OPT(OrderOperateConstant.PACK_DISCARD_OPT, "产品包作废"),
    PACK_TO_SALE_OPT(OrderOperateConstant.PACK_TO_SALE_OPT, "产品包调拨到结算"),

    PACK_SALE_RECEIVE_OPT(OrderOperateConstant.PACK_SALE_RECEIVE_OPT, "结算接收产品包"),
    PACK_SALE_RETURN_OPT(OrderOperateConstant.PACK_SALE_RETURN_OPT, "结算退回产品包"),
    PACK_RECEIVE_OPT(OrderOperateConstant.PACK_RECEIVE_OPT, "接受退回产品包"),
    SALE_BILL_CREATE_OPT(OrderOperateConstant.SALE_BILL_CREATE_OPT, "结算单创建"),
    SALE_BILL_UPDATE_OPT(OrderOperateConstant.SALE_BILL_UPDATE_OPT, "结算单修改"),
    SALE_BILL_DELETE_OPT(OrderOperateConstant.SALE_BILL_DELETE_OPT, "结算单删除"),
    SALE_BILL_CONFIRM_OPT(OrderOperateConstant.SALE_BILL_CONFIRM_OPT, "结算单审核"),
    SALE_BILL_INFIRM_OPT(OrderOperateConstant.SALE_BILL_INFIRM_OPT, "结算单反审"),
    SALE_BILL_DISCARD_OPT(OrderOperateConstant.SALE_BILL_DISCARD_OPT, "结算单作废"),
    SALE_BILL_DELIVERY_APPLY_OPT(OrderOperateConstant.SALE_BILL_DELIVERY_APPLY_OPT, "结算单发货申请"),
    SALE_BILL_DELIVERY_CONFIRM_OPT(OrderOperateConstant.SALE_BILL_DELIVERY_CONFIRM_OPT, "结算单发货审批"),
    SALE_BILL_UPLOAD_OPT(OrderOperateConstant.SALE_BILL_UPLOAD_OPT, "结算单上传签字图片"),
    SALE_BILL_DELIVERED_OPT(OrderOperateConstant.SALE_BILL_DELIVERED_OPT, "结算单已发货"),

    MARKING_BILL_CREATE_OPT(OrderOperateConstant.MARKING_BILL_CREATE_OPT, "字印单创建"),
    MARKING_BILL_UPDATE_OPT(OrderOperateConstant.MARKING_BILL_UPDATE_OPT, "字印单修改"),
    MARKING_BILL_DELETE_OPT(OrderOperateConstant.MARKING_BILL_DELETE_OPT, "字印单删除"),
    MARKING_BILL_CONFIRM_OPT(OrderOperateConstant.MARKING_BILL_CONFIRM_OPT, "字印单审核"),
    MARKING_BILL_INFIRM_OPT(OrderOperateConstant.MARKING_BILL_INFIRM_OPT, "字印单反审"),
    MARKING_BILL_DISCARD_OPT(OrderOperateConstant.MARKING_BILL_DISCARD_OPT, "字印单作废"),
    MARKING_BILL_MARKING_OPT(OrderOperateConstant.MARKING_BILL_MARKING_OPT, "字印单字印中"),
    MARKING_BILL_FINISH_OPT(OrderOperateConstant.MARKING_BILL_FINISH_OPT, "字印单字印完成"),

    SALE_PREPOSSESSING_CREATE_OPT(OrderOperateConstant.SALE_PREPOSSESSING_CREATE_OPT, "结算预处理创建"),
    SALE_PREPOSSESSING_UPDATE_OPT(OrderOperateConstant.SALE_PREPOSSESSING_UPDATE_OPT, "结算预处理修改"),
    SALE_PREPOSSESSING_DELETE_OPT(OrderOperateConstant.SALE_PREPOSSESSING_DELETE_OPT, "结算预处理删除"),
    SALE_PREPOSSESSING_CONFIRM_OPT(OrderOperateConstant.SALE_PREPOSSESSING_CONFIRM_OPT, "结算预处理审核"),
    SALE_PREPOSSESSING_INFIRM_OPT(OrderOperateConstant.SALE_PREPOSSESSING_INFIRM_OPT, "结算预处理反审"),
    SALE_PREPOSSESSING_DISCARD_OPT(OrderOperateConstant.SALE_PREPOSSESSING_DISCARD_OPT, "结算预处理作废"),
    ;

    @Getter
    private final String key;
    private final String text;

    OrderOperateEnum(String key, String text) {
        this.key = key;
        this.text = text;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值