管理系统开发技(10) 使用mq完成打印二维码功能

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

前言

由于前面使用前端页面来进行打印后,效果并不理想,在加载 522 张图片的时候需要 10 秒左右的预览时间。因此,将这打印步骤放入后端完成。再选购打印机后,但该打印机只能连接内网打印,而我们的服务是部署在公网中的,如何让内网的数据消费到公网的数据呢?这时候就需要一个中间件,它帮我们做到这两块内容的消息传送。

本次中间件选用的是 Kafka,它具备超一流的读写性能。在面对大数据量消息传输的时候具备很好的高吞吐率。而我们后续的应用会使用到 kafka ,所以这边我们首先来使用 Kafka 来完成这一功能。而为什么不采用 redis。区别如下:

  • 1、存储方式不同:redis 是存储是内存的,而 Kafka 是存储在硬盘的,redis 的数据可能会丢失,而 Kafka 相对会安全很多,同时,硬盘比内存的成本会小很多。
  • 2、订阅机制不同:Kafka 是专业的消息队列,除了主题之外,不仅可以消费已经消费的数据,还可以进行分区消费和分消费者组。

一、设计概述

1.1 打印时序图

就是两个服务之间的服务调用关系。

613aeff3dfe6d.png

1.2 运维子系统打印业务

打印功能相对比二维码的生成比较简单,只需找到所有的设备,然后将这些设备发送给中间件即可。

分为三种打印情况:

  • 1、单独打印
  • 2、按设备类型批量打印
  • 3、按设备类型组装成目录批量打印

先从数据库中获取动态分区,然后发送给指定的 主题和分区即可。

1
less复制代码kafkaTemplate.send(new ProducerRecord(PRODUCE_TOPIC,devicePrint.getPartition(),null,mapper.writeValueAsString(messageVO)));

然后打印服务只需要对打印失败的 retry 次数 +1 即,接下来就是打印业务的处理了。

image-20211011143243494

二、开发流程

后端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
scss复制代码 @KafkaListener(id = "consumer2", topicPartitions = { @org.springframework.kafka.annotation.TopicPartition(topic = "print_consumer_consumerPrintInfo", partitions = { "0" }) },groupId="subStation")
  public void consumer2(String str) {
      try {
          DeviceKafkaMessageVO messageVO = mapper.readValue(str, DeviceKafkaMessageVO.class);
          // 消费失败次数三次以内继续消费
          if(0==messageVO.getRetry()){
              socketApi.sendMsg(SocketDTO
                      .builder()
                      .password(configComponent.getPassword())
                      .topic(ElectricityStationConst.DEVICE_BATCH_PRINT + messageVO.getSysId())
                      .data(messageVO)
                      .build()
              );
              DeviceInfo deviceInfo = new DeviceInfo();
              deviceInfo.setId(messageVO.getId()).setIsPrint(0);
              redisSdk.lLeftAdd(configComponent.getPrintListSuccess(),new ObjectMapper().writeValueAsString(deviceInfo));
          }
          else if(messageVO.getRetry()==3){
              socketApi.sendMsg(SocketDTO
                      .builder()
                      .password(configComponent.getPassword())
                      .topic(ElectricityStationConst.DEVICE_BATCH_PRINT + messageVO.getSysId())
                      .data(messageVO)
                      .build()
              );
              DeviceInfo deviceInfo = new DeviceInfo();
              deviceInfo.setId(messageVO.getId()).setIsPrint(1);
              redisSdk.lLeftAdd(configComponent.getPrintListError(),new ObjectMapper().writeValueAsString(deviceInfo));
              System.out.println("值"+redisSdk.lLen(configComponent.getPrintListError()));
          }
          else{
              kafkaTemplate.send(new ProducerRecord(DeviceServiceImpl.PRODUCE_TOPIC,0,null,mapper.writeValueAsString(messageVO)));
          }
          if(redisSdk.lLen(configComponent.getPrintListError())+redisSdk.lLen(configComponent.getPrintListSuccess())>=messageVO.getTotal()){
              int sus = (int) redisSdk.lLen(configComponent.getPrintListSuccess());
              int errs = (int) redisSdk.lLen(configComponent.getPrintListError());
              // 插入消息通知
              if(errs>0){
                  MessageAccept messageAccept = new MessageAccept();
                  messageAccept.setContent("部分设备打印失败!总执行数:"+(sus+errs)+",失败数:"+(errs));
                  messageAccept.setTitle(SmConst.SM_MESAGE_TYPE_CONST_200.getName());
                  messageAccept.setSysId(41040020001L);
                  messageAccept.setType(SmConst.SM_MESAGE_TYPE_CONST_200.getStatus());
                  messageAccept.setCreateTime(new DateTime());
                  messageAccept.setUpdateTime(new DateTime());
                  messageAccept.setDeleteFlag(0);
                  messageAcceptMapper.insert(messageAccept);
              }
              // 批量更新状态
              while(redisSdk.lLen(configComponent.getPrintListSuccess())>0){
                  ObjectMapper objectMapper = new ObjectMapper();
                  ArrayList<DeviceInfo> successList = new ArrayList<>();
                  List<String> list = redisSdk.pLRightPop(configComponent.getPrintListSuccess(),5000);
                  for (String string : list) {
                      if(StrUtil.isNotEmpty(string)) {
                          DeviceInfo deviceInfo = objectMapper.readValue(string, DeviceInfo.class);
                          successList.add(deviceInfo);
                      }
                  }
                  List<Long> collect = successList.stream().map(e -> e.getId()).collect(Collectors.toList());
                  deviceInfoMapper.updateBatchIsPrintSuccess(collect);
              }
              while(redisSdk.lLen(configComponent.getPrintListError())>0){
                  ObjectMapper objectMapper = new ObjectMapper();
                  ArrayList<DeviceInfo> failList = new ArrayList<>();
                  List<String> list = redisSdk.pLRightPop(configComponent.getPrintListError(),5000);
                  for (String string : list) {
                      if(StrUtil.isNotEmpty(string)) {
                          DeviceInfo deviceInfo = objectMapper.readValue(string, DeviceInfo.class);
                          failList.add(deviceInfo);
                      }
                  }
                  List<Long> collect = failList.stream().map(e -> e.getId()).collect(Collectors.toList());
                  deviceInfoMapper.updateBatchIsPrintFail(collect);
              }
          }
      } catch (Exception e) {
          log.error("消费失败");
          e.printStackTrace();
      }
  }

前端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ini复制代码 //批量打印
  printBatch(row){
    this.$data.printshow=true;
    this.$data.printDialog=true;
    StoreService.setPrintNumber();
    let _this=this;
    console.log(row)
    this.$api.req("/am/device/img/menu/printBatch", {id:row.id},res =>{
      this.$data.loading = false;
    },res=>{
      this.$data.printDialog=false;
      this.$data.printshow=false;
      _this.$data.loading = false;
      _this.$message.error(res.msg);
    })
  },
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
ini复制代码printstomp(){
    var _this=this
    // 监听批量打印
    _this.$bus.$on(TopicConst.DEVICE_BATCH_PRINT+StoreService.getStationId(),data =>{
      var a = JSON.parse(data)
      // 将计数器 +1
      StoreService.incryPrintNumber()
      if(a.retry == 3){
        StoreService.incryPrintErrNumber()
      }
      _this.$data.printshow=true
      _this.$data.printDialog=true
      _this.$data.printvalue=parseInt(Math.round(StoreService.getPrintNumber()/a.total*100))
      if(a.total == StoreService.getPrintNumber()){
        if(StoreService.getPrintErrNumber()>0){
          this.$message.error("打印总数:"+StoreService.getPrintNumber()+",失败个数:"+StoreService.getPrintErrNumber())
          Utils.$emit('dot',true)
        }else {
          this.$message.success("打印完成!")
        }
        setTimeout(function(){
          _this.$data.printshow=false
          _this.$data.printDialog=false
          _this.$data.printvalue=0
        }, 1000);
        StoreService.setPrintNumber(0)
      }
    })
  },

最后,上成品。

693b9ed70312306750f7cc04895d5bb.jpg

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%