优化项目使用kafka发送系统通知

目录

为什么使用kafka?

Springboot整合Kafka

创建发送事件实体Event

创建生产者

创建消费者

最后在controller层


为什么使用kafka?

kafka是一个吞吐量分布式的发布订阅消息系统。可以处理消费者在网站上所有动作流的数据。

用户在给其他人点赞,关注,评论的时候,kafka可以记录下来。将点赞,关注,评论看成一个事件的发生。用户 点赞了以后,需要有消息通知,所以可以用kafka来发送消息,用户在点赞之后,kafka将这个事件发送到消息队列中,然后由生产者自行取数据。

Springboot整合Kafka

在项目中使用kafka,首先我们的Springboot先得整合kafka

关于如何整合Kafka可以看这个

整合以后我们就需要进行代码编写了。

创建发送事件实体Event

我们要向队列传送的数据可以封装在Event实体中

Map类型的data是为了防止以后业务有变,我们需要增加数据类型,这样就可以将他们封装在map中。

!set方法 进行修改,本来没有返回值的,但是我们可以写一个返回值

这样可以提高代码的灵活性,因为我们set了一个值以后可以返回这个对象,然后可以继续set其他属性。

为什么不用构造器呢?因为我们的属性是不确定的,而我们修改属性的时候不一定会修改哪几个属性,这样我们就需要写很多个构造器,灵活性降低。

package com.nowcoder.community.entity;

import java.util.HashMap;
import java.util.Map;

public class Event {

    private String topic;
    private int userId;
    private int entityType;
    private int entityId;
    private int entityUserId;
    private Map<String, Object> data = new HashMap<>();

    public String getTopic() {
        return topic;
    }

    public Event setTopic(String topic) {
        this.topic = topic;
        return this;
    }

    public int getUserId() {
        return userId;
    }

    public Event setUserId(int userId) {
        this.userId = userId;
        return this;
    }

    public int getEntityType() {
        return entityType;
    }

    public Event setEntityType(int entityType) {
        this.entityType = entityType;
        return this;
    }

    public int getEntityId() {
        return entityId;
    }

    public Event setEntityId(int entityId) {
        this.entityId = entityId;
        return this;
    }

    public int getEntityUserId() {
        return entityUserId;
    }

    public Event setEntityUserId(int entityUserId) {
        this.entityUserId = entityUserId;
        return this;
    }

    public Map<String, Object> getData() {
        return data;
    }

    public Event setData(String key,Object value) {
        this.data = data;
        return this;
    }
}

创建生产者

当我们使用KafkaTemplate的实体kafkaTemplate发送事件的时候,我们需要发送的是一个事件对象,但是需要传输的是一个字符串类型,怎么做呢,只需要将事件类型的对象通过JSON转换为一个JSON字符串。

@Component
public class EventProducer {
    @Autowired
    private KafkaTemplate kafkaTemplate;

    //处理事件  将事件发送到指定主题
    public void fireEvent(Event event){
        kafkaTemplate.send(event.getTopic(), JSONObject.toJSONString(event));
    }



}

创建消费者

消费者需要对消息进行消费,然后将内容包装到message中(所有数据,包括额外数据)

package com.nowcoder.community.event;

import com.alibaba.fastjson.JSONObject;
import com.nowcoder.community.entity.Event;
import com.nowcoder.community.entity.Message;
import com.nowcoder.community.service.MessageService;
import com.nowcoder.community.util.CommunityConstant;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@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 TOPIC_FOLLOW(ConsumerRecord record){
        if (record == null || record.value() == null){
            logger.error("消息的内容为空!");
            return;
        }



        //将事件从json转为对象
        Event event = JSONObject.parseObject(record.value().toString(), Event.class);

       if (event == null){
           logger.error("消息格式错误");
           return;
       }

       //传过来的消息没有问题,接下来就是对消息的消费。
        // 发送站内通知
        Message message = new Message();
        message.setFromId(SYSTEM_USER_ID);
        message.setToId(event.getEntityUserId());
        message.setConversationId(event.getTopic());
        message.setCreateTime(new Date());

        //需要的额外数据
        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());
            }
        }

        //将内容包装到message中
        message.setContent(JSONObject.toJSONString(content));
        messageService.addMessage(message);
    }

}

最后在controller层

在这一层中加入逻辑就好了。

就像这样的

    // 触发关注事件
        Event event = new Event()
                .setTopic(TOPIC_FOLLOW)
                .setUserId(hostHolder.getUser().getId())
                .setEntityType(entityType)
                .setEntityId(entityId)
                .setEntityUserId(entityId);
        eventProducer.fireEvent(event);
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值