码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 切面Aspect + 策略模式实现待办提醒功能


    1.背景

    产品需要实现一个待办提醒功能,就是核心业务发生变更即提醒业务员去处理相关业务。譬如:订单上传了支付凭证,那么就会提醒相关业务员去待办列表操办。

    2.表设计

    其实表设计主要是两张表sys_todo、sys_todo_detail

    一张是待办核心表,主要是记录待办类型,待办业务id等。

    1. CREATE TABLE `sys_todo` (
    2. `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
    3. `model` int NOT NULL DEFAULT '0' COMMENT '归属模块: 0-crm 1-srm',
    4. `type` int NOT NULL DEFAULT '0' COMMENT '待办类型',
    5. `biz_id` bigint NOT NULL DEFAULT '0' COMMENT '业务id',
    6. PRIMARY KEY (`id`)
    7. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='待办统计表';

    另一张是待办详情表,主要是记录这个待办能做哪些操作。

    1. CREATE TABLE `sys_todo_detail` (
    2. `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
    3. `todo_id` bigint NOT NULL DEFAULT '0' COMMENT 'sys_todo表id',
    4. `title` varchar(50) NOT NULL DEFAULT '' COMMENT '标题',
    5. `url` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '地址',
    6. `is_pop` int NOT NULL DEFAULT '0' COMMENT '是否弹窗 0-否 1-是',
    7. `content` varchar(3000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '内容',
    8. `sort_num` int NOT NULL DEFAULT '0' COMMENT '排序',
    9. PRIMARY KEY (`id`),
    10. KEY `idx_todo_id` (`todo_id`) USING BTREE
    11. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='待办统计详情表';

    举例:sys_todo 有个待办类型是【上传支付凭证】,id=1,sys_todo_detail 待办详情表,就有todo_id 为1的内容,譬如【查看】、【审核】操作的两条记录。

    当然,这些表具体实现得根据具体业务设计来实现。

    3.如何实现

    3.1 业务埋点

    业务埋点,也就是在每一个相关业务代码里面,加上待办的埋点,让相关待办业务内容插入待办表。譬如:【上传支付凭证】,就得在上传支付凭证的代码最后上传成功的地方,写上上传待办的业务代码。

    3.2 切面Aspect + 策略模式

    3.2.1 先定义好切面

    这里我在项目里面,定义好切面类。

    1. @Component
    2. @Aspect
    3. public class SrmTodoAspect {
    4. //这里拦截mybatis-plus底层方法
    5. @Pointcut("(execution(* com.baomidou.mybatisplus.extension.service.IService.update*(..))" +
    6. "||execution(* com.baomidou.mybatisplus.extension.service.IService.save*(..))" +
    7. "||execution(* com.baomidou.mybatisplus.core.mapper.BaseMapper.update*(..))" +
    8. "||execution(* com.baomidou.mybatisplus.core.mapper.BaseMapper.insert(..)))" )
    9. public void todo(){};
    10. //策略A
    11. @Resource
    12. private ATodoStrategy aTodoStrategy;
    13. //策略B
    14. @Resource
    15. private BTodoStrategy bTodoStrategy;
    16. //线程池
    17. @Resource
    18. private TaskExecutor taskExecutor;
    19. @Around("todo()")
    20. public Object around(ProceedingJoinPoint point) throws Throwable {
    21. Object[] args = point.getArgs();
    22. Object obj = point.proceed();
    23. Object arg = args[0];
    24. List paramList = null;
    25. if(Objects.isNull(arg)){
    26. return obj;
    27. }
    28. if(arg instanceof ArrayList){
    29. paramList = (List)arg;
    30. }else {
    31. paramList = Arrays.asList(args);
    32. }
    33. if (CollectionUtil.isEmpty(paramList)){
    34. return obj;
    35. }
    36. /*
    37. * 这里用到捕获异常很关键,不能因待办出现异常而影响主流程,
    38. * 用线程池避免待办处理过慢影响主流程性能
    39. */
    40. taskExecutor.execute(()->{
    41. try{
    42. Thread.sleep(1000L);
    43. dealTodoStrategy(paramList);
    44. }catch (Exception e){
    45. }
    46. });
    47. return obj;
    48. }
    49. /*
    50. * TodoContext 是策略模式的上下文
    51. * aTodoStrategy、bTodoStrategy 是具体的策略
    52. */
    53. private void dealTodoStrategy(List paramList) {
    54. TodoContext context = null;
    55. Object param = paramList.get(0);
    56. if(param instanceof A){
    57. context = new TodoContext(aTodoStrategy);
    58. }else if(param instanceof B) {
    59. context = new TodoContext(bTodoStrategy);
    60. }
    61. if(context != null){
    62. context.executeStrategy(paramList);
    63. }
    64. }
    65. }
    66. 特别说一句:这里其实最初的设计并不是用切面,而是用mybatis拦截器 Interceptor 去实现获取到insert或update后的实体的,但是拦截mybatis-plus的saveBatch方法能拿到List实体,但是没有id。因此不能很好处理待办业务。原因:大家可以去看下CSDN。

      3.2.2 定义策略模式

      策略接口(TodoStrategy) 

      1. public interface TodoStrategy {
      2. void dealTodo(List list);
      3. }

      Context类

      1. public class TodoContext {
      2. private TodoStrategy strategy;
      3. public TodoContext(TodoStrategy strategy){
      4. this.strategy = strategy;
      5. }
      6. public void executeStrategy(List list){
      7. strategy.dealTodo(list);
      8. }
      9. }

      策略实现类 (ATodoStrategy )

      1. @Service
      2. public class ATodoStrategy implements TodoStrategy {
      3. @Override
      4. public void dealTodo(List list) {
      5. if(CollectionUtil.isEmpty(list)){
      6. return;
      7. }
      8. TodoForm todoForm = null;
      9. List enquiryList = (List)list;
      10. List enquiryIdList =
      11. enquiryList.stream().map(Enquiry::getId).collect(Collectors.toList());
      12. //根据id找到数据库实体类
      13. enquiryList = enquiryService.findList(new EnquiryQuery().setIdList(enquiryIdList));
      14. //遍历实体类,然后根据不同的实体状态去实现待办规则新增或消除功能
      15. for(Enquiry enquiry : enquiryList){
      16. Long id = enquiry.getId();
      17. //新增去报价待办
      18. if(EnquiryStatusEnum.WAIT_QUOTE.getKey().equals(enquiry.getStatus())){
      19. }
      20. //消除去报价待办
      21. if(EnquiryStatusEnum.HAD_QUOTE.getKey().equals(enquiry.getStatus())){
      22. }
      23. }
      24. }
      25. }

      4.总结

      待办实现方式两种:①埋点 ②切面Aspect + 策略模式

      个人比较推荐② ,因为这个代码设计好处如下:

      1.不需要“过分”埋点。埋点的话,容易漏埋点。譬如新增代码业务代码在插入操作后埋点了,但是突然另一个业务也有插入操作,但是忘记埋点,那么待办就容易遗漏。

      2.代码集中维护,模块分层清晰。也就是待办新增或消除逻辑,统一写在策略模式里面了,只需要去策略模式里面维护即可。这样也能减少在业务代码过多埋点造成代码臃肿。

    67. 相关阅读:
      【CentOS7】基于python2,3安装docker-compose
      Django事务确保数据一致性
      windows域的搭建
      MySQL 表设计的经验准则
      分布式光伏发电系统的组网与研究
      [JAVAee]spring-Bean对象的执行流程与生命周期
      ​辉瑞校园《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著作——2023学生开学季辉少许
      POJ1008:玛雅日历
      配置OSPF包文分析和验证
      第75步 时间序列建模实战:多步滚动预测 vol-3(以决策树回归为例)
    68. 原文地址:https://blog.csdn.net/taipoucha5799/article/details/134494906
      • 最新文章
      • 攻防演习之三天拿下官网站群
        数据安全治理学习——前期安全规划和安全管理体系建设
        企业安全 | 企业内一次钓鱼演练准备过程
        内网渗透测试 | Kerberos协议及其部分攻击手法
        0day的产生 | 不懂代码的"代码审计"
        安装scrcpy-client模块av模块异常,环境问题解决方案
        leetcode hot100【LeetCode 279. 完全平方数】java实现
        OpenWrt下安装Mosquitto
        AnatoMask论文汇总
        【AI日记】24.11.01 LangChain、openai api和github copilot
      • 热门文章
      • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
        奉劝各位学弟学妹们,该打造你的技术影响力了!
        五年了,我在 CSDN 的两个一百万。
        Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
        面试官都震惊,你这网络基础可以啊!
        你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
        心情不好的时候,用 Python 画棵樱花树送给自己吧
        通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
        13 万字 C 语言从入门到精通保姆级教程2021 年版
        10行代码集2000张美女图,Python爬虫120例,再上征途
      Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
      正则表达式工具 cron表达式工具 密码生成工具

      京公网安备 11010502049817号