定义对象,封装事件发生时候的一切信息。
1.在entity下新建 event事件,以封装事件对象
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;//记录实体id
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.put(key, value);
return this;
}
}
2.开发事件的消费者
新建event包,在该包下新建EventProducer
package com.nowcoder.community.event;
import com.alibaba.fastjson.JSONObject;
import com.nowcoder.community.entity.Event;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;
@Component
public class EventProducer {
@Autowired
private KafkaTemplate kafkaTemplate;
// 处理事件
public void fireEvent(Event event) {
// 将事件发布到指定的主题
kafkaTemplate.send(event.getTopic(), JSONObject.toJSONString(event));//消息的内容是JSON 字符串
}
}
3有了生产者再去开发消费者
新建EventConsumer类
先在CommunityConstant 中新建几个主题常量
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 handleCommentMessage(ConsumerRecord record) {
if (record == null || record.value() == null) {
logger.error("消息的内容为空!");//记录日志
return;
}
Event event = JSONObject.parseObject(record.value().toString(), Event.class);//将消息的内容(json字符串) 恢复成 消息字符串
if (event == null) {
logger.error("消息格式错误!");//有值,但是没有还原成功
return;
}
// 发送站内通知,构造message数据,发送到message表里
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());
//这个content就是
if (!event.getData().isEmpty()) {//判断事件对象中map有无值,event不为空,则将其中所有数据存到content字段中。
for (Map.Entry<String, Object> entry : event.getData().entrySet()) {
content.put(entry.getKey(), entry.getValue());
}
}
message.setContent(JSONObject.toJSONString(content));//该JSON字符串是拼 这句话的各种条件
messageService.addMessage(message);
}
}
通知的形式特别相近,因此逻辑相近:
content就是如下这句话:
在评论、点赞、关注之后调用
在CommentController中
@Autowired
private EventProducer eventProducer;
在addComment后添加:
// 触发评论事件
Event event = new Event()//构造事件对象,把事件包含的内容包含进来。
.setTopic(TOPIC_COMMENT)
.setUserId(hostHolder.getUser().getId())//当前登录的人
.setEntityType(comment.getEntityType())
.setEntityId(comment.getEntityId())
.setData("postId", discussPostId);//传一个帖子id,以连接到地址
//实体的作者
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;
在commentMapper中添加:
在commentService中添加:
在LikeController中添加
// 触发点赞事件
if (likeStatus == 1) {//只有点赞的时候触发系统通知,取消点赞不会触发。满足if则是点赞
Event event = new Event()
.setTopic(TOPIC_LIKE)
.setUserId(hostHolder.getUser().getId())
.setEntityType(entityType)
.setEntityId(entityId)
.setEntityUserId(entityUserId)
.setData("postId", postId);
eventProducer.fireEvent(event);
}
return CommunityUtil.getJSONString(0, null, map);
}
在FollowController添加:
// 触发关注事件
Event event = new Event()
.setTopic(TOPIC_FOLLOW)
.setUserId(hostHolder.getUser().getId())
.setEntityType(entityType)
.setEntityId(entityId)
.setEntityUserId(entityId);
eventProducer.fireEvent(event);
return CommunityUtil.getJSONString(0, "已关注!");
}
所以最后链接到某人的主页上,张三关注了我,那么最后链接到张三的主页上
在discuss-detail.html中
测试:
对某帖子评论:
然后查询message表格:
点赞后接着看:
接着点赞:
只不过类型不一样:
进行关注:
表里的数据:
附:message表格式如下: