引言

消息已读功能在现代应用程序中非常常见,它允许用户知道哪些消息已经被他们阅读过了。这对于保持沟通和信息同步至关重要。本文将介绍如何使用Java来实现消息已读功能,让我们开始吧!

java imap 过滤 未读邮件 java未读消息原理_java imap 过滤 未读邮件

技术栈

在实现消息已读功能之前,我们需要熟悉一些基本的技术栈:

  • Java编程语言
  • 数据库(MySQL)
  • Web框架(例如Spring Boot)

步骤

1. 设计数据库表,除了一些常规字段外,需要一个保存已读用户id的字段,可以使用mysql中的json类型,用户点击读操作后,将用户id存到对应消息中的已读用户字段中,查询未读信息时,如果该字段中没有当前用户id,则表明是未读信息,效果如下:

java imap 过滤 未读邮件 java未读消息原理_开发语言_02

建表语句如下,“消息开启时间”该字段是进行到点发送消息的关键字,未到时间用户不会收到该消息。

CREATE TABLE `notification` (
  `notification_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '消息id',
  `notification_type` tinyint(1) DEFAULT 1 COMMENT '消息类型(0-弹窗消息,1-普通消息)',
  `notification_title` varchar(255) DEFAULT NULL COMMENT '消息标题',
  `notification_content` longtext DEFAULT NULL COMMENT '消息内容',
  `notification_start` varchar(255) DEFAULT NULL COMMENT '消息开启时间',
  `is_active` tinyint(1) DEFAULT 0 COMMENT '消息状态 0开启,1关闭,默认开启',
  `created_date` datetime DEFAULT NULL COMMENT '创建时间',
  `updated_date` datetime DEFAULT NULL COMMENT '更新时间',
  `read_ids` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '已读用户id',
  PRIMARY KEY (`notification_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2. 创建Java实体类

在Java中,我们需要创建一个实体类来映射数据库表

@Data注解省去了大量的getter,setter方法

@Data
public class Notification implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId
    private Long notificationId;

    /**
     * 消息类型(0-弹窗消息,1-普通消息)
     */
    @ApiModelProperty("消息类型(0-弹窗消息,1-普通消息)")
    private Integer notificationType;

    /**
     * 消息标题
     */
    @ApiModelProperty("消息标题")
    private String notificationTitle;

    /**
     * 消息内容
     */
    @ApiModelProperty("消息内容")
    private String notificationContent;

    /**
     * 消息开启时间
     */
    @ApiModelProperty("消息开启时间")
    private String notificationStart;

    /**
     * 消息状态(0开启,1关闭)默认开启
     */
    @ApiModelProperty("消息状态(0开启,1关闭)默认开启")
    private Integer isActive;

    /**
     * 创建时间
     */
    private LocalDateTime createdDate;

    /**
     * 更新时间
     */
    private LocalDateTime updatedDate;
}
3. 实现已读标记逻辑

新增消息,编辑消息等CRUD操作就不展示了,CV工程师必备技能。着重于已读功能实现

接下来,我们需要在Java中编写代码来实现消息的已读标记逻辑。首次阅读后将用户id存到数据库 中。这里主要展示对应的sql语句,controller,service层逻辑清晰,逐层调用暂不展示,sql如下,

userId就是前端传来的用户id参数,notificationId也是前端传来的消息id,后面做了重复添加消息的检测,如果已经存在该用户Id不会继续保存,也就是只有首次阅读时会添加id,后面再次阅读不会有影响。

<insert id="saveReadUser">
        UPDATE notification
        SET read_ids = JSON_ARRAY_APPEND(read_ids, '$', #{userId})
        WHERE notification_id = #{notificationId}
        and not JSON_CONTAINS(read_ids, JSON_ARRAY(#{userId}));
    </insert>
4. 获取全部消息

该部分就是全量查询数据库表中消息已到展示时间的数据,service实现类代码如下,

@Override
    public Map<String,Object> getNotification(Long userId) {
        //查找已读消息
        List<NotificationVo> readNotification = notificationMapper.getNotification(userId, 1);
        //查找未读消息
        List<NotificationVo> notReadnotification = notificationMapper.getNotification(userId, 0);

        HashMap<String,Object> notificationHashMap = new HashMap<>();
        notificationHashMap.put("read",readNotification);
        notificationHashMap.put("notRead",notReadnotification);
        return notificationHashMap;
    }

对应的sql语句如下,用isRead字段标识1查询已读消息,标识0查询未读消息

<select id="getNotification" resultType="com.jxepro.clinflash.notification.enity.vo.NotificationVo">
        <if test="isRead == 0">
            select * from notification n where not JSON_CONTAINS(n.read_ids, JSON_ARRAY(#{userId}))
        </if>
        <if test="isRead == 1">
            select * from notification n where JSON_CONTAINS(n.read_ids, JSON_ARRAY(#{userId}))
        </if>
        and
        n.notification_start  <= NOW()
        and
        n.is_active = 0;
    </select>
5.对获取道德消息列表进行处理

上面查询到了所有已读和未读的消息,现在前端反馈数据过于混乱,要求整理的更人性化些!只能用摸鱼的时间修改下代码了。

在原有数据的基础上,增加一个已读未读标识,并将是所有消息按照时间排序,代码如下

在原实体类上加入该字段,方便前端对数据进行二次处理。

/**
     * 是否已读 0-未读,1-已读
     */
    private Integer status;
  1. 修改后的业务处理逻辑代码如下:将未读消息,已读消息配置好相应的字段,再合到一起根据时间排序,另外也将未读消息排序单独作为一个列表返回,仁至义尽了,爱咋咋吧。
@Override
    public Map<String,Object> getNotification(Long userId) {
        //查找已读消息
        List<NotificationVo> readNotification = notificationMapper.getNotification(userId, 1);
        //查找未读消息
        List<NotificationVo> notReadnotification = notificationMapper.getNotification(userId, 0);
        for(NotificationVo notificationVo : readNotification){
            //标记为已读
            notificationVo.setStatus(1);
        }
        for(NotificationVo notificationVo:notReadnotification){
            notificationVo.setStatus(0);
        }
        notReadnotification.sort(new Comparator<NotificationVo>() {
            @Override
            public int compare(NotificationVo notification1, NotificationVo notification2) {
                int startComparison = notification2.getNotificationStart().compareTo(notification1.getNotificationStart());
                if (startComparison != 0) {
                    return startComparison; // 按照notificationStart倒序排序
                } else {
                    return notification2.getCreatedDate().compareTo(notification1.getCreatedDate()); // 按照createtime倒序排序
                }
            }
        });
        ArrayList<NotificationVo> mergedNotifications = new ArrayList<>();
        //全部消息(已读和未读)
        mergedNotifications.addAll(readNotification);
        mergedNotifications.addAll(notReadnotification);
        mergedNotifications.sort(new Comparator<NotificationVo>() {
            @Override
            public int compare(NotificationVo notification1, NotificationVo notification2) {
                int startComparison = notification2.getNotificationStart().compareTo(notification1.getNotificationStart());
                if (startComparison != 0) {
                    return startComparison; // 按照notificationStart倒序排序
                } else {
                    return notification2.getCreatedDate().compareTo(notification1.getCreatedDate()); // 按照createtime倒序排序
                }
            }
        });
        HashMap<String,Object> notificationHashMap = new HashMap<>();
        notificationHashMap.put("all",mergedNotifications);
        notificationHashMap.put("notRead",notReadnotification);
        return notificationHashMap;
    }

斯古一,前端联调完成,打到测试验收,准备摸鱼。什么,又又又有新需求,累了毁灭吧。