文章目录
- 总结:技术点 动态代理 + 模版方法模式 + 线程池异步处理/MQ
- 一、目的
- 二、难点:如何实现不同接口不同入参的数据转换?
- 三、代码实现
- 1.定义 切点注解接口
- 2.定义 转换接口和模版方法
- 3.定义 切面类
- 4.定义 转换实现类
- 5.业务方法使用注解
- 6.常量类和枚举
总结:技术点 动态代理 + 模版方法模式 + 线程池异步处理/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;
}
}