仿牛客社区项目笔记-构建TB级异步消息系统(引入Kafka)

仿牛客社区项目笔记-构建TB级异步消息系统(引入Kafka)

  • 1. 构建TB级异步消息系统
    • 1.1 引入Kafka
    • 1.2 Spring 整合 Kafka
    • 1.3 发送系统通知
    • 1.4 显示系统通知
      • 1.4.1 点击系统通知
      • 1.4.2 系统通知详情页面

1. 构建TB级异步消息系统

分为引入Kafka,Spring 整合 Kafka,发送系统通知和显示系统通知。

1.1 引入Kafka

  1. 在 Kafka.apach.org 安装 kafka 压缩包,解压缩。
  2. 更改 config 目录下 zookeeper.properties 和 server.properties 下的 /temp 路径,改为硬盘下路径。
  3. Kafka简介:其中broker是kafka的集群服务器,而zookeeper是管理集群的。topic是存放消息的空间,partition是topic的分区。

仿牛客社区项目笔记-构建TB级异步消息系统(引入Kafka)_第1张图片

1.2 Spring 整合 Kafka

  1. 导入 Spring-kafka 依赖。
  2. 在 application.properties 中设置配置。
  3. 在使用 kafka 前要使用命令行打开 zookeeper 和 kafka,命令为:

cd idea/kafka/kafka_2.12-3.1.0
E:\IDEA\kafka\kafka_2.12-3.1.0>bin\windows\zookeeper-server-start.bat config\zookeeper.properties
E:\IDEA\kafka\kafka_2.12-3.1.0>bin\windows\kafka-server-start.bat config\server.properties

1.3 发送系统通知

  1. 构建事件 Event 实体类。包含字段:

private String topic; // 存放消息空间
private int userId; // 触发事件用户id
private int entityType; // 事件目标类型
private int entityId; // 事件目标id
private int entityUserId ;// 事件目标所有者id
private Map data = new HashMap<>(); // 其他

  1. 在 event 文件夹下构建 EventProducer 类,调用 KafkaTemplate 将事件发布到指定的主题。
@Component
public class EventProducer {

    @Autowired
    private KafkaTemplate kafkaTemplate;
    
    // 处理事件
    public void fireEvent(Event event) {
        // 将事件发布到指定的主题
        kafkaTemplate.send(event.getTopic(), JSONObject.toJSONString(event));
    }
}
  1. 在 event 文件夹下构建 EventConsumer 类,监听三种类型topic,即:评论,点赞,关注。根据收到的 event 构建 message 对象,使用 messageService 插入数据库。
@Component
public class EventConsumer implements CommunityConstant {

    private static final Logger logger = LoggerFactory.getLogger(EventConsumer.class);

    @Autowired
    private MessageService messageService;

    @KafkaListener(topics = {TOPIC_COMMENT, TOPIC_LIKE, TOPIC_FOLLOW})
    public void handleCommentMessage(ConsumerRecord record) {
        if (record == null || record.value() == null) {
            logger.error("消息的内容为空!");
            return;
        }

        Event event = JSONObject.parseObject(record.value().toString(), Event.class);
        if (event == null) {
            logger.error("消息格式错误!");
            return;
        }

        // 发送站内通知
        Message message = new Message();
        // 系统发送 设为 1
        message.setFromId(SYSTEM_USER_ID);
        message.setToId(event.getEntityUserId());
        // ConversationId 设为 topic。
        message.setConversationId(event.getTopic());
        message.setCreateTime(new Date());
        
        // message 的 content 
        Map<String, Object> content = new HashMap<>();
        content.put("userId", event.getUserId());
        content.put("entityType", event.getEntityType());
        content.put("entityId", event.getEntityId());

        if (!event.getData().isEmpty()) {
            for (Map.Entry<String, Object> entry : event.getData().entrySet()) {
                content.put(entry.getKey(), entry.getValue());
            }
        }
        
        // 保存为 json 字符串
        message.setContent(JSONObject.toJSONString(content));
        messageService.addMessage(message);
    }
}
  1. 在评论,点赞,关注时加入触发事件代码。在 帖子模块(核心)1.5小节:CommentController,点赞关注模块(引入Redis)1.2小节:LikeController,点赞关注模块(引入Redis)1.4.1小节:FollowController中加入相应代码,即构建event并且调用 eventProducer 发布事件。

1.4 显示系统通知

1.4.1 点击系统通知

  1. 点击消息内的系统通知,映射到 MessageController 中的 /notice/list。会分别显示评论,赞,关注三类通知的一个最新消息。
  2. 以评论为例:会调用 messageService.findLatestNotice 方法查询到最近的评论通知,将 message 中的 content 反html转义后从json转为map对象,然后将各种信息传入返回给浏览器的map,同时在该map中装入评论通知总数和未读评论通知数。然后将map装入model返回给浏览器。
  3. 赞和关注模块同样如上。最后再将所有的未读数量查询出,装入model。

1.4.2 系统通知详情页面

  1. 点击评论,赞,关注三类通知的某一类通知,会映射到 MessageController 层的 /notice/detail/{topic}。设置分页信息。通过 messageService.findNotices 方法查询通知列表。
  2. 将列表中每个message装入map,并且将每个message中的content反转义并且从json转换为map,将该map中的信息装入返回给浏览器的map。将每个map装入list,将list装入model。
  3. 使用 messageService.readMessage 方法将列表中的 message 设置为已读。
  4. 返回 /site/notice-detail。

最后使用 MessageInterceptor 拦截器查询出私信未读数量和系统通知未读数量,将其加和放入modelAndView,在顶部栏的消息上显示总的未读数量。

你可能感兴趣的:(仿牛客社区项目笔记,kafka,java,分布式)