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

330 阅读3分钟

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

前言

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

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

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

一、设计概述

1.1 打印时序图

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

613aeff3dfe6d.png

1.2 运维子系统打印业务

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

分为三种打印情况:

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

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

kafkaTemplate.send(new ProducerRecord(PRODUCE_TOPIC,devicePrint.getPartition(),null,mapper.writeValueAsString(messageVO)));

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

image-20211011143243494

二、开发流程

后端

 @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();
        }
    }

前端:

 //批量打印
    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);
      })
    },
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