JavaWeb开发--简易论坛--3系统通知--3.1发布系统通知和显示系统通知

简易论坛–发布系统通知和显示系统通知

1、思路

触发事件

  • 评论后,发布通知
  • 点赞后,发布通知
  • 关注后,发布通知

处理事件

  • 封装事件对象
  • 开发事件的生产者
  • 开发事件的消费者

通知列表

  • 显示评论、点赞、关注三种类型的通知

通知详情

  • 分页显示某一类主题所包含的通知

未读消息

  • 在页面头部显示所有的未读消息数量

2、使用技术或方法

mybatis,依赖注入,SpringMVC,MVC,thymeleaf,redis,Kafka

3、关键代码

3.1、关键类

KafkaTemplate

3.2、关键逻辑

//事件生产者
//Event 类是普通的Java类(自己编写),保存事件信息
@Component
public class EventProducer {

    @Autowired
    private KafkaTemplate kafkaTemplate;

    // 处理事件
    public void fireEvent(Event event) {
        // 将事件发布到指定的主题
        //end方法就是向指定的topic队列中发送一个消息,这里我们发送的是event对象转成json之后的字符串
        kafkaTemplate.send(event.getTopic(), JSONObject.toJSONString(event));
    }

}
//事件消费者
@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();
        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.setContent(JSONObject.toJSONString(content));
        messageService.addMessage(message);
    }
}
    @Autowired
    private EventProducer eventProducer;
 // 触发评论事件
        Event event = new Event()
                .setTopic(TOPIC_COMMENT)
                .setUserId(hostHolder.getUser().getId())
                .setEntityType(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);
//拦截器--调用controller之前
@Component
public class MessageInterceptor implements HandlerInterceptor {
    @Autowired
    private HostHolder hostHolder;

    @Autowired
    private MessageService messageService;

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        User user = hostHolder.getUser();
        if (user != null && modelAndView != null){
            int letterUnreadCount = messageService.findLetterUnreadCount(user.getId(),null);
            int noticeUnreadCount = messageService.findNoticeUnreadCount(user.getId(),null);
            modelAndView.addObject("allUnreadCount",letterUnreadCount+noticeUnreadCount);
        }
    }
}

4、扩展

1、阻塞队列
a.BlockingQueue(接口)
解决线程通信的问题。
阻塞方法:put、take。
b.生产者消费者模式
生产者:产生数据的线程。
消费者:使用数据的线程。
c.实现类
ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue、DelayQueue等。

2、 Kafka入门
a.Kafka简介
Kafka是一个分布式的流媒体平台。
应用:消息系统、日志收集、用户行为追踪、流式处理。
b.Kafka特点
高吞吐量、消息持久化(把数据存在硬盘里(顺序读取))、高可靠性(分布式)、高扩展性(可加服务器)。
c.Kafka术语
Broker(一个服务器)、Zookeeper(分布式协同管理)、Topic(存放消息的位置)、Partition(主题位置的分区)、Offset(消息在分区里面的序列)、Leader Replica(主副本,负责处理 )、Follower Replica(从副本,只是备份不做处理)
d.消息队列的两种方式

点对点–>BlockingQueue,
发布定位模式(把消息放到了某个位置,消费者可以订阅这个位置,读取消息)–>Kafka)

3、访问Kafka

  • 生产者
    kafkaTemplate.send(topic, data);
  • 消费者
    @KafkaListener(topics = {“test”})
    public void handleMessage(ConsumerRecord record) {}

5、注意点

  • 注意该种方法并不能让消费者实时消费

6、后续优化

6.1、优化思路

6.2、优化点

你可能感兴趣的:(JavaWeb开发)