5.4发送系统通知

在这里插入图片描述
拼一个对象,触发事件,处理事件。面向事件编程。
Entity实体类中编写消费者和生产者
创建event包,专门处理,里面的eventproducer发送消息,eventconsumer处理消息
Eventconsumer中,把从producer那边拿到的消息进行内容和格式的判断,之后发送站内通知,先设置发送者和接受者,为了获得发送的消息的具体内容,发送的消息的内容需要拼出,创这个hashmap(content),从event里面获取内容装进去,构造好消息,最后用messageservice塞进去
给响应的controller调用eventproducer,产生通知。

开发流程

event实体类,要做一定的处理,方便之后设置参数

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<>(); //其他不知道的属性存在这个map里面。让其具有扩展性。

        //对下面的set和get进行改造
        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.put(key, value);
        return this;
    }
}

EventProducer


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

    //处理事件
    public void fireEvent(Event event){
        //将事件发布到指定的主题
        kafkaTemplate.send(event.getTopic(), JSONObject.toJSONString(event));//消息内容变化为JSON格式

    }
}

EventConsumer

@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 message = new Message();
        message.setFromId(SYSTEM_USER_ID);//是系统发送通知
        message.setToId(event.getEntityUserId()); //发送给的人的ID
        message.setConversationId(event.getTopic());
        message.setCreateTime(new Date());

        //构造的具体的通知内容,最后存成json字符串传出去
        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());//把event中的其他数据在存到content中
            }
        }

        message.setContent(JSONObject.toJSONString(content));
        messageService.addMessage(message);
    }
}

在Comment和Like、Follow的controller中增加发送消息的逻辑

    @RequestMapping(path = "/add/{discussPostId}",method = RequestMethod.POST)
    public String addComment(@PathVariable("discussPostId") int discussPostId, Comment comment){
        comment.setUserId(hostHolder.getUser().getId()); //后面做统一异常的处理(这里可能会有未登录的错误)
        comment.setStatus(0);
        comment.setCreateTime(new Date());
        commentService.addComment(comment);

        //添加评论后通知
        //触发评论事件
        Event event = new Event()
                .setTopic(TOPIC_COMMENT)
                .setUserId(hostHolder.getUser().getId())
                .setEntityId(comment.getEntityType())
                .setEntityId(comment.getEntityId())
                .setData("postId",discussPostId);
        if (comment.getEntityType() == ENTITY_TYPE_POST){
            DiscussPost target = discussPostService.findDiscussPostById(comment.getEntityId());
            event.setEntityUserId(target.getUserId());
        }else if (comment.getEntityType() == ENTITY_TYPE_COMMENT){
            Comment target = commentService.findCommentById(comment.getEntityId());
            event.setEntityUserId(target.getUserId());
        }

        //设置全了,就发送消息
        eventProducer.fireEvent(event);

        return "redirect:/discuss/detail/"+discussPostId;
    }

这里在Like方法中多增加了一个postId的参数,所以要在前端页面进行修改,多传一个属性进来。记得js文件也要修改

<a href="javascript:;" th:οnclick="|like(this,2,${cvo.comment.id},${cvo.comment.userId},${post.id})
        //触发点赞事件
        if (likeStatus == 1){
            //当前逻辑是点赞,才触发事件
            Event event = new Event()
                    .setTopic(TOPIC_LIKE)
                    .setEntityType(entityType)
                    .setEntityId(entityId)
                    .setEntityUserId(entityUserId)
                    .setData("postId",postId);
            eventProducer.fireEvent(event);

        }

        //触发通知
        Event event = new Event()
                .setTopic(TOPIC_FOLLOW)
                .setUserId(user.getId())
                .setEntityType(entityType)
                .setUserId(entityId)
                .setEntityUserId(entityId);
        eventProducer.fireEvent(event);

最后测试的坑:


        //之前我们所有对service的访问请求都是通过controller访问的,
        //现在我们使用consumer去调用的service,这次调用里就没有request,就会出现空指针异常
        if (attributes == null){
            return;
        }
        HttpServletRequest request = attributes.getRequest();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值