深入解析:分布式之RabbitMQ的使用(2)

news/2025/10/10 10:48:33/文章来源:https://www.cnblogs.com/yxysuanfa/p/19132557

文章目录

  • 主题模式(通配符模式)
    • 生产者
    • 消费者
      • 消费者01
    • 运行结果
  • 消息确认机制
    • AMQP协议中实现了事务机制
      • 生产者
      • 消费者
      • 运行结果
    • Confirm模式
      • 普通发送确认模式
      • 批量确认模式
      • 异步监听发送方确认模式
  • SpringBoot整合RabbitMQ
    • 引入依赖
    • 修改配置yml
    • 加入启动类
  • SpringBoot中的简单队列
    • controller层编写生产者
    • 编写消费者
    • 运行结果
  • SpringBoot工作队列模型
    • 生产者
    • 消费者
    • 运行结果
  • SpringBoot发送对象如何接收
    • 生产者
    • 消费者
    • 运行结果
  • SpringBoot公平分发和手动/自动反馈
    • 添加配置
    • 生产者
    • 消费者
    • 运行结果
  • 订阅模型
    • 生产者
    • 消费者

主题模式(通配符模式)

接着上一篇的接着讲
在这里插入图片描述
Topic:主题模式
在这里插入图片描述
# 匹配一个或多个 (user.msg.1) 也就是user后跟多个点(类似多级文件夹)
* 匹配一个 (user.goods) user后跟一个.(类似于一级文件夹)
在这里插入图片描述

生产者

语法

// 发送消息
// 参数一: 交换机名称
// 参数二: 队列名称(在简单队列和Work模式已经演示过了)/路由键
// 参数三: 消息的持久化
// 参数四: 要发送的消息
channel.basicPublish("exchange", "user.1", null, msg.getBytes());
package com.hsh.test05;
import com.hsh.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class Producer01
{
public static void main(String[] args) {
System.out.println("生产者启动...");
// 获得连接
Connection connection = ConnectionUtils.getConnection();
try {
// 创建通道
Channel channel = connection.createChannel();
// 创建交换机
// 参数一: 交换机名称
// 参数二: 处理路由键(这个后面讲不着急)
channel.exchangeDeclare("exchange", "topic");
// 定义要发送的消息
String msg = "我是user消息";
// 发送消息
// 参数一: 交换机名称
// 参数二: 队列名称(在简单队列和Work模式已经演示过了)/路由键
// 参数三: 消息的持久化
// 参数四: 要发送的消息
channel.basicPublish("exchange", "user.1", null, msg.getBytes());
System.out.println("生产者发送消息:" + msg);
channel.close();
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
}

消费者

语法

// 绑定交换机
// 参数一:队列名称
// 参数二:交换机名称
// 参数三:路由key
channel.queueBind("errorMessage", "exchange", "user.*");
channel.queueBind("errorMessage", "exchange", "user.#");

消费者01

package com.hsh.test05;
import com.hsh.utils.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author xrkhy
* @date 2025/9/23 9:44
* @description
*/
public class Consumer01
{
public static void main(String[] args) {
System.out.println("消费者启动...");
try {
// 获得连接
Connection connection = ConnectionUtils.getConnection();
// 创建通道
Channel channel = connection.createChannel();
// 连接队列
channel.queueDeclare("allMessage", false, false, false, null);
// 绑定交换机
// 参数一:队列名称
// 参数二:交换机名称
// 参数三:路由key
channel.queueBind("allMessage", "exchange", "user.*");
// 监听 true自动反馈
DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println("消费者1:" + message);
}
};
// 监听
channel.basicConsume("allMessage", true, defaultConsumer);
}catch (Exception e){
e.printStackTrace();
}
}
}
package com.hsh.test05;
import com.hsh.utils.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author xrkhy
* @date 2025/9/23 9:44
* @description
*/
public class Comsumer02
{
public static void main(String[] args) {
System.out.println("消费者启动...");
try {
// 获得连接
Connection connection = ConnectionUtils.getConnection();
// 创建通道
Channel channel = connection.createChannel();
// 连接队列
channel.queueDeclare("errorMessage", false, false, false, null);
// 绑定交换机
// 参数一:队列名称
// 参数二:交换机名称
// 参数三:路由key
channel.queueBind("errorMessage", "exchange", "user.#");
// 监听 true自动反馈
DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println("消费者2:" + message);
}
};
// 监听
channel.basicConsume("errorMessage", true, defaultConsumer);
}catch (Exception e){
e.printStackTrace();
}
}
}

运行结果

这里还是先去启动生产者,再去启动消费者,最后再去启动生产者
在这里插入图片描述
修改生产者为多个点再次运行

String msg = "我是user.msg.1消息";
channel.basicPublish("exchange", "user.msg.1", null, msg.getBytes());

发现只有消费者2才有。
在这里插入图片描述

消息确认机制

我们之前讲了消费者和RabbitMQ的持久化如下图。
在这里插入图片描述
但是我们如何确保生产者的数据能够到达RabbitMQ呢?这就是消息确认机制
在这里插入图片描述
生产者将消息发送出去之后,消息有没有到达rabbitm服务器?(默认不知道)
两种方式可以确认:

  1. AMQP协议中实现了事务机制
  2. Confirm模式

AMQP协议中实现了事务机制

语法

channel.txSelect()声明启动事务模式;
channel.txCommit()提交事务;
channel.txRollback()回滚事务;

模式缺点:降低系统吞吐量
下面开始代码演示

生产者

在test06中新建Producer01

package com.hsh.test06;
import com.hsh.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author xrkhy
* @date 2025/9/22 18:52
* @description
*/
public class Producer01
{
public static void main(String[] args) {
System.out.println("生产者启动...");
Connection connection = null;
Channel channel = null;
// 定义是否发送成功
int cnt = 0;
try {
// 获得连接
connection = ConnectionUtils.getConnection();
// 创建通道
channel = connection.createChannel();
// 创建队列声明
channel.queueDeclare("test06", false, false, false, null);
// 定义发送消息的数据
String message = "test06的内容";
// 声明事务
channel.txSelect();
// 发送消息
channel.basicPublish("", "test06", null, message.getBytes());
// 报错
int i = 1/0;
// 提交事务
channel.txCommit();
System.out.println("生产者发送消息:" + message);
}catch (Exception e){
e.printStackTrace();
// 报错就事务回滚
try {
channel.txRollback();
System.out.println("事务回滚");
cnt++;
} catch (Exception ex) {
e.printStackTrace();
}
}finally {
try {
channel.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("消息发送"+(cnt==0?"成功":"失败"));
}
}

消费者

在test06中新建Consumer01

package com.hsh.test06;
import com.hsh.utils.ConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author xrkhy
* @date 2025/9/22 18:53
* @description
*/
public class Consumer01
{
public static void main(String[] args) {
System.out.println("消费者启动...");
try {
// 获得连接
Connection connection = ConnectionUtils.getConnection();
// 创建通道
Channel channel = connection.createChannel();
// 连接队列
channel.queueDeclare("test06", false, false, false, null);
// 监听 true自动反馈
DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println("消费者1:" + message);
}
};
channel.basicConsume("test06", true, defaultConsumer);
}catch (Exception e){
e.printStackTrace();
}
}
}

运行结果

在这里插入图片描述

将生产者的int i = 1/0;取消注释,再次测试,如果回滚说明成功
在这里插入图片描述

Confirm模式

方式一:channel.waitForConfirms()普通发送方确认模式;
方式二:channel.waitForConfirmsOrDie()批量确认模式;
方式三:channel.addConfirmListener()异步监听发送方确认模式;

普通发送确认模式

Connection conn = ConnectionUtils.getConnection();
Channel ch = conn.createChannel();
ch.queueDeclare(QUEUE_NAME,false,false,false,null);
String str = "holle wzy 333";
ch.confirmSelect();
//开启消息确认模式
ch.basicPublish("",QUEUE_NAME,null,str.getBytes());
//加入错误代码后事务回滚
int i = 1/0;
if(ch.waitForConfirms())
{
System.out.println("消息确认发送");
}
ch.close();
conn.close();

ch.confirmSelect()声明开启发送方确认模式,再使用ch.waitForConfirms()等待消息被服务器确认即可。

批量确认模式

// 声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 开启发送方确认模式
channel.confirmSelect();
for (int i = 0; i <
10; i++) {
String message = "holle wzy 333";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
}
channel.waitForConfirmsOrDie();
//直到所有信息都发布,只要有一个未确认就会IOException
System.out.println("全部执行完成");

ch.confirmSelect()声明开启发送方确认模式,再使用ch.waitForConfirmsOrDie()等待消息被服务器确认即可。

异步监听发送方确认模式

// 开启发送方确认模式
channel.confirmSelect();
for (int i = 0; i <
10; i++) {
String message = "holle wzy "+i;
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
}
//异步监听确认和未确认的消息
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
System.out.println("未确认消息,标识:" + deliveryTag);
}
@Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.out.println(String.format("已确认消息,标识:%d,多个消息:%b", deliveryTag, multiple));
}
});

异步模式的优点,就是执行效率高,不需要等待消息执行完,只需要监听消息即可。

deliveryTag:如果是多条,这个就是最后一条消息的tag
Multiple: 是否多条

SpringBoot整合RabbitMQ

引入依赖

<!-- 注释之前的依赖 --><!--<dependency>--><!-- <groupId>com.rabbitmq</groupId>--><!-- <artifactId>amqp-client</artifactId>--><!-- <version>5.7.1</version>--><!--</dependency>--><!-- 添加依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><!-- 引入lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>

由于集成的RabbitMQ的依赖中包含amqp-client所以不会报错。
在这里插入图片描述

修改配置yml

application.properties修改为application.yml

spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest

加入启动类

由于我们之前把启动类删除了,现在在加上。
注意要在com…hsh下新建Rabbitmq01Application文件
在这里插入图片描述

package com.hsh;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Rabbitmq01Application
{
public static void main(String[] args) {
SpringApplication.run(Rabbitmq01Application.class, args)
;
}
}

SpringBoot中的简单队列

在springboot中编写队列时,一般在消费者创建队列就行了,生产者不需要创建队列。

controller层编写生产者

package com.hsh.controller;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/index")
public class IndexController
{
// 注入RabbitMQ模版
@Autowired
private RabbitTemplate rabbitTemplate;
@RequestMapping("/send")
public String index(){
// 向队列发送消息
rabbitTemplate.convertAndSend("简单队列", "test06的内容");
return "发送成功";
}
}

编写消费者

package com.hsh.controller;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class ConsumerRabbitListenrs
{
@RabbitListener(queuesToDeclare = @Queue("简单队列"))
// 上面注解相当于 queueDeclare("简单队列", false, false, false, null);
public void receive01(String message){
System.out.println("消费者1:" + message);
}
}

运行结果

浏览器输入http://localhost:8080/index/send
在这里插入图片描述
idea的控制台
在这里插入图片描述
RabbitMQ可视化工具
在这里插入图片描述

SpringBoot工作队列模型

生产者

package com.hsh.controller;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/index")
public class IndexController
{
@Autowired
private RabbitTemplate rabbitTemplate;
@RequestMapping("/send")
public String index(){
// 向队列发送消息
for (int i = 0; i <
10; i++){
rabbitTemplate.convertAndSend("work", "work的内容" + i);
}
return "发送成功";
}
}

消费者

package com.hsh.controller;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class ConsumerRabbitListenrs
{
@RabbitListener(queuesToDeclare = @Queue("work"))
// 上面注解相当于 queueDeclare("work队列", false, false, false, null);
public void receive01(String message){
System.out.println("消费者1:" + message);
}
@RabbitListener(queuesToDeclare = @Queue("work"))
// 上面注解相当于 queueDeclare("work队列", false, false, false, null);
public void receive02(String message){
System.out.println("消费者2:" + message);
}
}

运行结果

浏览器输入http://localhost:8080/index/send
在这里插入图片描述

SpringBoot发送对象如何接收

我们先来配置Goods类

package com.hsh.pojo;
import lombok.Data;
import java.io.Serializable;
@Data
public class Goods
implements Serializable {
private Integer goodsId;
private String goodsName;
}

注意实体类必须序列化

生产者

package com.hsh.controller;
import com.hsh.pojo.Goods;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/index")
public class IndexController
{
@Autowired
private RabbitTemplate rabbitTemplate;
@RequestMapping("/send")
public String index(){
Goods goods =new Goods();
goods.setGoodsId(1);
// 向队列发送消息
for (int i = 0; i <
10; i++){
goods.setGoodsName("商品"+ i);
rabbitTemplate.convertAndSend("work", goods);
}
return "发送成功";
}
}

消费者

Goods goods = (Goods) SerializationUtils.deserialize(message.getBody());
package com.hsh.controller;
import com.hsh.pojo.Goods;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.utils.SerializationUtils;
import org.springframework.stereotype.Component;
@Component
public class ConsumerRabbitListenrs
{
@RabbitListener(queuesToDeclare = @Queue("work"))
// 上面注解相当于 queueDeclare("简单队列", false, false, false, null);
public void receive01(Message message){
Goods goods = (Goods) SerializationUtils.deserialize(message.getBody());
System.out.println("消费者1:" + goods);
}
@RabbitListener(queuesToDeclare = @Queue("work"))
// 上面注解相当于 queueDeclare("简单队列", false, false, false, null);
public void receive02(Message message){
Goods goods = (Goods) SerializationUtils.deserialize(message.getBody());
System.out.println("消费者2:" + goods);
}
}

运行结果

在这里插入图片描述

SpringBoot公平分发和手动/自动反馈

添加配置

spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
listener:
simple:
acknowledge-mode: manual # 开启手动反馈 相当于channel.basicConsume("队列名", false, defaultConsumer);

生产者

package com.hsh.controller;
import com.hsh.pojo.Goods;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/index")
public class IndexController
{
@Autowired
private RabbitTemplate rabbitTemplate;
@RequestMapping("/send")
public String index(){
Goods goods =new Goods();
// 向队列发送消息
for (int i = 0; i <
10; i++){
goods.setGoodsId(i);
goods.setGoodsName("商品"+ i);
rabbitTemplate.convertAndSend("work", goods);
}
return "发送成功";
}
}

消费者

package com.hsh.controller;
import com.hsh.pojo.Goods;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.utils.SerializationUtils;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class ConsumerRabbitListenrs
{
@RabbitListener(queuesToDeclare = @Queue("work"))
// 上面注解相当于 queueDeclare("简单队列", false, false, false, null);
public void receive01(Message message, Channel channel){
Goods goods = null;
try {
goods = (Goods) SerializationUtils.deserialize(message.getBody());
if(goods.getGoodsId() == 4){
int i = 1/0;
}
System.out.println("消费者1:" + goods);
// 手动反馈
// 第一个参数:envelope.getDeliveryTag() 当前消息的编号 我在上面的输出打印了可以看看
// 第二个参数:false单挑消息应答,true批量应答
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e) {
e.printStackTrace();
System.out.println("第"+message.getMessageProperties().getDeliveryTag()+"条处理失败,放回队列,内容是:"+goods);
try {
// 拒绝消息
// 参数1: 消息的编号
// 参数2:表示是否进行批量操作 默认false
// 参数3:被拒绝的消息是否重新入队
// 当设置为 true时,RabbitMQ 会将被拒绝的消息重新放回原始队列的尾部,以便可以再次被消费
// 当设置为 false时,RabbitMQ 会将消息从队列中删除,不会重新入队
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
} catch (Exception ex) {
ex.printStackTrace();
}
} finally {
// 无论失败还是成功,都需要执行睡眠一会
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@RabbitListener(queuesToDeclare = @Queue("work"))
// 上面注解相当于 queueDeclare("简单队列", false, false, false, null);
public void receive02(Message message, Channel channel){
Goods goods = null;
try {
goods = (Goods) SerializationUtils.deserialize(message.getBody());
System.out.println("消费者2:" + goods);
// 手动反馈
// 第一个参数:envelope.getDeliveryTag() 当前消息的编号 我在上面的输出打印了可以看看
// 第二个参数:false单挑消息应答,true批量应答
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e) {
e.printStackTrace();
System.out.println("第"+message.getMessageProperties().getDeliveryTag()+"条处理失败,放回队列,内容是:"+goods);
try {
// 拒绝消息
// 参数1: 消息的编号
// 参数2:表示是否进行批量操作 默认false
// 参数3:被拒绝的消息是否重新入队
// 当设置为 true时,RabbitMQ 会将被拒绝的消息重新放回原始队列的尾部,以便可以再次被消费
// 当设置为 false时,RabbitMQ 会将消息从队列中删除,不会重新入队
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
} catch (Exception ex) {
ex.printStackTrace();
}
} finally {
// 无论失败还是成功,都需要执行睡眠一会
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

运行结果

报错放回之前队列
在这里插入图片描述

订阅模型

生产者

public void topic() {
for (int i = 0; i <
10; i++) {
if (i == 4) {
rabbitTemplate.convertAndSend("report", "user.vip.msg", "vip消息" + i);
continue;
} if (i == 8){
rabbitTemplate.convertAndSend("report", "user.vip.gift", "vip礼物" + i);
continue;
}
rabbitTemplate.convertAndSend("report", "user.msg", "用户消息" + i);
}
}

消费者

@RabbitListener(bindings = {
@QueueBinding(
value = @Queue, //临时队列
exchange = @Exchange(value = "report", type = "topic"), //指定交换机
key = {
"user.#"
}
)
})
public void receive2(String message) {
System.out.println("消费者2->" + message);
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker-compose 启动 elk

一 docker-compose 新增节点# elasticsearchelasticsearch:image: elasticsearch:7.17.6container_name: elasticsearchports:- "9410:9410"- "9420:9420"environment:# 设置集群名称cluster.name…

Gitee领航中国DevOps市场:本土化优势与云原生战略的双轮驱动

Gitee领航中国DevOps市场:本土化优势与云原生战略的双轮驱动 中国DevOps市场正在经历前所未有的高速发展期,这一现象背后折射出的是中国数字化转型浪潮的加速推进。根据最新市场研究数据显示,到2025年中国DevOps市场…

禅道怎么更新MySQL数据库的用户名和密码

创建用户并授权 需要使用本地地址127.0.0.1连接MySQL数据库否则可能授权失败> create user zentao@% identified by password; > grant all on zentao.* to zentao@%; > flush privileges修改配置文件 配置文…

【IEEE出版、EI检索稳定】 第五届数字化社会与智能系统国际学术会议(DSInS 2025)

第五届数字化社会与智能系统国际学术会议(DSInS 2025) 2025 5th International Conference on Digital Society and Intelligent Systems 多届IEEE稳定出版,EI检索稳定,录用率高 海南大学等多所高校联合主办丨确定…

【2025-10-03】连岳摘抄

23:59当你原谅别人时,对方可能没有察觉,但你会释怀。宽恕不是为了别人,宽恕是我们给自己的礼物。——凯文凯利有了孩子,吵架、打架确实不好,一是对孩子有不良示范,二是父母就是孩子的天,再小的事他们也以为是天…

maxscript的自动科学计数法转换导致dotnet json序列化识别错误

intEndFrame = -2147483648 -- print -2.14748e+09 classof intEndFrame -- float--转json后是 {"key":-2.14748365E+09} -2.14748365 10⁹ = -2,147,483,650 这玩意已经不在int32范围内intEndFrame = dot…

国产项目管理工具Gitee:本土化优势赋能企业数字化转型

国产项目管理工具Gitee:本土化优势赋能企业数字化转型 在数字化转型浪潮席卷全球的当下,项目管理工具已成为企业提升协作效率的关键基础设施。随着国内技术自主可控需求的日益增强,本土项目管理平台迎来了前所未有的…

【光照】UnityURP[光照贴图]GPU instancing在静态动态物体上的应用

该专栏探讨了Unity URP中静态和动态物体的GPU实例化技术要点。对于静态物体,需标记为BatchingStatic并禁用静态合批,通过LightmapIndex绑定光照贴图,在着色器中添加实例化支持。动态物体则依赖光照探针获取间接光照…

Vue3路由传递复杂参数(比如一个对象)

在 Vue 3 中,需要通过路由传递复杂参数(比如一个对象)时,有多种方法可以实现。下面我为你详细介绍几种主流方式,并提供相应的代码示例。最佳实践提示:传递复杂对象时,由于 URL 有长度限制,对于数据量较大的对象…

2025 年国内一体板厂家最新推荐排行榜:装配式 / 珍珠岩 / 免拆 / 外墙保温品类优质企业权威精选

在建筑节能与绿色发展政策驱动下,一体板因整合保温、装饰、防火等功能成为建筑项目核心选材,市场规模持续扩张。但行业快速发展伴随乱象:部分企业以次充好,用劣质芯材降低成本,导致产品防火等级不足、保温性能衰减…

系统提示词优化模板-通用优化-带输出格式要求

你是一个专业的AI提示词优化专家。请帮我优化以下prompt,并按照以下格式返回: # Role: [角色名称] ## Profile- language: [语言]- description: [详细的角色描述]- background: [角色背景]- personality: [性格特征…

CRMEB标准版PHP订单列表源码解析:自定义字段与导出功能

订单列表 订单列表显示商城所有订单信息,包含待支付、待发货、待核销、待收货、待评价、已完成及售后订单;可以根据订单类型、支付方式,订单创建时间,关键字(订单号、用户id、用户名称、用户电话、商品名称等)进…

odoo18安装环境

odoo18 1 安装python 3.11.9 2 安装node.js 14.21.3 安装配置运行环境 重启... 3 安装pycharm配置 python git 下载依赖库 python -m pip -r requirements.tex

系统提示词优化模板-通用模板

你是一个专业的AI提示词优化专家。请帮我优化以下prompt,并按照以下格式返回: # Role: [角色名称] ## Profile- language: [语言]- description: [详细的角色描述]- background: [角色背景]- personality: [性格特征…

aardio编程中的常量

aardio编程中的常量二. 常量( constants ) # 在程序运行过程中,用来存储数据值并且其值不能被改变的对象称为常量,常量赋为非 null 值以后就不能再更改值。 常量名使用首字符为下划线且长度大于 1 个字节、小于 25…

Group Theory Note 2/2 (Michael Artin Algebra Chapter 2 Groups) (to complete)

2.6 ISOMORPHISMS 2.6.1 Def. (Isomorphism) Bijective group homomorphism. Notation: \(G \approx G\) 2.6.2 Lemma. $\varphi: G \to G \text{ is isomorphism } \leftrightarrow \varphi^{-1}: G \to G \text{ is …

开源 C# 快速开发(三)复杂控件 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

CF2145E Predicting Popularity

有帮助的题集第三篇 😃😃😃。题意 有 $n$ 个人喜欢看电影,第 $i$ 个人对电影的评价有两个,动作元素值 $a_i$ 和剧情元素值 $d_i$。现在有一部电影的上述两个值为 $ac$ 和 $dr$,每个人要满足一个条件 TA 才会去…

偏微分方程数值解法

偏微分方程数值解法参考:https://chat.deepseek.com/a/chat/s/05f7620b-5c20-41ed-93cf-52e4af3294ea

半导体行业文件摆渡系统:守护核心数据安全,赋能高效协同!

在数字经济时代,半导体行业作为科技产业的核心支柱,其研发设计、工艺参数等核心数据是企业竞争力的关键。为保护这些高价值数据,半导体企业普遍采用网络隔离架构,将内部网络细分为红区(高敏感,存储核心设计数据)…