创建延时队列、springboot配置多个rabbitmq

创建延时队列

queue.file_delay_destroy
x-dead-letter-exchange:	exchange.file_delay_destroy
x-message-ttl:	259200000
259200000为3天,1000为1秒

在这里插入图片描述

创建普通队列

queue.file_destroy

创建普通交换机

exchange.file_delay_destroy

type选择fanout
在这里插入图片描述

交换机绑定普通队列

(图中已经绑定,红框为绑定过程)
在这里插入图片描述

普通队列绑定交换机

(图中已经绑定,红框为绑定过程)
在这里插入图片描述

延时队列

springboot配置多个rabbitmq

延时队列时间到之后,将消息发送给queue.file_destroy,执行删除文件操作

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@EqualsAndHashCode
@Data
public class MQMessage implements Serializable {
  private JSONObject msg;
  private String messageId;   //存储消息发送的唯一标识
}
import com.sxqx.entity.MQMessage;

public interface MQMessageSender {
  /**
   *
   * @param queue 消息队列名称
   * @param msg 消息
   */
  void send(String queue, MQMessage msg);
}

RabbitConfig配置类

import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
public class RabbitConfig {

  @Primary
  @Bean(name="mq1ConnectionFactory")
  public ConnectionFactory mq1ConnectionFactory(
          @Value("${spring.rabbitmq.mq1.host}") String host,
          @Value("${spring.rabbitmq.mq1.port}") int port,
          @Value("${spring.rabbitmq.mq1.username}") String username,
          @Value("${spring.rabbitmq.mq1.password}") String password,
          @Value("${spring.rabbitmq.mq1.virtual-host}") String virtualHost
  ){
    CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
    connectionFactory.setHost(host);
    connectionFactory.setPort(port);
    connectionFactory.setUsername(username);
    connectionFactory.setPassword(password);
    connectionFactory.setVirtualHost(virtualHost);
    connectionFactory.setPublisherConfirms(true);
    connectionFactory.setPublisherReturns(true);
    return connectionFactory;
  }

  @Bean(name="mq2ConnectionFactory")
  public ConnectionFactory mq2ConnectionFactory(
          @Value("${spring.rabbitmq.mq2.host}") String host,
          @Value("${spring.rabbitmq.mq2.port}") int port,
          @Value("${spring.rabbitmq.mq2.username}") String username,
          @Value("${spring.rabbitmq.mq2.password}") String password,
          @Value("${spring.rabbitmq.mq2.virtual-host}") String virtualHost
  ){
    CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
    connectionFactory.setHost(host);
    connectionFactory.setPort(port);
    connectionFactory.setUsername(username);
    connectionFactory.setPassword(password);
    connectionFactory.setVirtualHost(virtualHost);
    connectionFactory.setPublisherConfirms(true);
    connectionFactory.setPublisherReturns(true);
    return connectionFactory;
  }

  @Primary
  @Bean(name="mq1RabbitTemplate")
  public RabbitTemplate mq1RabbitTemplate(
          @Qualifier("mq1ConnectionFactory") ConnectionFactory connectionFactory
  ){
    RabbitTemplate mq1RabbitTemplate = new RabbitTemplate(connectionFactory);
    mq1RabbitTemplate.setMessageConverter(jsonMessageConverter());
    return mq1RabbitTemplate;
  }

  @Bean(name="mq2RabbitTemplate")
  public RabbitTemplate mq2RabbitTemplate(
          @Qualifier("mq2ConnectionFactory") ConnectionFactory connectionFactory
  ){
    RabbitTemplate mq2RabbitTemplate = new RabbitTemplate(connectionFactory);
    mq2RabbitTemplate.setMessageConverter(jsonMessageConverter());
    return mq2RabbitTemplate;
  }

  @Bean
  public Jackson2JsonMessageConverter jsonMessageConverter() {
    return new Jackson2JsonMessageConverter();
  }


  @Bean(name = "mq1Factory")
  @Primary
  public SimpleRabbitListenerContainerFactory mq1Factory(
          SimpleRabbitListenerContainerFactoryConfigurer configurer,
          @Qualifier("mq1ConnectionFactory") ConnectionFactory connectionFactory
  ) {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    configurer.configure(factory, connectionFactory);
    return factory;
  }

  @Bean(name = "mq2Factory")
  public SimpleRabbitListenerContainerFactory mq2Factory(
          SimpleRabbitListenerContainerFactoryConfigurer configurer,
          @Qualifier("mq2ConnectionFactory") ConnectionFactory connectionFactory
  ) {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    configurer.configure(factory, connectionFactory);
    return factory;
  }
}

mq1

@Component
public class RabbitMQ1MessageSender  implements MQMessageSender, RabbitTemplate.ConfirmCallback{
  @Resource(name = "mq1RabbitTemplate")
  private RabbitTemplate mq1RabbitTemplate;
  Log log = LogFactory.getLog(RabbitMQ1MessageSender.class);
  @Autowired
  public RabbitMQ1MessageSender() {
  }

  @PostConstruct
  public void init(){
    mq1RabbitTemplate.setConfirmCallback(this);
  }

  @Override
  public void confirm(CorrelationData correlationData, boolean ack, String cause) {
    if(!ack){
      log.error("消息接收失败" + cause);
      // 我们这里要做一些消息补发的措施
      System.out.println("id="+correlationData.getId());
    }
  }

  @Override
  public void send(String routingKey, MQMessage msg) {
    String jsonString = JsonConverter.bean2Json(msg);
    if (jsonString != null) {
      mq1RabbitTemplate.convertAndSend(routingKey, jsonString);
    }
  }
}

mq2

import com.sxqx.entity.MQMessage;
import com.sxqx.utils.dataConverter.JsonConverter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

@Component
public class RabbitMQ2MessageSender implements MQMessageSender, RabbitTemplate.ConfirmCallback{
  @Resource(name = "mq2RabbitTemplate")
  private RabbitTemplate mq2RabbitTemplate;
  Log log = LogFactory.getLog(RabbitMQ2MessageSender.class);
  @Autowired
  public RabbitMQ2MessageSender() {
  }
  
  @PostConstruct
  public void init(){
    mq2RabbitTemplate.setConfirmCallback(this);
  }

  @Override
  public void confirm(CorrelationData correlationData, boolean ack, String cause) {
    if(!ack){
      log.error("消息接收失败" + cause);
      // 我们这里要做一些消息补发的措施
      System.out.println("id="+correlationData.getId());
    }
  }

  @Override
  public void send(String routingKey, MQMessage msg) {
    String jsonString = JsonConverter.bean2Json(msg);
    if (jsonString != null) {
      mq2RabbitTemplate.convertAndSend(routingKey, jsonString);
    }
  }
}

application-prod.yaml

spring:
  rabbitmq:
    mq1:
      username: guest
      password: guest
      host: mq1_ip
      port: 5672
      virtual-host: /
      publisher-returns: true
      publisher-confirm-type: simple
      listener:
        simple:
          acknowledge-mode: auto # 手动应答
          prefetch: 10 #每次从队列中取一个,轮询分发,默认是公平分发
          retry:
            max-attempts: 5 # 重试次数
            enabled: true # 开启重试
          concurrency: 5
          max-concurrency: 10
    mq2:
      username: guest
      password: guest
      host: mq2_ip
      port: 5672
      virtual-host: /
      publisher-returns: true
      publisher-confirm-type: simple
      listener:
        simple:
          acknowledge-mode: auto # 手动应答
          prefetch: 10 #每次从队列中取一个,轮询分发,默认是公平分发
          retry:
            max-attempts: 5 # 重试次数
            enabled: true # 开启重试
          concurrency: 5
          max-concurrency: 10

mq1消费端,发消息给mq2

@Component
public class SyncWeatherLivePicMessageReceiver  implements IMessageReceiver {
    private final IWeatherLivePicMapper weatherLivePicMapper;
    private final RabbitMQ2MessageSender rabbitMQ2MessageSender;

    @Autowired
    public SyncWeatherLivePicMessageReceiver(IWeatherLivePicMapper weatherLivePicMapper,
                                             RabbitMQ2MessageSender rabbitMQ2MessageSender) {
        this.weatherLivePicMapper = weatherLivePicMapper;
        this.rabbitMQ2MessageSender = rabbitMQ2MessageSender;
    }

    Log log = LogFactory.getLog(SyncWeatherLivePicMessageReceiver.class);
    private FtpHelper ftpHelperIns1;
    private FtpHelper ftpHelperIns2;
    private FTPFileFilter ftpFileFilter;
    @RabbitListener(queuesToDeclare = {
            @Queue(name = "sxqxgzbgxw_weather_live_pic")
    })
    @RabbitHandler
    @Override
    public void onMessageReceived(String mqMessageString) {
        JsonNode jsonNode = JsonConverter.jsonString2JsonNode(mqMessageString);
        JsonNode msg = jsonNode.findValue("msg");
        JsonNode JsonNodeParams = msg.findValue("params");
        Map<String, Object> params = JsonConverter.jsonNode2HashMap(JsonNodeParams);
        if (params.size() > 0) {
            String times = params.get("times").toString();
            String serverFrom = params.get("serverFrom").toString();
			......
            
			// 清除数据
			MQMessage mqMessage = new MQMessage();
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("filePath", "/data/static/dataSharingStatic/weatherlive/colorFigure/png/610000/610000/"+ times);
			mqMessage.setMsg(jsonObject);
			rabbitMQ2MessageSender.send("queue.file_delay_destroy", mqMessage);

			// 清除DB记录
			MQMessage mqMessage2 = new MQMessage();
			JSONObject jsonObject2 = new JSONObject();
			jsonObject2.put("tableName", "WEATHER_LIVE_PIC");
			jsonObject2.put("picUrl", "http://外网ip/dataSharingStatic/weatherlive/colorFigure/png/610000/610000/"+ times +"/"+ type + "/" + "gjzjqyz/"+ fileNameFrom);
			mqMessage2.setMsg(jsonObject);
			rabbitMQ2MessageSender.send("queue.db_delay_destroy", mqMessage2);                
        }
    }
}

mq2消费端用于递归删除文件

import com.fasterxml.jackson.databind.JsonNode;
import com.sxqx.listener.IMessageReceiver;
import com.sxqx.utils.dataConverter.JsonConverter;
import com.sxqx.utils.file.FileHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.File;

@Component
public class FileDestroyMessageReceiver implements IMessageReceiver {
  Log log = LogFactory.getLog(FileDestroyMessageReceiver.class);
  @RabbitListener(queuesToDeclare = {
      @Queue(name = "queue.file_destroy")
  })
  @RabbitHandler
  @Override
  public void onMessageReceived(String mqMessageString) {
    JsonNode jsonNode = JsonConverter.jsonString2JsonNode(mqMessageString);
    JsonNode msg = jsonNode.findValue("msg");
    String filePath = msg.findValue("filePath").asText();

    if (filePath.contains("/data/static/dataSharingStatic/weatherlive/colorFigure/png/610000/610000")) {
      File file = new File(filePath);
      if (file.exists()) {
        FileHelper.deleteFile(file);
      }
    } else {
      log.info("有人想删除设定之外的文件");
      log.info(filePath);
    }
  }
}

FileHelper工具类递归删除文件或文件夹

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class FileHelper {
    /**
     * 递归删除文件或文件夹
     * @param directory
     */
    public static void deleteFile(File directory) {
        if (!directory.exists()) {
            return;
        }

        File[] files = directory.listFiles();
        if (files!=null) {//如果包含文件进行删除操作
            for (File value : files) {
                if (value.isFile()) {
                    //删除子文件
                    value.delete();
                } else if (value.isDirectory()) {
                    //通过递归的方法找到子目录的文件
                    deleteFile(value);
                }
                value.delete();//删除子目录
            }
        }
        directory.delete();
    }
}

mq2消费端用于删除数据库数据

import com.fasterxml.jackson.databind.JsonNode;
import com.sxqx.listener.IMessageReceiver;
import com.sxqx.mapper.remote.xugugzb.weatherlivepic.IWeatherLivePicMapper;
import com.sxqx.utils.dataConverter.JsonConverter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Objects;

@Component
public class DBDestroyMessageReceiver implements IMessageReceiver {
  private final IWeatherLivePicMapper weatherLivePicMapper;
  @Autowired
  public DBDestroyMessageReceiver(IWeatherLivePicMapper weatherLivePicMapper){
    this.weatherLivePicMapper = weatherLivePicMapper;
  }
  Log log = LogFactory.getLog(DBDestroyMessageReceiver.class);
  @RabbitListener(queuesToDeclare = {
      @Queue(name = "queue.db_destroy")
  })
  @RabbitHandler
  @Override
  public void onMessageReceived(String mqMessageString) {
    JsonNode jsonNode = JsonConverter.jsonString2JsonNode(mqMessageString);
    JsonNode msg = jsonNode.findValue("msg");
    String tableName = msg.findValue("tableName").asText();
    String picUrl = msg.findValue("picUrl").asText();

    if (picUrl.contains("/dataSharingStatic/weatherlive/colorFigure/png/610000/610000/")) {
      if (Objects.equals("WEATHER_LIVE_PIC",tableName)) {
        weatherLivePicMapper.deleteWeatherLivePic(picUrl);
      }
    } else {
      log.info("有人想删除设定之外的数据");
      log.info(picUrl);
    }
  }
}

nginx.conf

上传静态资源至linux path,配置nginx.conf,使浏览器可以直接访问静态资源

server {
	listen       80;
	server_name  60.204.202.112;
	add_header   Cache-Control no-store;
	charset	     utf-8;

	location / {
		root   /mnt/sxqxgxw-gzb-front/dist/;
	try_files $uri $uri/ /index.html;
		index  index.html index.htm;
	}
	#访问/dataSharingStatic时,相当于访问/data/static/dataSharingStatic路径下资源
	location /dataSharingStatic {
		root   /data/static;
		autoindex   on;
		add_header  Access-Control-Allow-Origin *;
		add_header  Access-Control-Allow-Headers X-Requestd-With;
		add_header  Access-Control-Allow-Methods GET,POST,OPTIONS;
	}
	
	error_page   500 502 503 504  /50x.html;
	location = /50x.html {
		root   html;
	}
	
	location /api/ {
		proxy_pass    http://60.204.202.112:8896;
		rewrite	  ^/api/(.*)$ /$1 break;
		add_header    Access-Control-Allow-Origin *;
		add_header    Access-Control-Allow-Headers X-Requestd-With;
		add_header	  Access-Control-Allow-Methods GET,POST,OPTIONS;
	}
   
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/85803.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络安全---Ring3下动态链接库.so函数劫持

一、动态链接库劫持原理 1.1、原理 Unix操作系统中&#xff0c;程序运行时会按照一定的规则顺序去查找依赖的动态链接库&#xff0c;当查找到指定的so文件时&#xff0c;动态链接器(/lib/ld-linux.so.X)会将程序所依赖的共享对象进行装载和初始化&#xff0c;而为什么可以使用…

web基础+HTTP协议+httpd详细配置

目目录录 一、Web基础1.1 HTML概述1.1.1 HTML的文件结构1.1.2 HTML中的部分基本标签 1.3 MIME1.4 URI 和 URL1.4 定义1.4.2 URI 和 URL 的区别 二、静态资源和动态资源2.1 静态资源2.2 动态资源 三、HTTP协议3.1 HTTP协议简介3.2 HTTP协议版本3.2 HTTP方法3.3 HTTP请求访问的完…

环二肽16364-35-5,cyclo(Glu-Gly),环(甘氨酰-谷氨酸),产品特点介绍

中文名&#xff1a;环&#xff08;甘氨酰-谷氨酸&#xff09; 英文名&#xff1a;cyclo(Glu-Gly) CYCLO(-GLY-GLU) CAS&#xff1a;16364-35-5 分子式&#xff1a;C7H10N2O4 分子量&#xff1a;186.165 沸点&#xff1a; 666.840.0 C(Predicted) 表面张力&#xff08;dy…

一键解决ssh登录密码问题:sshpass的安装与使用

引言 大家好&#xff0c;我是运维家的Linux和Python技术持续学习者。在日常的运维工作中&#xff0c;我们经常需要远程登录服务器进行管理和操作。而对于那些不支持密钥登录或者需要输入密码的服务器&#xff0c;你是否曾经遇到过繁琐的手动输入密码的问题呢&#xff1f;别担心…

芯片验证板卡设计原理图:446-基于VU440T的多核处理器多输入芯片验证板卡

基于VU440T的多核处理器多输入芯片验证板卡 一、板卡概述 基于XCVU440-FLGA2892的多核处理器多输入芯片验证板卡为实现网络交换芯片的验证&#xff0c;包括四个FMC接口、DDR、GPIO等&#xff0c;北京太速科技芯片验证板卡用于完成甲方的芯片验证任务&#xff0c;多任务…

计组 | 寻址方式

目录 一、知识点 1.寻址方式什么&#xff1f; 2.根据操作数所在的位置&#xff0c;都有哪些寻址方式&#xff1f; 3.直接寻址 4.立即寻址 5.隐含寻址 6.相对寻址 7.寄存器 8.寄存器-寄存器型&#xff08;RR&#xff09;、寄存器-存储器型&#xff08;RS&#xff09;和…

华为AR路由器 典型配置案例——以太网交换

目录 Eth-Trunk 例&#xff1a;配置三层链路聚合 组网需求 操作步骤 检查配置结果 配置脚本 VLAN 举例&#xff1a;配置基于接口划分VLAN&#xff0c;实现同一VLAN内的互通&#xff08;同设备&#xff09; 组网需求 操作步骤 检查配置结果 配置脚本 举例&#xff…

YOLOv8教程系列:三、K折交叉验证——让你的每一份标注数据都物尽其用(yolov8目标检测+k折交叉验证法)

YOLOv8教程系列&#xff1a;三、K折交叉验证——让你的每一份标注数据都物尽其用&#xff08;yolov8目标检测k折交叉验证法&#xff09; 0.引言 k折交叉验证&#xff08;K-Fold Cross-Validation&#xff09;是一种在机器学习中常用的模型评估技术&#xff0c;用于估计模型的性…

elaticsearch(1)

1.简介 Elasticsearch是一个开源的高扩展的分布式全文检索引擎&#xff0c;它可以近乎实时的存储、检索数据&#xff1b;本身扩展性很好&#xff0c;可以扩展到上百台服务器&#xff0c;处理PB级别的数据。 Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引…

Electron之初体验

Electron是一款使用Html、Css、JS开发跨平台桌面应用的框架。 话不多说直接开搞。 必坑指南&#xff1a; node版本>18.0使用淘宝镜像安装npm相关包&#xff1b;把下面两行配置放到你的npmrc文件中electron_mirrorhttps://npm.taobao.org/mirrors/electron/ ELECTRON_MIRRO…

手写 Mybatis-plus 基础架构(工厂模式+ Jdk 动态代理统一生成代理 Mapper)

这里写目录标题 前言温馨提示手把手带你解析 MapperScan 源码手把手带你解析 MapperScan 源码细节剖析工厂模式Jdk 代理手撕脚手架&#xff0c;复刻 BeanDefinitionRegistryPostProcessor手撕 FactoryBean代理 Mapper 在 Spring 源码中的生成流程手撕 MapperProxyFactory手撕增…

浅析Linux SCSI子系统:调试方法

文章目录 SCSI日志调试功能scsi_logging_level调整SCSI日志等级 SCSI trace events使能SCSI trace events方式一&#xff1a;通过set_event接口方式二&#xff1a;通过enable 跟踪trace信息 相关参考 SCSI日志调试功能 SCSI子系统支持内核选项CONFIG_SCSI_LOGGING配置日志调试…

C++day2(笔记整理)

一、Xmind整理&#xff1a; 二、上课笔记整理&#xff1a; 1.左值引用 #include <iostream> using namespace std;int main() {int a 100;int &ra a; //定义了变量a的引用racout << &a << endl;cout << "&ra" << &…

wx原生微信小程序入门常用总结

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、定义值和修改值1、定义值2、修改值&#xff08;1&#xff09;代码&#xff08;2&#xff09;代码说明&#xff08;3&#xff09;注意点 二、点击事件三、微…

机器人TF坐标系变换与一些可视化工具的应用

TF坐标在ROS中是一个非常重要的概念&#xff0c;因为机器人在做日常操作任务的时候&#xff0c;对于其所在位置和朝向是需要时刻知道的&#xff0c;而机器人是由很多节点组成的协同任务&#xff0c;对于每个部件&#xff0c;我们需要知道它的位姿(位置和朝向)&#xff0c;这使得…

React+Typescript使用接口泛型处理props

好 刚讲完组件 那么 这次 我们来看一下 数据传递的 props 还是上文的案例 例如 我们想将 title 传给Hello组件 之前我们可以直接这样 以一个标签属性的形式传过去 而我们在子组件中 这样去使用 但现在 我们从编辑器中都可以看出 这种写法已经不行了 然后 我们将 hello 组件…

Windows 11 + Ubuntu20.04 双系统 坑里爬起来

ThinkPad x390 安装双系统&#xff0c;原有的磁盘太小&#xff0c;扩充了磁盘重新装系统&#xff0c;出现的问题&#xff0c;加以记录。 1. windows和ubuntu谁先安装&#xff0c;两个都可以&#xff0c;一般建议先安装windows&#xff0c;后安装ubuntu 2. 安装windows后&…

c++--动态规划回文串问题

1.回文子串 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给定一个字符串 s &#xff0c;请计算这个字符串中有多少个回文子字符串。 具有不同开始位置或结束位置的子串&#xff0c;即使是由相同的字符组成&#xff0c;也会被视作不同的子串。 示…

无涯教程-Perl - time函数

描述 此函数返回自纪元以来的秒数(对于大多数系统,是1970年1月1日UTC,00:00:00&#xff1b;对于Mac OS,是1904年1月1日,00:00:00)。适用于gmtime和本地时间。 语法 以下是此函数的简单语法- time返回值 此函数返回自纪元后数秒的整数。 例 以下是显示其基本用法的示例代…

如何实现24/7客户服务自动化?建设智能客服知识库

客户自助服务是指用户通过企业或者第三方建立的网络平台或者终端&#xff0c;实现相关的自定义处理。实现客户服务自动化&#xff0c;对提高客户满意度、维持客户关系至关重要。客户服务自动化可以帮助企业以更快的速度和更高的效率来满足客户的售后服务要求&#xff0c;以进一…