快速上手RabbitMQ

  1. 安装RabbitMQ
    1. 首先将镜像包上传到虚拟机,使用命令加载镜像
docker load -i mq.tar
    1. 运行MQ容器
docker run \
 -e RABBITMQ_DEFAULT_USER=itcast \
 -e RABBITMQ_DEFAULT_PASS=123321 \
 -v mq-plugins:/plugins \
 --name mq \
 --hostname mq \
 -p 15672:15672 \
 -p 5672:5672 \
 -d \
 rabbitmq:3-management
  1. MQ的基本结构
    1. RabbitMQ的一些角色
      1. publisher:生产者
      2. consumer:消费者
      3. exchange:交换机,负责消息路由
      4. queue:队列,存储消息
      5. virtualHost:虚拟主机,隔离不同租户的exchange,queue,消息的隔离
    1. 快速入门

public class PublisherTest {
    @Test
    public void testSendMessage() throws IOException, TimeoutException {
        // 1.建立连接
        ConnectionFactory factory = new ConnectionFactory();
        // 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
        factory.setHost("192.168.150.101");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("itcast");
        factory.setPassword("123321");
        // 1.2.建立连接
        Connection connection = factory.newConnection();

        // 2.创建通道Channel
        Channel channel = connection.createChannel();

        // 3.创建队列
        String queueName = "simple.queue";
        channel.queueDeclare(queueName, false, false, false, null);

        // 4.发送消息
        String message = "hello, rabbitmq!";
        channel.basicPublish("", queueName, null, message.getBytes());
        System.out.println("发送消息成功:【" + message + "】");

        // 5.关闭通道和连接
        channel.close();
        connection.close();

    }
}
public class ConsumerTest {

    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接
        ConnectionFactory factory = new ConnectionFactory();
        // 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
        factory.setHost("192.168.150.101");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("itcast");
        factory.setPassword("123321");
        // 1.2.建立连接
        Connection connection = factory.newConnection();

        // 2.创建通道Channel
        Channel channel = connection.createChannel();

        // 3.创建队列
        String queueName = "simple.queue";
        channel.queueDeclare(queueName, false, false, false, null);

        // 4.订阅消息
        channel.basicConsume(queueName, true, new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body) throws IOException {
                // 5.处理消息
                String message = new String(body);
                System.out.println("接收到消息:【" + message + "】");
            }
        });
        System.out.println("等待接收消息。。。。");
    }
}
  1. SpringAMQP
    1. 功能
      1. 自动声明队列、交换机及其绑定关系
      2. 基于注解的监听器模式,异步接收消息
      3. 封装了RabbitTemplate工具,用于发送消息
    1. 简化模型 === producer->queue->consumer
      1. BasicQueue
        1. 首先在父工程中引入依赖
<!--AMQP依赖,包含RabbitMQ-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
        1. 配置MQ地址,在publisher服务的application.yml中添加配置
spring:
  rabbitmq:
    host: 192.168.137.138 # 主机名
    port: 5672 # 端口
    virtual-host: / # 虚拟主机
    username: itcast # 用户名
    password: 123321 # 密码
        1. 编写队列
@RabbitListener(queues = "simple.queue")
public void listenSimpleQueueMessage(String msg){
    log.info("接受到的消息:{}",msg);
}
        1. 发送消息
@SpringBootTest
public class SpringAmqpTest {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testSimpleQueue(){
    String queueName = "simple.queue";
    String message = "hello,world";
    rabbitTemplate.convertAndSend(queueName,message);
    }

}
      1. WorkQueue === 让多个消费者绑定到一个队列,共同消费队列中的消息
        1. 结构图

        2. 消息发送
@SpringBootTest
public class SpringAmqpTest {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void testWorkQueue() throws Exception{
        String queueName = "simple.queue";
        String message = "hello,world";
        for (int i = 1; i <= 50; i++) {
            rabbitTemplate.convertAndSend(queueName,"第"+i+"个"+message);
            Thread.sleep(20);
        }
    }
}
        1. prefetch能者多劳机制
          1. 原理:mq在收到consumer的ack之前,可以向consumer推送的消息的条数,默认250
          2. 修改consumer服务的application.yml文件
spring:
  rabbitmq:
    listener:
      simple:
        prefetch: 1 # 每次只能获取一条消息,处理完成才能获取下一个消息
        1. 消息接受
@Slf4j
@Component
public class SpringRabbitListener {

    @RabbitListener(queues = "simple.queue")
    public void onWorkQueue1(String msg) throws Exception {
        log.info("work1接收到的消息,{}", msg);
        Thread.sleep(20);
    }

    @RabbitListener(queues = "simple.queue")
    public void onWorkQueue2(String msg) throws Exception {
        log.info("work2接收到的消息,{}", msg);
        Thread.sleep(200);
    }

}
    1. 发布/订阅模型 === producer->exchange(只负责路由,不负责存储)->queue->consumer
      1. Fanout === 广播给所有的queue
        1. 结构图

        2. 消息发送流程
          1. 可以有多个队列
          2. 每个队列都要绑定到Exchange(交换机)
          3. 生产者发送的消息,只能发送到交换机,交换机来决定要发给哪个队列,生产者无法决定
          4. 交换机把消息发送给绑定过的所有队列
          5. 订阅队列的消费者都能拿到消息
        1. 在消费者模块中创建一个类,声明队列和交换机
@Configuration
public class FanoutConfig {
    /*
    * 创建一个交换机
    * */
    @Bean
    public FanoutExchange fanoutExchange(){
        return new FanoutExchange("fanout.exchange");
    }
    /*
    * 创建队列1
    * */
    @Bean
    public Queue fanoutQueue1(){
        return new Queue("fanout.queue1");
    }
    /*
    * 创建队列2
    * */
    @Bean
    public Queue fanoutQueue2(){
        return new Queue("fanout.queue2");
    }
    /*
    * 将队列1绑定到交换机
    * */
    @Bean
    public Binding queue1Binding(){
        return BindingBuilder.bind(fanoutQueue1()).to(fanoutExchange());
    }
    /*
    * 将队列2绑定到交换机
    * */
    @Bean
    public Binding queue2Binding(){
        return BindingBuilder.bind(fanoutQueue2()).to(fanoutExchange());
    }
    
}
        1. 发送消息
@SpringBootTest
public class SpringAmqpTest {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    @Test
    public void testFanoutExchange() {
        // 队列名称
        String exchangeName = "fanout.exchange";
        // 消息
        String message = "hello world!";
        rabbitTemplate.convertAndSend(exchangeName, "", message);
    }
}
        1. 消息接受
@Slf4j
@Component
public class SpringRabbitListener {

    @RabbitListener(queues = "fanout.queue1")
    public void fanoutQueue1(String msg){
        log.info("收到了来自fanout.queue1的消息,{}",msg);
    }

    @RabbitListener(queues = "fanout.queue2")
    public void fanoutQueue2(String msg){
        log.info("收到了来自fanout.queue2的消息,{}",msg);
    }
}
      1. Direct === 路由给exchange绑定的queue
        1. 结构图

        2. 消息发送流程
          1. queue与exchange绑定的时候需要设置bindingkey
          2. 可以设置多个bindingkey,key可以重复
          3. produce发送的时候需要设置routingkey
          4. exchange判断消息的routingkey与queue中的bindingkey是否完全一致,一致才会接受到消息
        1. 基于注解声明队列和交换机
@Slf4j
@Component
public class SpringRabbitListener {
    
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue1"),
            exchange = @Exchange(name = "direct.exchange"),
            key = {"red","blue"}
    ))
    public void directQueue1(String msg){
        log.info("收到了来自direct.queue1的消息,{}",msg);
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue2"),
            exchange = @Exchange(name = "direct.exchange"),
            key = {"gary","blue"}
    ))
    public void directQueue2(String msg){
        log.info("收到了来自direct.queue2的消息,{}",msg);
    }

}
        1. 消息发送
@SpringBootTest
public class SpringAmqpTest {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void testDirectExchange(){
        String exchange = "direct.exchange";
        String routingKey = "gary";
        String message = "hello direct";
        rabbitTemplate.convertAndSend(exchange,routingKey,message);
    }

}
        1. Direct交换机与Fanout交换机有什么区别?
          1. Fanout交换机将消息路由给每一个与之绑定的队列
          2. Direct交换机根据RoutingKey判断路由给哪个队列
      1. Topic
        1. 结构图

        2. 匹配支持通配符
          1. *:1个单词
          2. #:1个或者多个单词
        1. 基于注解声明队列和交换机
@Slf4j
@Component
public class SpringRabbitListener {

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue1"),
            exchange = @Exchange(name = "topic.exchange"),
            key = "china.#"
    ))
    public void topicQueue1(String msg){
        log.info("收到了来自topic.queue1的消息,{}",msg);
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue2"),
            exchange = @Exchange(name = "topic.exchange"),
            key = "#.news"
    ))
    public void topicQueue2(String msg){
        log.info("收到了来自topic.queue2的消息,{}",msg);
    }

}
        1. 消息发送
@SpringBootTest
public class SpringAmqpTest {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testTopicExchange(){
        String exchange = "topic.exchange";
        String routingKey = "china.123";
        String message = "so cool";
        rabbitTemplate.convertAndSend(exchange, routingKey, message);
    }

}
    1. 消息转换器
      1. 默认发送String,byte[],Serializable
      2. 可以自定义序列化
        1. 在publisher和consumer两个服务中都引入依赖:
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.10</version>
</dependency>
        1. 注入MessageConverter的实现类
@Bean
public MessageConverter jsonMessageConverter(){
    return new Jackson2JsonMessageConverter();
}
        1. 消息发送
@SpringBootTest
public class SpringAmqpTest {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testObjectQueue(){
        String queue = "object.queue";
        User message = new User("蒋浩楠",80);
        rabbitTemplate.convertAndSend(queue,message);
    }
}
        1. 接收消息
@Slf4j
@Component
public class SpringRabbitListener {
    @RabbitListener(queues = "object.queue")
    public void objectQueue(UserDTO dto){
        log.info("收到了来自topic.queue2的消息,{}",dto.toString());
    }
}
  1. RabbitMQ集群

    1. 普通集群
      1. 结构图

      2. 特征
        1. 会在集群的各个节点间共享部分数据,包括:交换机、队列元信息。不包含队列中的消息。
        2. 当访问集群某节点时,如果队列不在该节点,会从数据所在节点传递到当前节点并返回
        3. 队列所在节点宕机,队列中的消息就会丢失
    1. 镜像集群
      1. 结构图

      2. 特征
        1. 交换机、队列、队列中的消息会在各个mq的镜像节点之间同步备份。
        2. 创建队列的节点被称为该队列的主节点,备份到的其它节点叫做该队列的镜像节点
        3. 一个队列的主节点可能是另一个队列的镜像节点
        4. 所有操作都是主节点完成,然后同步给镜像节点
        5. 主宕机后,镜像节点会替代成新的主
    1. 仲裁队列
      1. 特征
        1. 与镜像队列一样,都是主从模式,支持主从数据同步
        2. 使用非常简单,没有复杂的配置
        3. 主从同步基于Raft协议,强一致
      1. java代码中创建仲裁队列
        1. 创建队列
@Bean
public Queue quorumQueue() {
    return QueueBuilder
        .durable("quorum.queue") // 持久化
        .quorum() // 仲裁队列
        .build();
}
        1. SpringAMQP连接MQ集群
spring:
  rabbitmq:
    addresses: 192.168.150.105:8071, 192.168.150.105:8072, 192.168.150.105:8073 #address来代替host、port方式
    username: itcast
    password: 123321
    virtual-host: /
  1. 部署集群
    1. 计划部署3节点的mq集群

    2. 获取cookie,每个集群节点必须具有相同的 cookie。实例之间也需要它来相互通信
docker exec -it mq cat /var/lib/rabbitmq/.erlang.cookie

UTQKOGHXAJPQFJREBLEL #cookie

docker rm -f mq #停止并删除当前的mq容器,我们重新搭建集群
    1. 准备集群配置
#在/tmp目录新建一个配置文件 rabbitmq.conf
cd /tmp

# 创建文件
touch rabbitmq.conf

#配置文件内容如下
loopback_users.guest = false
listeners.tcp.default = 5672
default_user = itcast 
default_pass = 123321
cluster_formation.peer_discovery_backend = rabbit_peer_discovery_classic_config
cluster_formation.classic_config.nodes.1 = rabbit@mq1
cluster_formation.classic_config.nodes.2 = rabbit@mq2
cluster_formation.classic_config.nodes.3 = rabbit@mq3
    1. 再创建一个文件,记录cookie
cd /tmp

# 创建cookie文件
touch .erlang.cookie

# 写入cookie
echo "UTQKOGHXAJPQFJREBLEL" > .erlang.cookie
# 修改cookie文件的权限
# 修改cookie文件的权限
# 修改cookie文件的权限
chmod 600 .erlang.cookie
    1. 准备三个目录,mq1、mq2、mq3,然后拷贝rabbitmq.conf、cookie文件到mq1、mq2、mq3:
cd /tmp

# 创建目录
mkdir mq1 mq2 mq3

# 进入/tmp
cd /tmp

# 拷贝
cp rabbitmq.conf mq1
cp rabbitmq.conf mq2
cp rabbitmq.conf mq3
cp .erlang.cookie mq1
cp .erlang.cookie mq2
cp .erlang.cookie mq3

# 或者
echo mq1 mq2 mq3 | xargs -t -n 1 cp rabbitmq.conf
echo mq1 mq2 mq3 | xargs -t -n 1 cp .erlang.cookie
    1. 启动集群
#创建一个网络
docker network create mq-net

#运行命令
docker run -d --net mq-net \
-v ${PWD}/mq1/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf \
-v ${PWD}/mq1/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie \
--name mq1 \
--hostname mq1 \
-p 8071:5672 \
-p 8081:15672 \
rabbitmq:3-management

docker run -d --net mq-net \
-v ${PWD}/mq2/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf \
-v ${PWD}/mq2/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie \
--name mq2 \
--hostname mq2 \
-p 8072:5672 \
-p 8082:15672 \
rabbitmq:3-management

docker run -d --net mq-net \
-v ${PWD}/mq3/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf \
-v ${PWD}/mq3/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie \
--name mq3 \
--hostname mq3 \
-p 8073:5672 \
-p 8083:15672 \
rabbitmq:3-management
    1. 添加镜像模式
docker exec -it mq1 rabbitmqctl set_policy ha-two "^two\." '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'

    1. 添加仲裁队列

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

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

相关文章

图像识别——玩转YOLO网络

图像识别——玩转YOLO网络 YOLO&#xff0c;全称“You Only Look Once”&#xff0c;意为你只需要看一次&#xff0c;是一种快速、准确的目标检测算法。它由Joseph Redmon等人在2016年提出&#xff0c;其核心思想是将输入图像划分为SS个网格单元&#xff0c;每个网格预测B个边…

什么是脏读?幻读?不可重复读?

脏读(Drity Read)&#xff1a;某个事务 A 已更新一份数据&#xff0c;另一个事务 B 在此时读取了同一份数据&#xff0c;由于某些原因&#xff0c;事务 A 回滚&#xff0c;而事务B读取到事务 A 回滚前的数据。 例子:小明读取到小红提交的100数据.但是小红异常回滚了数据,100变…

STM32单片机实战开发笔记-PWM波输出频率及占空比配置【wulianjishu666】

单片机物联网开发资料&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1XzodQuML7CqZ4ZKinDGKkg?pwdbgep 提取码&#xff1a;bgep PWM模块测试 功能描述 脉冲宽度调制模式&#xff1a; PWM边沿对齐模式&#xff1a; 向上计数配置 当TIMX_CR1寄存器中的DIR为低的时…

Video2Game:革新游戏开发,重塑虚拟世界的未来

Video2Game&#xff1a;革新游戏开发&#xff0c;重塑虚拟世界的未来 一、Video2Game的提出与意义二、Video2Game的核心技术三、Video2Game的实现与应用四、代码实例与未来展望 在数字化和虚拟化日益盛行的今天&#xff0c;高质量的交互式虚拟环境&#xff0c;如游戏和模拟器&a…

TinTin Web3 Bounty 挑战杯第二期再启程,NEAR 生态邀请你来找 Bug!

对 Web3 来说&#xff0c;Bounty 任务应该是普通人获得行业“一杯羹”的重要捷径&#xff01; 通过深入学习各类 Web3 公链技术&#xff0c;凭借实战锻炼开发创新项目&#xff0c;或完善已有网络运行中出现的问题&#xff0c;就有机会更加快速了解其底层技术逻辑&#xff0c;更…

基于YOLOv8+PyQt5复杂场景下船舶目标检测系统

1. 应用场景 复杂场景下船舶目标检测系统的应用场景包括&#xff1a; 港口管理和安全&#xff1a;监控港口区域&#xff0c;确保船舶安全地进出港口&#xff0c;预防相撞事故的发生。 海洋交通监控&#xff1a;实时追踪海上交通流&#xff0c;并识别违规或异常航行行为&#x…

Python ValueError: bad transparency mask

修改前 修复后 运行正常 from PIL import Image# 读取图片 #报错信息解决ValueError: bad transparency mask--相关文档地址https://blog.csdn.net/kalath_aiur/article/details/103945309 #1. 检查 alpha 通道是否是一个有效的掩码。如果不是&#xff0c;则需要对 alpha 通道…

《Boundary Smooth for NER》

来源&#xff1a; ACL2022, 作者&#xff1a;中科院 命名实体识别(NER)模型很容易遇到over-confidence的问题&#xff0c;从而降低了性能。 基于边界存在的问题&#xff0c;参考 Label Smoothing&#xff0c;作者提出了 boundary smoothing 的训练方法&#xff0c;即使用 biaff…

苍穹外卖,接入redis cache后,新增套餐有问题

终端报错&#xff1a; java.lang.IllegalArgumentException: Null key returned for cache operation (maybe you are using named params on classes without debug info?) Builder[public com.sky.result.Result com.sky.controller.admin.SetmealController.save(com.sky.d…

Stable Diffusion WebUI 中文提示词插件 sd-webui-prompt-all-in-one

本文收录于《AI绘画从入门到精通》专栏,订阅后可阅读专栏内所有文章,专栏总目录:点这里。 大家好,我是水滴~~ 今天为大家介绍 Stable Diffusion WebUI 的一款中文提示词插件 sd-webui-prompt-all-in-one,就像它的名字一样,该插件几乎涵盖了提示词相关的所有功能。 文章内…

3D模型格式转换工具HOOPS Exchange如何读取建筑工程中复杂庞多的数据?

在当今数字化时代&#xff0c;建筑行业正日益依赖于复杂的3D建模工具和软件&#xff0c;以便在设计、规划和建造过程中实现更高的效率和精确性。然而&#xff0c;这种效率的提升往往伴随着一个挑战&#xff1a;不同软件之间的3D模型格式可能不兼容&#xff0c;这导致了数据转换…

SpringBootWeb创建

创建spring项目 创建SpringBoot工程定义请求处理类运行常见问题java: 无效的源发行版: XXjava: 无法访问org.springframework.web.bind.annotation.RequestMapping类文件具有错误的版本 61.0, 应为 52.0 创建SpringBoot工程 定义请求处理类 RestController public class HelloC…

unity入门学习笔记

文章目录 unity学习笔记熟悉界面窗口页面快捷键视图特点移动、旋转、缩放快捷键聚焦和隐藏 一些基本概念模型模型的导入一些补充 资源文件资源包的导出资源包的导入 轴心物体的父子关系空物体Global与localpivot与center 组件脚本基础我的第一个脚本 获取脚本组件本地坐标播放模…

JVM调优--理论篇

在对Java应用进行性能优化时&#xff0c;JVM的调优是一个绕不开的话题。本文重点介绍下如何对JVM进行调优&#xff0c;以期提高Java应用的性能、稳定性、响应时间等性能目标。JVM的调优过程符合Java应用的调优过程&#xff0c;主要分为三步&#xff1a;性能监控、性能分析、性能…

8086 汇编学习 Part 8

移位指令 当 C N T > 1 CNT > 1 CNT>1 时&#xff0c;CNT 必须是 CL 寄存器 逻辑左移 SHL OPR , CNT 将寄存器或内存单元中的数据向左移 CNT 位&#xff0c;最后移除的一位写入 CF&#xff0c;最低位用 0 补充 循环左移 ROL OPR , CNT 将寄存器中的值的最高位存…

视频改字祝福 豪车装X系统源码uniapp前端小程序源码

视频改字祝福 豪车装X系统源码uniapp前端小程序源码&#xff0c;创意无限&#xff01;AI视频改字祝福&#xff0c;豪车装X系统源码开源&#xff0c;打造个性化祝 福视频不再难&#xff01; 想要为你的朋友或家人送上一份特别的祝福&#xff0c;让他们感受到你的真诚与关怀吗&am…

服务器数据恢复—ESXi虚拟机中MySQL数据库数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌EVA某型号存储中部署VMware ESXi虚拟化平台&#xff0c;数据盘&#xff08;精简模式&#xff09;快照数据盘&#xff0c;虚拟机中有mysql数据库。 服务器故障&#xff1a; 机房意外断电导致该存储中的一台VMware虚拟机无法启动&#xff0…

深度剖析muduo网络库1.1---面试提问(阻塞、非阻塞、同步、异步)

在面试过程中&#xff0c;如果被问到关于IO的阻塞、非阻塞、同步、异步时&#xff0c;我们应该如何回答呢&#xff1f; 结合最近学习的课程&#xff0c;我作出了以下的总结&#xff0c;希望能与大家共同探讨&#xff01; 先给出 陈硕大神原话&#xff1a;在处理IO的时候&…

基于家政小程序的个性化家政服务研究

基于家政小程序的个性化家政服务研究&#xff0c;是近年来随着移动互联网技术的快速发展和人们生活品质的提高而兴起的一个热门话题。以下是对该领域的研究探讨&#xff1a; 一、引言 随着现代生活节奏的加快&#xff0c;家政服务已成为越来越多家庭不可或缺的一部分。然而&a…

最新优质电商API接口,附带教程【多语言环境高并发】

给大家更新一波24年一月份的新接口吧。 01 接口信息 线路推荐: 多仓&#xff1a; 1.春盈&#xff1a; https://wds.ecsxs.com/230989.json 2.无意&#xff1a; http://www.wya6.cn/tv/yc.json 3.主流电商平台API数据采集 单仓&#xff1a; 1.饭太硬&#xff1a; http:/…
最新文章