1、依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>
2、配置
spring:
cloud:
stream:
rocketmq:
binder:
name-server: ${ROCKETMQ_NAME_SERVER:192.168.3.22:30094} # RocketMQ NameServer地址
enable-msg-trace: true
bindings:
buryingPointOutput:
destination: burying-point-topic # 生产者的Topic
group: burying-point-product-group # 生产者的Group
producer:
partitionKeyExtractorName: buryingPointQueueSelector
buryingPointInput:
destination: burying-point-topic # 消费者的Topic
group: burying-point-consumer-group1 # 消费者的Group
cloud:
stream:
rocketmq:
binder:
name-server: ${ROCKETMQ_NAME_SERVER:192.168.3.22:30094} # RocketMQ NameServer地址
enable-msg-trace: true
bindings:
buryingPointOutput:
destination: burying-point-topic # 生产者的Topic
group: burying-point-product-group # 生产者的Group
producer:
partitionKeyExtractorName: buryingPointQueueSelector
buryingPointInput:
destination: burying-point-topic # 消费者的Topic
group: burying-point-consumer-group1 # 消费者的Group
3、定义生产
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
public interface HelpAiLogSource {
String HELP_AI_LOG_OUTPUT = "helpAiLogOutput";
@Output(HELP_AI_LOG_OUTPUT)
MessageChannel helpAiLogOutput();
}
import jnpf.helpailog.config.HelpAiLogSource;
import jnpf.model.helpailog.po.FtbHelpAiChatLog;
import org.apache.rocketmq.common.message.MessageConst;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
@Service
@EnableBinding(HelpAiLogSource.class)
public class HelpAiLogProducer {
@Autowired
private HelpAiLogSource helpAiLogSource;
public void sendMessage(FtbHelpAiChatLog dto) {
//怎么给消息打上tag
boolean send = helpAiLogSource.buryingPointOutput().send(MessageBuilder.withPayload(dto)
.setHeader(MessageConst.PROPERTY_TAGS, dto.getTenantId() + "," + dto.getUserId())
.setHeader("partitionKey", dto.getFrontKey()) // 将frontKey作为PROPERTY_KEYS发送
.build());
.setHeader(MessageConst.PROPERTY_TAGS, dto.getTenantId() + "," + dto.getUserId())
.setHeader("partitionKey", dto.getFrontKey()) // 将frontKey作为PROPERTY_KEYS发送
.build());
}
}
4、定义消费
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;
public interface HelpAiLogSink {
String HELP_AI_LOG_INPUT = "helpAiLogInput";
@Input(HELP_AI_LOG_INPUT)
SubscribableChannel helpAiLogInput();
}
import cn.hutool.json.JSONUtil;
import jnpf.base.UserInfo;
import jnpf.config.ConfigValueUtil;
import jnpf.database.util.TenantDataSourceUtil;
import jnpf.exception.LoginException;
import jnpf.helpailog.config.HelpAiLogSink;
import jnpf.helpailog.service.FtbHelpAiChatLogService;
import jnpf.model.helpailog.po.FtbHelpAiChatLog;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import jnpf.util.data.DataSourceContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
@Service
@Slf4j
@EnableBinding(HelpAiLogSink.class)
public class HelpAiLogConsumer {
@Autowired
private FtbHelpAiChatLogService ftbHelpAiChatLogService;
@Autowired
private ConfigValueUtil configValueUtil;
@StreamListener(HelpAiLogSink.HELP_AI_LOG_INPUT)
public void receive(String message) {
FtbHelpAiChatLog entity = JSONUtil.toBean(message, FtbHelpAiChatLog.class);
log.info("0000000接收到消息:{}", message);
switchTenant(entity.getTenantId());
ftbHelpAiChatLogService.record(entity);
}
private void switchTenant(String tenantId) {
// 判断是否为多租户
if (configValueUtil.isMultiTenancy()) {
// 判断是不是从外面直接请求
if (StringUtil.isNotEmpty(tenantId)) {
//切换成租户库
try {
TenantDataSourceUtil.switchTenant(tenantId);
} catch (LoginException e) {
throw new RuntimeException("切换租户失败");
}
} else {
UserInfo userInfo = UserProvider.getUser();
Assert.notNull(userInfo.getUserId(), "缺少租户信息");
DataSourceContextHolder.setDatasource(userInfo.getTenantId(), userInfo.getTenantDbConnectionString(), userInfo.isAssignDataSource());
}
}
}
}
5、定义测试接口
@Autowired
private HelpAiLogProducer helpAiLogProducer;
@Autowired
private UserProvider userProvider;
@Autowired
private FtbHelpAiChatLogService ftbHelpAiChatLogService;
/**
* @param dto
* @return
*/
@PostMapping("/record")
public ActionResult<Boolean> record(@Validated @RequestBody HelpAiLogDto dto) {
try {
UserInfo userInfo = userProvider.get();
String userId = userInfo.getUserId();
String tenantId = userInfo.getTenantId();
helpAiLogProducer.sendMessage(dto.convertToEntity(userId, tenantId));
} catch (Exception e) {
e.printStackTrace();
log.error("帮助ai 聊天记录异常:{},{}", dto, e);
}
return ActionResult.success();
}
定义队列选择器
package jnpf.buryingpoint.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy;
import org.springframework.cloud.stream.binder.PartitionSelectorStrategy;
import org.springframework.stereotype.Component;
@Slf4j
@Component("buryingPointQueueSelector")
public class BuryingPointQueueSelector implements PartitionSelectorStrategy, PartitionKeyExtractorStrategy {
@Override
public int selectPartition(Object key, int partitionCount) {
int id = key.hashCode();
int index = id % partitionCount;
return index;
}
@Override
public Object extractKey(org.springframework.messaging.Message<?> message) {
if (message.getHeaders().containsKey("partitionKey")) {
return message.getHeaders().get("partitionKey");
}
return null;
}
}
浙公网安备 33010602011771号