为了账号安全,请及时绑定邮箱和手机立即绑定

【九月打卡】第10天 查询用户动态

标签:
Java

一、课程介绍
【课程名称】SpringBoot 2.x 实战仿B站高性能后端项目。
【章节】第三章3.29、3.30、3.31 生产消费动态,查询用户动态
【讲师】HELLOSTAR

二、课程内容
使用场景:
视频主发布动态之后,所有关注该视频主的用户都能得到消息推送。

实现逻辑:
----使用redis数据库的hash存储每个用户的所有订阅动态。每个用户的key为“subscribed”+用户id,value为用户动态集合;
----视频主发布动态之后,使用MQ的生产者发送该动态消息,消费者消费消息,并将该动态添加到每个粉丝在redis中存储的订阅动态集合中。保证Redis中存储的始终是用户当前所有的订阅动态。

  1. 新增用户动态
    在用户动态表(userMoments)中插入一条数据,包含视频主用户id,动态内容,发布时间等信息。
    调用默认配置的生产者(分组已命名),使用MQ发送一条消息。

    public void addUserMoments(UserMoment userMoment) throws Exception {
        userMoment.setCreateTime(new Date());
        userMomentsDao.addUserMoments(userMoment);
        DefaultMQProducer producer = (DefaultMQProducer)applicationContext.getBean("momentsProducer");
        Message msg = new Message(UserMomentsConstant.TOPIC_MOMENTS, JSONObject.toJSONString(userMoment).getBytes(StandardCharsets.UTF_8));
        RocketMQUtil.syncSendMsg(producer, msg);
    }
    
  2. 消费用户动态
    消费者的消息监听器一旦监听到生产者(相同分组中的)有消息发送,在消息监听器中获取到信息。
    使用json工具类将消息装换成userMoments类型。获取发布消息的用户id;
    得到该用户的所有粉丝,将该动态userMoments作为值存入到该用户的消息通知队列中。
    使用redis来存储每个用户的通知消息队列,key为“subscribed”+用户id,value为需要通知的动态集合。

    //消费者
    @Bean("momentsConsumer")
    public DefaultMQPushConsumer momentsConsumer() throws Exception{
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(UserMomentsConstant.GROUP_MOMENTS);
        consumer.setNamesrvAddr(nameServerAddr);
        consumer.subscribe(UserMomentsConstant.TOPIC_MOMENTS, "*");
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context){
                //获取消息
                MessageExt msg = msgs.get(0);
                if(msg == null){
                    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                }
                String bodyStr = new String(msg.getBody());
                //解析消息中的用户动态
                UserMoment userMoment = JSONObject.toJavaObject(JSONObject.parseObject(bodyStr), UserMoment.class);
                Long userId = userMoment.getUserId();
                List<UserFollowing>fanList = userFollowingService.getUserFans(userId);
                for(UserFollowing fan : fanList){
                    String key = "subscribed-" + fan.getUserId();
                    //1.得到该粉丝目前的所有消息
                    String subscribedListStr = redisTemplate.opsForValue().get(key);
                    List<UserMoment> subscribedList;
                    if(StringUtil.isNullOrEmpty(subscribedListStr)){
                        subscribedList = new ArrayList<>();
                    }else{
                        subscribedList = JSONArray.parseArray(subscribedListStr, UserMoment.class);
                    }
                    //2.加入新消息
                    subscribedList.add(userMoment);
                    //3.将最新的所有消息保存在Redis中
                    redisTemplate.opsForValue().set(key, JSONObject.toJSONString(subscribedList));
                }
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        consumer.start();
        return consumer;
    }
    
    
  3. 查询订阅动态
    获取当前用户id,拼接redis中保存用户通知消息的key。根据key查询得到的value即是当前用户订阅的动态集合。

    public List<UserMoment> getUserSubscribedMoments(Long userId) {
        String key = "subscribed-" + userId;
        String listStr = redisTemplate.opsForValue().get(key);
        return JSONArray.parseArray(listStr, UserMoment.class);
    }
    

三、课程收获
开发实现MQ中简单的消息生产和消费的过程。没有使用中间代理来转发消息。

四、学习过程
图片描述
图片描述

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消