MQTT搭建及相关逻辑

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());


    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值