1.导入依赖
<!-- mqtt -->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
</dependency>
2.相关代码
@Data
@Configuration
public class MqttConfiguration {
private static final Logger log = LoggerFactory.getLogger(MqttConfiguration.class);
@Value("${mqtt.host:tcp://116.62.36.68:1883}")
private String host;
@Value("${mqtt.username:admin}")
private String username;
@Value("${mqtt.password:admin123}")
private String password;
@Value("${mqtt.clientId:ClientId_local}")
private String clientId;
@Value("${mqtt.timeout:10}")
private int timeOut;
@Value("${mqtt.keepalive:20}")
private int keepAlive;
@Value("${mqtt.topic1:A/pick/warn/#}")
private String topic1;
@Value("${mqtt.topic2:room_pk_message_topic}")
private String topic2;
@Value("${mqtt.topic3:A/cmd/resp}")
private String topic3;
@Value("${mqtt.topic4:ABCH}")
private String topic4;
}
@Data
public class MqttRoomPkMsg implements Serializable {
/**
* 麦位PK值信息
*/
private List<MicrophonePkValueDto> microphonePkValueDtoList;
/**
* 倒计时
*/
private Long countdown;
/**
* 红队信息
*/
private RedTeamDto redTeamDto;
/**
* 蓝队信息
*/
private BlueTeamDto blueTeamDto;
private String time;
}
@Slf4j
public class MyMQTTCallback implements MqttCallbackExtended {
@Autowired
private MqttConfiguration mqttConfiguration;
@Autowired
private MyMQTTClient myMQTTClient;
/**
* 丢失连接,可在这里做重连
* 只会调用一次
*
* @param throwable
*/
@Override
public void connectionLost(Throwable throwable) {
// 输出日志信息,提示连接已经断开, 并记录异常原因
log.error("mqtt connectionLost 连接断开,5S之后尝试重连: {}", throwable.getMessage());
// 尝试进行重新连接
long reconnectTimes = 1;//重新连接的次数
while (true) {//开启死循环
try {
// 如果客户端已经重新连接成功,则重新订阅主题并返回
if (myMQTTClient.getClient().isConnected()) {
//判断已经重新连接成功 需要重新订阅主题 可以在这个if里面订阅主题 或者 connectComplete(方法里面) 看你们自己选择
log.warn("mqtt reconnect success end 重新连接 重新订阅成功");
// TODO: 在这里添加代码重新订阅主题
return;
}
// 如果客户端仍未连接成功,则进行重新连接,并记录重连次数
reconnectTimes += 1;
log.warn("mqtt reconnect times = {} try again... mqtt重新连接时间 {}", reconnectTimes, reconnectTimes);
myMQTTClient.getClient().reconnect();
} catch (MqttException e) {
// 输出异常信息
log.error("mqtt断连异常", e);
}
try {
// 等待 5s 后再次尝试重新连接
Thread.sleep(5000);
} catch (InterruptedException e1) {
// 捕获线程中断异常,并忽略
}
}
}
/**
* @param topic
* @param mqttMessage
* @throws Exception subscribe后得到的消息会执行到这里面
*/
@Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
// 输出日志信息,提示接收到消息和消息内容
log.info("接收消息主题 : {},接收消息内容 : {}", topic, new String(mqttMessage.getPayload()));
//发布消息主题
// 判断消息主题,并根据不同的主题进行不同的处理
if (topic.equals("embed/resp")) {
// 解析 JSON 消息内容
Map maps = (Map) JSON.parse(new String(mqttMessage.getPayload(), CharsetUtil.UTF_8));
//todo 在这里添加代码完成自己的业务接口
insertCmdResults(maps);
}
//接收报警主题
if (topic.equals("embed/warn")) {
// 解析 JSON 消息内容
Map maps = (Map) JSON.parse(new String(mqttMessage.getPayload(), CharsetUtil.UTF_8));
//todo 在这里添加代码完成自己的业务接口
insertPushAlarm(maps);
}
}
private void insertPushAlarm(Map maps) {
System.out.println("-------接收报警主题------业务002--------" + maps);
}
private void insertCmdResults(Map maps) {
System.out.println("--------发布消息主题----业务001------" + maps);
}
/**
* 连接成功后的回调 可以在这个方法执行 订阅主题 生成Bean的 MqttConfiguration方法中订阅主题 出现bug
* 重新连接后 主题也需要再次订阅 将重新订阅主题放在连接成功后的回调 比较合理
*
* @param reconnect
* @param serverURI
*/
@Override
public void connectComplete(boolean reconnect, String serverURI) {
log.info("MQTT 连接成功,连接方式:{}", reconnect ? "重连" : "直连");
//订阅主题
// myMQTTClient.subscribe(mqttConfiguration.topic1, 1);
myMQTTClient.subscribe(mqttConfiguration.getTopic2(), 1);
// myMQTTClient.subscribe(mqttConfiguration.topic3, 1);
// myMQTTClient.subscribe(mqttConfiguration.topic4, 1);
}
/**
* 消息到达后
* subscribe后,执行的回调函数
*
* @param s
* @param mqttMessage
* @throws Exception
*/
/**
* publish后,配送完成后回调的方法
*
* @param iMqttDeliveryToken
*/
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
log.info("==========deliveryComplete={}==========", iMqttDeliveryToken.isComplete());
}
}
@Slf4j
public class MyMQTTClient {
private static final Logger LOGGER = LoggerFactory.getLogger(MyMQTTClient.class);
private volatile MqttClient client;
@Autowired
private MqttConfiguration mqttConfiguration;
@Autowired
@Lazy
private MyMQTTCallback myMqttCallback;
// 在 Bean 初始化完成后执行
public void connect(String applicationName, String ipAddr) {
try {
if (client == null) {
synchronized (this) {// 双重检查锁确保多线程安全性
if (client == null) {
创建 MqttClient 实例并设置回调函数
//MemoryPersistence() 表示采用内存存储消息,对于短时间内需要发送的消息,可以使用内存存储,不需要持久化到本地磁盘。
client = new MqttClient(mqttConfiguration.getHost(), applicationName + ":" + ipAddr, new MemoryPersistence());
client.setCallback(myMqttCallback);
}
}
}
// 设置 MQTT 连接选项
MqttConnectOptions mqttConnectOptions = setMqttConnectOptions(mqttConfiguration.getUsername(), mqttConfiguration.getPassword(), mqttConfiguration.getTimeOut(), mqttConfiguration.getKeepAlive());
// 进行 MQTT 连接
if (!client.isConnected()) {// 如果未连接,则进行连接
client.connect(mqttConnectOptions);
} else {// 如果已经连接,则断开连接后再进行连接
client.disconnect();
client.connect(mqttConnectOptions);
}
} catch (MqttException e) {
log.error("mqtt failed to connect");
Asserts.fail(e.getMessage());
}
LOGGER.info("MQTT connect success");//未发生异常,则连接成功
}
public MqttClient getClient() {
return client;
}
public void setClient(MqttClient client) {
this.client = client;
}
/**
* 设置mqtt连接参数
*
* @param username
* @param password
* @param timeout
* @param keepalive
* @return
*/
public MqttConnectOptions setMqttConnectOptions(String username, String password, int timeout, int keepalive) {
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(username);
options.setPassword(password.toCharArray());
options.setConnectionTimeout(timeout);
options.setKeepAliveInterval(keepalive);
options.setCleanSession(true);
options.setAutomaticReconnect(true);
return options;
}
/**
* 发布,默认qos为0,非持久化
*
* @param pushMessage
* @param topic
*/
public void publish(String pushMessage, String topic) {
publish(pushMessage, topic, 0, false);
}
/**
* 发布消息
*
* @param pushMessage
* @param topic
* @param qos
* @param retained:留存
*/
public void publish(String pushMessage, String topic, int qos, boolean retained) {
MqttMessage message = new MqttMessage();
message.setPayload(pushMessage.getBytes());
message.setQos(qos);
message.setRetained(retained);
MqttTopic mqttTopic = getClient().getTopic(topic);
if (null == mqttTopic) {
LOGGER.error("topic is not exist");
}
MqttDeliveryToken token;//Delivery:配送
synchronized (this) {//注意:这里一定要同步,否则,在多线程publish的情况下,线程会发生死锁,分析见文章最后补充
try {
token = mqttTopic.publish(message);//也是发送到执行队列中,等待执行线程执行,将消息发送到消息中间件
token.waitForCompletion(1000L);
} catch (MqttPersistenceException e) {
e.printStackTrace();
} catch (MqttException e) {
e.printStackTrace();
}
}
}
/**
* 订阅某个主题
*
* @param topic
* @param qos
*/
public void subscribe(String topic, int qos) {
try {
getClient().subscribe(topic, qos);
} catch (MqttException e) {
e.printStackTrace();
}
}
/**
* 取消订阅主题
*
* @param topic 主题名称
*/
public void cleanTopic(String topic) {
if (client != null && client.isConnected()) {
try {
client.unsubscribe(topic);
} catch (MqttException e) {
e.printStackTrace();
}
} else {
System.out.println("取消订阅失败!");
}
}
}
3.启动类
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication(scanBasePackages = {"com.aaa.bbb.common", "com.aaa.bbb.chatroom"})
public class DJSoulChatRoomApplication {
public static void main(String[] args) throws UnknownHostException {
ConfigurableApplicationContext applicationContext = SpringApplication.run(DJSoulChatRoomApplication.class, args);
MyMQTTClient myMQTTClient = applicationContext.getBean(MyMQTTClient.class);
ConfigurableEnvironment environment = applicationContext.getEnvironment();
String applicationName = environment.getProperty("spring.application.name");
myMQTTClient.connect(applicationName, InetAddress.getLocalHost().getHostAddress());
}
}
Controller
@ApiOperation("发起房间PK初始化")
@PostMapping("/initiateRoomPKInitialization")
public void initiateRoomPKInitialization(@RequestBody InitiateRoomPKRequest roomPKRequest){
chatRoomService.initiateRoomPKInitialization(roomPKRequest);
}
@ApiOperation("房间PK贡献榜记录")
@GetMapping("/roomPkContributionList")
public CommonResult<List<RoomPkContributionResponse>> roomPkContributionList(@ApiParam("房间id") @RequestParam String roomId,@ApiParam("队伍类型") @RequestParam String teamType){
return CommonResult.success(chatRoomService.roomPkContributionList(roomId,teamType));
}
@ApiOperation("倒计时结束,根据房间id查询房间PK结果")
@GetMapping("/queryRoomPkResults")
public CommonResult<InitiateRoomPKResponse> queryRoomPkResults(@ApiParam("房间id") @RequestParam String roomId){
return CommonResult.success(chatRoomService.queryRoomPkResults(roomId));
}
@ApiOperation("结束PK")
@GetMapping("/endRoomPk")
public CommonResult<Boolean> endRoomPk(@ApiParam("房间id") @RequestParam String roomId){
return CommonResult.success(chatRoomService.endRoomPk(roomId));
}
Service
/**
* 发起房间PK初始化
* @param roomPKRequest
* @return
*/
void initiateRoomPKInitialization(InitiateRoomPKRequest roomPKRequest);
/**
* 房间PK贡献榜记录
* @param roomId
* @param teamType
* @return
*/
List<RoomPkContributionResponse> roomPkContributionList(String roomId, String teamType);
/**
* 根据房间id查询房间PK结果
* @param roomId
* @return
*/
InitiateRoomPKResponse queryRoomPkResults(String roomId);
/**
* 结束PK
* @param roomId
* @return
*/
Boolean endRoomPk(String roomId);
ServiceImpl
public Boolean canUsersInitiateRoomPK(String roomId, DjsUser user, DjsChatRoom djsChatRoom) {
//校验房间id是否为空
if (StringUtils.isEmpty(roomId)) {
Asserts.fail(ResultCode.ROOM_ID_CANNOT_BE_EMPTY);
}
//获取当前用户信息
//根据房间id查询房间信息
if (ObjectUtils.isEmpty(djsChatRoom)) {
Asserts.fail(ResultCode.THE_ROOM_DOES_NOT_EXIST);
}
//判断当前用户是否是房主或者管理员,如果不是就提示没有权限发起PK
DjsChatRoomRole djsChatRoomRole = chatRoomRoleDao.selectChatRoomRoleByChatRoomIdAndUserId(user.getUserId(), djsChatRoom.getCrId());
if (ObjectUtils.isEmpty(djsChatRoomRole)) {
Asserts.fail(ResultCode.CURRENTLY_DO_NOT_HAVE_PERMISSION_TO_INITIATE_ROOM_PK);
}
//查询该房间 红队:1号 2号 5号 6号 蓝队:3号 4号 7号 8号 红蓝队伍各麦位上至少有一个用户
//根据房间id获取该房间麦位信息
Map<Object, Object> allWheatPosition = redisService.hGetAll(RedisKeyConstant.getChatRoomMicroPhoneKey(roomId));
if (ObjectUtils.isEmpty(allWheatPosition.get(MicroPhoneEnum.ONE.getCode())) && ObjectUtils.isEmpty(allWheatPosition.get(MicroPhoneEnum.TWO.getCode())) && ObjectUtils.isEmpty(allWheatPosition.get(MicroPhoneEnum.FIVE.getCode())) && ObjectUtils.isEmpty(allWheatPosition.get(MicroPhoneEnum.SIX.getCode()))) {
//红蓝双方至少各有一人,可开启PK
Asserts.fail(ResultCode.AT_LEAST_ONE_PERSON_FROM_EACH_OF_THE_RED_AND_BLUE_SIDES_CAN_INITIATE_A_PK);
}
if (ObjectUtils.isEmpty(allWheatPosition.get(MicroPhoneEnum.THREE.getCode())) && ObjectUtils.isEmpty(allWheatPosition.get(MicroPhoneEnum.FOUR.getCode())) && ObjectUtils.isEmpty(allWheatPosition.get(MicroPhoneEnum.SEVEN.getCode())) && ObjectUtils.isEmpty(allWheatPosition.get(MicroPhoneEnum.EIGHT.getCode()))) {
//红蓝双方至少各有一人,可开启PK
Asserts.fail(ResultCode.AT_LEAST_ONE_PERSON_FROM_EACH_OF_THE_RED_AND_BLUE_SIDES_CAN_INITIATE_A_PK);
}
//根据房间id创建房间PK值的redis
for (int i = 0; i < 8; i++) {
redisTemplate.opsForHash().put(RedisKeyConstant.getChatRoomPkValueKey(roomId), String.valueOf(i + 1), 0);
}
return true;
}
@Override
public void initiateRoomPKInitialization(InitiateRoomPKRequest roomPKRequest) {
//校验房间id是否为空
if (StringUtils.isEmpty(roomPKRequest.getRoomId())) {
Asserts.fail(ResultCode.ROOM_ID_CANNOT_BE_EMPTY);
}
//获取当前用户信息
DjsUser user = getUser();
//根据房间id查询房间信息
DjsChatRoom djsChatRoom = chatRoomDao.selectChatRoomById(roomPKRequest.getRoomId());
if (ObjectUtils.isEmpty(djsChatRoom)) {
Asserts.fail(ResultCode.THE_ROOM_DOES_NOT_EXIST);
}
//校验房间是否能够发起PK
canUsersInitiateRoomPK(roomPKRequest.getRoomId(), user, djsChatRoom);
//倒计时计算
log.info("需要PK的时间:{}" + roomPKRequest.getPkTimeCountdown());
Long now = System.currentTimeMillis();
log.info("发起PK当前时间:{}" + now);
Long pkTimeCountdown = roomPKRequest.getPkTimeCountdown() * 1000L + now;
log.info("PK到期时间:{}" + pkTimeCountdown);
//删除 当前房间麦克风PK值(值为hash类型) getChatRoomPkValueKey(String crId)
redisService.del(RedisKeyConstant.getChatRoomPkValueKey(roomPKRequest.getRoomId()));
//删除 房间PK倒计时 static final String getRoomPkCountdown()
redisService.hDel(RedisKeyConstant.getRoomPkCountdown(), roomPKRequest.getRoomId());
//删除 PK贡献榜 getPkContributionList(String roomId,String teamType)
redisService.del(RedisKeyConstant.getPkContributionList(roomPKRequest.getRoomId(), TeamTypeEnum.RED_TEAM.getCode()));
redisService.del(RedisKeyConstant.getPkContributionList(roomPKRequest.getRoomId(), TeamTypeEnum.BLUE_TEAM.getCode()));
//删除 红蓝队伍PK信息 //删除 红蓝队伍PK信息 getRedAndBluePkInformation(String crId)
redisService.remove(RedisKeyConstant.getRedAndBluePkInformation(roomPKRequest.getRoomId()), TeamTypeEnum.RED_TEAM.getCode());
redisService.remove(RedisKeyConstant.getRedAndBluePkInformation(roomPKRequest.getRoomId()), TeamTypeEnum.BLUE_TEAM.getCode());
//1.房间PK倒计时存到redis中以房间id进行区分
redisService.hSet(RedisKeyConstant.getRoomPkCountdown(), roomPKRequest.getRoomId(), String.valueOf(pkTimeCountdown));
//2.队伍PK总值根据房间id作为redis作为key 里面以队伍类型区分
//红队总PK值
redisService.incrScore(RedisKeyConstant.getRedAndBluePkInformation(roomPKRequest.getRoomId()), TeamTypeEnum.RED_TEAM.getCode(), 0);
//蓝队总PK值
redisService.incrScore(RedisKeyConstant.getRedAndBluePkInformation(roomPKRequest.getRoomId()), TeamTypeEnum.BLUE_TEAM.getCode(), 0);
//3.获取初始的PK总值
Double redTeamScore = redisService.score(RedisKeyConstant.getRedAndBluePkInformation(roomPKRequest.getRoomId()), TeamTypeEnum.RED_TEAM.getCode());
log.info("红队总PK值:{}" + redTeamScore);
Double blueTeamScore = redisService.score(RedisKeyConstant.getRedAndBluePkInformation(roomPKRequest.getRoomId()), TeamTypeEnum.BLUE_TEAM.getCode());
log.info("蓝队总PK值:{}" + blueTeamScore);
MqttRoomPkMsg roomPkMsg = new MqttRoomPkMsg();
roomPkMsg.setCountdown(pkTimeCountdown);
//红队
RedTeamDto redTeamDto = new RedTeamDto();
redTeamDto.setTotalPkValue(redTeamScore.longValue());
redTeamDto.setUserList(new ArrayList<>());
roomPkMsg.setRedTeamDto(redTeamDto);
//蓝队
BlueTeamDto blueTeamDto = new BlueTeamDto();
blueTeamDto.setTotalPkValue(blueTeamScore.longValue());
blueTeamDto.setUserList(new ArrayList<>());
roomPkMsg.setBlueTeamDto(blueTeamDto);
//时间格式化
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = df.format(new Date());
roomPkMsg.setTime(time);
//map转json
String sendMsg = JSONObject.toJSONString(roomPkMsg);
System.out.println(sendMsg);
MqttMessage mqttMessage = null;
try {
mqttMessage = new MqttMessage(sendMsg.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
mqttMessage.setQos(0);
System.out.println("时间戳" + System.currentTimeMillis());
//发起PK的房间
redisService.hSet(RedisKeyConstant.getRoomInitiatingPk(), djsChatRoom.getCrId(), djsChatRoom.getCrId());
//发送IM通知PK开始
//创建消息附件
ChatRoomPkMessage message = new ChatRoomPkMessage();
String url = host;
URI uri = URI.create(url);
String ip = uri.getHost();
int port = uri.getPort();
message.setUrl(url);
message.setHost(ip);
message.setPort(String.valueOf(port));
message.setUserName(username);
message.setPassword(password);
message.setTopic(MQTTTopicConstant.ROOM_PK_MESSAGE_TOPIC + roomPKRequest.getRoomId());
message.setPkTimeCountdown(pkTimeCountdown);
message.setIsPK(true);
NeteaseAttachDto neteaseAttachDto = new NeteaseAttachDto();
neteaseAttachDto.setType(NeteaseAttachTypeEnum.CHAR_ROOM_IS_PK.getCode());
neteaseAttachDto.setData(message);
//发送自定义云信消息 有座驾的是true 没有的用false
neteaseService.roomMessagePush(djsChatRoom.getNeteaseChatId(), user.getUserId(), NeteaseMsgTypeEnum.CUSTOM, neteaseAttachDto, "", true);
}
@Override
public List<RoomPkContributionResponse> roomPkContributionList(String roomId, String teamType) {
if (StringUtils.isEmpty(roomId)) {
Asserts.fail(ResultCode.ROOM_ID_CANNOT_BE_EMPTY);
}
if (StringUtils.isEmpty(teamType)) {
Asserts.fail(ResultCode.TEAM_TYPE_CANNOT_BE_EMPTY);
}
//房间PK贡献榜单列表
//根据房间id和队伍类型查询贡献值 最高的前三名用户信息
List<String> rankingList = new LinkedList<>();
List<RoomPkContributionResponse> roomPkContributionList = new ArrayList<>();
Set<ZSetOperations.TypedTuple<Object>> set = redisTemplate.opsForZSet().reverseRangeWithScores(RedisKeyConstant.getPkContributionList(roomId, teamType), 0, 2);
if (set == null || set.size() == 0) {
return roomPkContributionList;
}
for (ZSetOperations.TypedTuple<Object> objectTypedTuple : set) {
rankingList.add(String.valueOf(objectTypedTuple.getValue()));
RoomPkContributionResponse response = new RoomPkContributionResponse();
response.setUserId(String.valueOf(objectTypedTuple.getValue()));
response.setBoostValue(String.valueOf(objectTypedTuple.getScore()));
roomPkContributionList.add(response);
}
//根据获取到的用户查询用户信息
List<DjsUser> userList = feignUserService.selectByListId(ListIdRequest.builder().userIds(rankingList).build()).getData();
List<RoomPkContributionResponse> contributionResponses = roomPkContributionList.stream().peek(c -> {
DjsUser djsUser = userList.stream().filter(u -> Objects.equals(c.getUserId(), u.getUserId())).findFirst().orElse(new DjsUser());
c.setDisplayId(djsUser.getDisplayId());
c.setNickname(djsUser.getNickname());
c.setProfilePath(djsUser.getProfilePath());
}).collect(Collectors.toList());
return contributionResponses;
}
@Override
public InitiateRoomPKResponse queryRoomPkResults(String roomId) {
if (StringUtils.isEmpty(roomId)) {
Asserts.fail(ResultCode.ROOM_ID_CANNOT_BE_EMPTY);
}
//根据房间id查询获胜结果
//获胜方的最佳助攻
//todo 4.整合返回体数据信息返回给客户端
DjsChatRoom djsChatRoom = chatRoomDao.selectChatRoomById(roomId);
log.info("根据房间id查询房间信息:{}" + djsChatRoom);
if (Objects.isNull(djsChatRoom)) {
log.error("Chat room is null");
}
//房间麦克风的数量
int size;
if (djsChatRoom.getRoomTagCategory().equals(ChatRoomTypeEnum.GAME_ROOM.getCode())) {
size = 1;
} else {
size = 9;
}
//获取当前房间麦位的pk值
InitiateRoomPKResponse roomPKResponse = new InitiateRoomPKResponse();
//红队信息集合
RoomRedTeamDto redTeamDto = new RoomRedTeamDto();
//红队总PK值
Double redTeamScore = redisTemplate.opsForZSet().score(RedisKeyConstant.getRedAndBluePkInformation(roomId), TeamTypeEnum.RED_TEAM.getCode());
//红队总PK值
redTeamDto.setTotalPkValue(redTeamScore.longValue());
List<String> redTeaRankingList = new LinkedList<>();
List<RoomUserContributingDto> redTeaUserContributingDtoList = new ArrayList<>();
Set<ZSetOperations.TypedTuple<Object>> set = redisTemplate.opsForZSet().reverseRangeWithScores(RedisKeyConstant.getPkContributionList(roomId, TeamTypeEnum.RED_TEAM.getCode()), 0, 2);
if (set != null || set.size() != 0) {
for (ZSetOperations.TypedTuple<Object> objectTypedTuple : set) {
redTeaRankingList.add(String.valueOf(objectTypedTuple.getValue()));
RoomUserContributingDto response = new RoomUserContributingDto();
response.setUserId(String.valueOf(objectTypedTuple.getValue()));
response.setBoostValue(String.valueOf(objectTypedTuple.getScore()));
redTeaUserContributingDtoList.add(response);
}
//根据获取到的用户查询用户信息
List<DjsUser> redTeaUserList = feignUserService.selectByListId(ListIdRequest.builder().userIds(redTeaRankingList).build()).getData();
List<RoomUserContributingDto> redTeaContributionResponses = redTeaUserContributingDtoList.stream().peek(c -> {
DjsUser djsUser = redTeaUserList.stream().filter(u -> Objects.equals(c.getUserId(), u.getUserId())).findFirst().orElse(new DjsUser());
c.setDisplayId(djsUser.getDisplayId());
c.setNickname(djsUser.getNickname());
c.setProfilePath(djsUser.getProfilePath());
}).collect(Collectors.toList());
//todo 获取用户前三的数据信息
//红队的用户贡献榜单
redTeamDto.setUserList(redTeaContributionResponses);
//红队信息
roomPKResponse.setRedTeamDto(redTeamDto);
}
//蓝队信息集合
RoomBlueTeamDto blueTeamDto = new RoomBlueTeamDto();
//蓝队总PK值
Double blueTeamScore = redisTemplate.opsForZSet().score(RedisKeyConstant.getRedAndBluePkInformation(roomId), TeamTypeEnum.BLUE_TEAM.getCode());
//蓝队的总PK值
blueTeamDto.setTotalPkValue(blueTeamScore.longValue());
List<String> blueTeaRankingList = new LinkedList<>();
List<RoomUserContributingDto> blueTeaUserContributingDtoList = new ArrayList<>();
Set<ZSetOperations.TypedTuple<Object>> blueSet = redisTemplate.opsForZSet().reverseRangeWithScores(RedisKeyConstant.getPkContributionList(roomId, TeamTypeEnum.RED_TEAM.getCode()), 0, 2);
if (blueSet != null || blueSet.size() != 0) {
for (ZSetOperations.TypedTuple<Object> objectTypedTuple : blueSet) {
blueTeaRankingList.add(String.valueOf(objectTypedTuple.getValue()));
RoomUserContributingDto response = new RoomUserContributingDto();
response.setUserId(String.valueOf(objectTypedTuple.getValue()));
response.setBoostValue(String.valueOf(objectTypedTuple.getScore()));
blueTeaUserContributingDtoList.add(response);
}
//根据获取到的用户查询用户信息
List<DjsUser> blueTeaUserList = feignUserService.selectByListId(ListIdRequest.builder().userIds(blueTeaRankingList).build()).getData();
List<RoomUserContributingDto> blueTeaContributionResponses = blueTeaUserContributingDtoList.stream().peek(c -> {
DjsUser djsUser = blueTeaUserList.stream().filter(u -> Objects.equals(c.getUserId(), u.getUserId())).findFirst().orElse(new DjsUser());
c.setDisplayId(djsUser.getDisplayId());
c.setNickname(djsUser.getNickname());
c.setProfilePath(djsUser.getProfilePath());
}).collect(Collectors.toList());
//todo 获取用户前三的数据信息
//蓝队的用户贡献榜单
blueTeamDto.setUserList(blueTeaContributionResponses);
//蓝队信息
roomPKResponse.setBlueTeamDto(blueTeamDto);
}
//todo 获取用户前三的数据信息
if (redTeamScore.longValue() > blueTeamScore.longValue()) {
roomPKResponse.setVictoriousTeam("001");
} else if (redTeamScore.longValue() < blueTeamScore.longValue()) {
roomPKResponse.setVictoriousTeam("002");
} else if (redTeamScore.longValue() == blueTeamScore.longValue()) {
roomPKResponse.setVictoriousTeam("003");
} else {
roomPKResponse.setVictoriousTeam("004");
}
log.info("roomPKResponse的结果:{}" + roomPKResponse);
return roomPKResponse;
}
@Override
public Boolean endRoomPk(String roomId) {
if (StringUtils.isEmpty(roomId)) {
Asserts.fail(ResultCode.ROOM_ID_CANNOT_BE_EMPTY);
}
//结束PK
// todo 数据留存
//红队总PK值
//蓝队总PK值
//3.获取初始的PK总值
Double redTeamScore = redisService.score(RedisKeyConstant.getRedAndBluePkInformation(roomId), TeamTypeEnum.RED_TEAM.getCode());
log.info("红队总PK值:{}" + redTeamScore);
Double blueTeamScore = redisService.score(RedisKeyConstant.getRedAndBluePkInformation(roomId), TeamTypeEnum.BLUE_TEAM.getCode());
log.info("蓝队总PK值:{}" + blueTeamScore);
DjsRoomPkRecord roomPkRecord = new DjsRoomPkRecord();
String roomPkRecordId = cn.hutool.core.util.IdUtil.simpleUUID();
roomPkRecord.setRoomPkRecordId(roomPkRecordId);
roomPkRecord.setRedTeamRoomId(roomId);
roomPkRecord.setBlueTeamRoomId(roomId);
roomPkRecord.setPkType(PkTypeEnum.IN_ROOM_PK.getCode());
roomPkRecord.setRedTeamTotalPkValue(redTeamScore.longValue());
roomPkRecord.setBlueTeamTotalPkValue(blueTeamScore.longValue());
roomPkRecord.setCreateTime(new Timestamp(System.currentTimeMillis()));
Integer insertRoomPk = roomPkRecordDao.insertRoomPkRecord(roomPkRecord);
if (insertRoomPk < 0) {
//记录添加失败
Asserts.fail(ResultCode.INSERT_ERROR);
}
//红队贡献值前三的用户
//蓝队贡献值前三的用户
List<DjsRoomPkContributionList> roomPkContributionList = new ArrayList<>();
Set<ZSetOperations.TypedTuple<Object>> redTeamSet = redisTemplate.opsForZSet().reverseRangeWithScores(RedisKeyConstant.getPkContributionList(roomId, TeamTypeEnum.RED_TEAM.getCode()), 0, 2);
if (redTeamSet != null || redTeamSet.size() > 0) {
for (ZSetOperations.TypedTuple<Object> objectTypedTuple : redTeamSet) {
DjsRoomPkContributionList contribution = new DjsRoomPkContributionList();
contribution.setPkContributionRecordId(cn.hutool.core.util.IdUtil.simpleUUID());
contribution.setRoomPkRecordId(roomPkRecordId);
contribution.setTeamType(TeamTypeEnum.RED_TEAM.getCode());
contribution.setUserId(String.valueOf(objectTypedTuple.getValue()));
contribution.setBoostValue(objectTypedTuple.getScore().longValue());
contribution.setCreateTime(new Timestamp(System.currentTimeMillis()));
roomPkContributionList.add(contribution);
}
}
Set<ZSetOperations.TypedTuple<Object>> blueTeamSet = redisTemplate.opsForZSet().reverseRangeWithScores(RedisKeyConstant.getPkContributionList(roomId, TeamTypeEnum.BLUE_TEAM.getCode()), 0, 2);
if (blueTeamSet != null || blueTeamSet.size() > 0) {
for (ZSetOperations.TypedTuple<Object> objectTypedTuple : blueTeamSet) {
DjsRoomPkContributionList contribution = new DjsRoomPkContributionList();
contribution.setPkContributionRecordId(cn.hutool.core.util.IdUtil.simpleUUID());
contribution.setRoomPkRecordId(roomPkRecordId);
contribution.setTeamType(TeamTypeEnum.BLUE_TEAM.getCode());
contribution.setUserId(String.valueOf(objectTypedTuple.getValue()));
contribution.setBoostValue(objectTypedTuple.getScore().longValue());
contribution.setCreateTime(new Timestamp(System.currentTimeMillis()));
roomPkContributionList.add(contribution);
}
}
Integer insertRoomPkContribution = roomPkContributionListDao.insertRoomPkContributionList(roomPkContributionList);
if (insertRoomPkContribution < 0) {
//添加失败
Asserts.fail(ResultCode.INSERT_ERROR);
}
// todo 数据缓存清理
// 当前房间麦克风PK值(值为hash类型)
redisService.del(RedisKeyConstant.getChatRoomPkValueKey(roomId));
// 红蓝队伍PK信息
redisService.remove(RedisKeyConstant.getRedAndBluePkInformation(roomId), TeamTypeEnum.RED_TEAM.getCode());
redisService.remove(RedisKeyConstant.getRedAndBluePkInformation(roomId), TeamTypeEnum.BLUE_TEAM.getCode());
// 房间PK倒计时 (值为hash类型)
redisService.hDel(RedisKeyConstant.getRoomPkCountdown(),roomId);
// PK贡献榜
redisService.del(RedisKeyConstant.getPkContributionList(roomId, TeamTypeEnum.RED_TEAM.getCode()));
redisService.del(RedisKeyConstant.getPkContributionList(roomId, TeamTypeEnum.BLUE_TEAM.getCode()));
// 发起PK的房间
redisService.hDel(RedisKeyConstant.getRoomInitiatingPk(),roomId);
return true;
}
送礼
@Service
@Slf4j
@RocketMQMessageListener(consumerGroup = MQConsumerGroupConstant.INCREASE_CHAT_ROOM_PK_VALUE_MQ_GROUP, topic = MQTopicConstant.INCREASE_CHAT_ROOM_PK_VALUE_TOPIC)
public class ChatRoomPkValueMQConsumer extends AbstractMQConsumer {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private MicrophoneService microphoneService;
@Autowired
private ChatRoomDao chatRoomDao;
@Autowired
private NeteaseService neteaseService;
@Autowired
private MyMQTTClient myMQTTClient;
@Autowired
private FeignUserService feignUserService;
@Override
public void doService(String message) {
IncreaseMicrophoneCharmValueMQDto mqDto = JSONObject.parseObject(message, IncreaseMicrophoneCharmValueMQDto.class);
log.info("接收送礼mq消息,房间麦位PK值更新");
//送礼人id
String sourceUserId = mqDto.getSourceUserId();
log.info("送礼人id:{}"+sourceUserId);
//房间id
String chatRoomId = mqDto.getChatRoomId();
log.info("房间id:{}"+chatRoomId);
//收礼人信息
List<TargetUserGiftMQDto> targetUserGiftMQDtos = mqDto.getTargetUserGiftMQDtos();
log.info("收礼人信息:{}"+targetUserGiftMQDtos);
/**
* 更新麦位的PK值
*/
for (TargetUserGiftMQDto targetUserGiftMQDto : targetUserGiftMQDtos) {
Long totalValue = 0L;
log.info("初始化的礼物价值:{}"+totalValue);
List<GiftInfoMQDto> giftInfoMQDtos = targetUserGiftMQDto.getGiftInfoMQDtos();
log.info("第一个循环中收到礼物信息结果:{}"+giftInfoMQDtos);
for (GiftInfoMQDto giftInfoMQDto : giftInfoMQDtos) {
//循环累加礼物价值
totalValue = totalValue + giftInfoMQDto.getTotal() * giftInfoMQDto.getPrice();
log.info("循环累加礼物价值:{}"+totalValue);
}
log.info("累加之后的价值:{}"+totalValue);
//查询当前收礼人所在的麦克风序号
String microphoneNumber = microphoneService.getCurrentUserMicrophoneNumber(chatRoomId, targetUserGiftMQDto.getUserId());
log.info("查询当前收礼人所在的麦克风序号:{}"+microphoneNumber);
//todo 1.更新房间PK的麦位的PK值数据
//todo 2.更新房间PK的红蓝队伍的总PK值的数据信息
//todo 3.更行房间PK用户贡献榜单数据
if (StringUtils.isNotBlank(microphoneNumber) && MicroPhoneEnum.ONE.getCode().equals(microphoneNumber)
|| MicroPhoneEnum.TWO.getCode().equals(microphoneNumber)
|| MicroPhoneEnum.FIVE.getCode().equals(microphoneNumber)
|| MicroPhoneEnum.SIX.getCode().equals(microphoneNumber)) {
//根据麦位序号添加麦位PK值
log.info("红队-添加的麦位序号:{}"+microphoneNumber+ "红队-添加麦位PK值:{}"+totalValue.longValue());
redisTemplate.opsForHash().increment(RedisKeyConstant.getChatRoomPkValueKey(chatRoomId), microphoneNumber, totalValue.longValue());
//添加红队的PK总值
log.info("添加红队-的PK总值:{}"+totalValue.longValue());
redisTemplate.opsForZSet().incrementScore(RedisKeyConstant.getRedAndBluePkInformation(chatRoomId), TeamTypeEnum.RED_TEAM.getCode(), totalValue.longValue());
//红队贡献榜
log.info("红队-贡献榜助力用户id:{}"+sourceUserId+"红队-贡献榜助力值:{}"+totalValue.longValue());
redisTemplate.opsForZSet().incrementScore(RedisKeyConstant.getPkContributionList(chatRoomId, TeamTypeEnum.RED_TEAM.getCode()), sourceUserId, totalValue.longValue());
}
if (StringUtils.isNotBlank(microphoneNumber) && MicroPhoneEnum.THREE.getCode().equals(microphoneNumber)
|| MicroPhoneEnum.FOUR.getCode().equals(microphoneNumber)
|| MicroPhoneEnum.SEVEN.getCode().equals(microphoneNumber)
|| MicroPhoneEnum.EIGHT.getCode().equals(microphoneNumber)) {
log.info("蓝队-添加的麦位序号:{}"+microphoneNumber+ "蓝队-添加麦位PK值:{}"+totalValue.longValue());
redisTemplate.opsForHash().increment(RedisKeyConstant.getChatRoomPkValueKey(chatRoomId), microphoneNumber, totalValue.longValue());
//添加蓝队的PK总值
log.info("添加蓝队-的PK总值:{}"+totalValue.longValue());
redisTemplate.opsForZSet().incrementScore(RedisKeyConstant.getRedAndBluePkInformation(chatRoomId), TeamTypeEnum.BLUE_TEAM.getCode(), totalValue.longValue());
//蓝队贡献榜
log.info("蓝队-贡献榜助力用户id:{}"+sourceUserId+"蓝队-贡献榜助力值:{}"+totalValue.longValue());
redisTemplate.opsForZSet().incrementScore(RedisKeyConstant.getPkContributionList(chatRoomId, TeamTypeEnum.BLUE_TEAM.getCode()), sourceUserId, totalValue.longValue());
}
}
//todo 4.整合返回体数据信息返回给客户端
DjsChatRoom djsChatRoom = chatRoomDao.selectChatRoomById(chatRoomId);
log.info("根据房间id查询房间信息:{}"+djsChatRoom);
if (Objects.isNull(djsChatRoom)) {
log.error("Chat room is null");
}
//房间麦克风的数量
int size;
if (djsChatRoom.getRoomTagCategory().equals(ChatRoomTypeEnum.GAME_ROOM.getCode())) {
size = 1;
} else {
size = 9;
}
//获取当前房间麦位的pk值
MqttRoomPkMsg roomPkMsg = new MqttRoomPkMsg();
List<MicrophonePkValueDto> microphonePkValueDtoList = new ArrayList<>();
for (int i = 0; i < size; i++) {
MicrophonePkValueDto microphonePkValueDto = new MicrophonePkValueDto();
//opsForHash().get()获取的值类型不固定,会根据实际的值变化,有可能为Integer或Long等
Object value = redisTemplate.opsForHash().get(RedisKeyConstant.getChatRoomPkValueKey(chatRoomId), String.valueOf(i));
Long charmValue = 0L;
if (Objects.nonNull(value)) {
charmValue = Long.valueOf(value.toString());
}
microphonePkValueDto.setMicrophonePosition(i);
microphonePkValueDto.setMicrophonePkValue(charmValue);
microphonePkValueDtoList.add(microphonePkValueDto);
}
log.info("获取的麦位信息:{}"+microphonePkValueDtoList);
//获取房间PK的倒计时
Object roomPkCountdown = redisTemplate.opsForHash().get(RedisKeyConstant.getRoomPkCountdown(), chatRoomId);
log.info("redis中获取的倒计时:{}"+roomPkCountdown);
//麦位PK值信息
roomPkMsg.setMicrophonePkValueDtoList(microphonePkValueDtoList);
//倒计时
roomPkMsg.setCountdown(Long.valueOf(roomPkCountdown.toString()));
//红队信息集合
RedTeamDto redTeamDto = new RedTeamDto();
//红队总PK值
Double redTeamScore = redisTemplate.opsForZSet().score(RedisKeyConstant.getRedAndBluePkInformation(chatRoomId), TeamTypeEnum.RED_TEAM.getCode());
//红队总PK值
redTeamDto.setTotalPkValue(redTeamScore.longValue());
List<String> redTeaRankingList = new LinkedList<>();
List<UserContributingDto> redTeaUserContributingDtoList = new ArrayList<>();
Set<ZSetOperations.TypedTuple<Object>> set = redisTemplate.opsForZSet().reverseRangeWithScores(RedisKeyConstant.getPkContributionList(chatRoomId, TeamTypeEnum.RED_TEAM.getCode()), 0, 2);
if (set != null || set.size() != 0) {
for (ZSetOperations.TypedTuple<Object> objectTypedTuple : set) {
redTeaRankingList.add(String.valueOf(objectTypedTuple.getValue()));
UserContributingDto response = new UserContributingDto();
response.setUserId(String.valueOf(objectTypedTuple.getValue()));
response.setBoostValue(String.valueOf(objectTypedTuple.getScore()));
redTeaUserContributingDtoList.add(response);
}
//根据获取到的用户查询用户信息
List<DjsUser> redTeaUserList = feignUserService.selectByListId(ListIdRequest.builder().userIds(redTeaRankingList).build()).getData();
List<UserContributingDto> redTeaContributionResponses = redTeaUserContributingDtoList.stream().peek(c -> {
DjsUser djsUser = redTeaUserList.stream().filter(u -> Objects.equals(c.getUserId(), u.getUserId())).findFirst().orElse(new DjsUser());
c.setDisplayId(djsUser.getDisplayId());
c.setNickname(djsUser.getNickname());
c.setProfilePath(djsUser.getProfilePath());
}).collect(Collectors.toList());
//todo 获取用户前三的数据信息
//红队的用户贡献榜单
redTeamDto.setUserList(redTeaContributionResponses);
//红队信息
roomPkMsg.setRedTeamDto(redTeamDto);
}
//蓝队信息集合
BlueTeamDto blueTeamDto = new BlueTeamDto();
//蓝队总PK值
Double blueTeamScore = redisTemplate.opsForZSet().score(RedisKeyConstant.getRedAndBluePkInformation(chatRoomId), TeamTypeEnum.BLUE_TEAM.getCode());
//蓝队的总PK值
blueTeamDto.setTotalPkValue(blueTeamScore.longValue());
List<String> blueTeaRankingList = new LinkedList<>();
List<UserContributingDto> blueTeaUserContributingDtoList = new ArrayList<>();
Set<ZSetOperations.TypedTuple<Object>> blueSet = redisTemplate.opsForZSet().reverseRangeWithScores(RedisKeyConstant.getPkContributionList(chatRoomId, TeamTypeEnum.RED_TEAM.getCode()), 0, 2);
if (blueSet != null || blueSet.size() != 0) {
for (ZSetOperations.TypedTuple<Object> objectTypedTuple : blueSet) {
blueTeaRankingList.add(String.valueOf(objectTypedTuple.getValue()));
UserContributingDto response = new UserContributingDto();
response.setUserId(String.valueOf(objectTypedTuple.getValue()));
response.setBoostValue(String.valueOf(objectTypedTuple.getScore()));
blueTeaUserContributingDtoList.add(response);
}
//根据获取到的用户查询用户信息
List<DjsUser> blueTeaUserList = feignUserService.selectByListId(ListIdRequest.builder().userIds(blueTeaRankingList).build()).getData();
List<UserContributingDto> blueTeaContributionResponses = blueTeaUserContributingDtoList.stream().peek(c -> {
DjsUser djsUser = blueTeaUserList.stream().filter(u -> Objects.equals(c.getUserId(), u.getUserId())).findFirst().orElse(new DjsUser());
c.setDisplayId(djsUser.getDisplayId());
c.setNickname(djsUser.getNickname());
c.setProfilePath(djsUser.getProfilePath());
}).collect(Collectors.toList());
//todo 获取用户前三的数据信息
//蓝队的用户贡献榜单
blueTeamDto.setUserList(blueTeaContributionResponses);
//蓝队信息
roomPkMsg.setBlueTeamDto(blueTeamDto);
}
// //todo 获取用户前三的数据信息
//时间格式化
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = df.format(new Date());
roomPkMsg.setTime(time);
log.info("roomPkMsg的结果:{}"+roomPkMsg);
//map转json
String sendMsg = JSONObject.toJSONString(roomPkMsg);
log.info("roomPkMsg转成json的结果是"+sendMsg);
MqttMessage mqttMessage = null;
try {
mqttMessage = new MqttMessage(sendMsg.getBytes("UTF-8"));
mqttMessage.setQos(1);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
log.info("mqttMessage的结果:{}"+mqttMessage);
//发布消息 topic2 是你要发送到那个通道里面的主题 比如我要发送到topic2主题消息
try {
myMQTTClient.getClient().publish(MQTTTopicConstant.ROOM_PK_MESSAGE_TOPIC+chatRoomId, mqttMessage);
} catch (MqttException e) {
throw new RuntimeException(e);
}
log.info("时间戳" + System.currentTimeMillis());
}
}