Spring Boot 站内信的设计与实现

什么是站内信

在WEB系统中,站内信相当于是一个托管在服务器上的轻量邮局,它可以从WEB系统或者是用户获取信息并发送给指定的用户或者是用户群体。

站内信的类型

据我所知,当前实现站内信的方式主要通过两种:

  • 通过Websocket来进行实现

  • 通过纯数据库来进行实现

同时,基础的站内信一般都会实现两大功能,点到点的消息传送,点到面的消息传送

点到点的消息传送

点到点的消息传送,类似于我们关系型数据库所讲的一对一关系,也就是说,用户可以对用户进行消息的投递,或者是说用户对管理员进行消息的投递

点到面的消息传送

点到面的消息传送,类似于关系型数据库所说的一对多关系,web后台对应多个用户,也就是说,web后台可以对多个用户(用户群)进行群发消息通知

站内信的应用场景

  • 通知公告

  • 营销类活动

  • 相关的信息通知

  • 用户之间的互动

  • 订阅信息
    ......

站内信的设计

在这里我们暂且只介绍下数据库的后端实现步骤,下次有机会的话介绍websocket方式

前端方面就靠你们自己吧

数据库

我们通过两张表实现,新建inner_messageinner_message_text

CREATE TABLE `inner_message_text` (
  `id` varchar(255) NOT NULL COMMENT '站内信内容id',
  `sendId` int(255) unsigned DEFAULT NULL COMMENT '发信者id',
  `content` text NOT NULL COMMENT '信件内容',
  `groupId` int(2) unsigned DEFAULT NULL COMMENT '群发站内消息用 0->群发用户组 1->群发管理组',
  `type` int(1) NOT NULL COMMENT '0 -> 系统消息 , 1 -> 私信 , 2 -> 站内通知',
  `postDate` datetime NOT NULL COMMENT '发信时间',
  PRIMARY KEY (`id`),
  KEY `suid` (`sendId`),
  KEY `groupId` (`groupId`),
  CONSTRAINT `groupId` FOREIGN KEY (`groupId`) REFERENCES `user` (`groupId`),
  CONSTRAINT `suid` FOREIGN KEY (`sendId`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `inner_message` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `getUid` int(255) unsigned NOT NULL COMMENT '接受者的id',
  `messageId` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '站内信内容id',
  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '站内信的状态 -> 未读 已读 删除',
  PRIMARY KEY (`id`),
  KEY `mid` (`messageId`),
  KEY `uid` (`getUid`),
  CONSTRAINT `mid` FOREIGN KEY (`messageId`) REFERENCES `inner_message_text` (`id`),
  CONSTRAINT `uid` FOREIGN KEY (`getUid`) REFERENCES `user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

如上,我们分了两个表,一个存放信息列表,一个存放信息内容表,这样的好处就是解耦合,试想一下,倘若我们将所有数据放在一张表上,那么每个用户收到的信息都会被存入数据库中,几百人的使用量还好说,一旦用户数量上升,那么你的数据库只有一个结果:boom~

SpringBoot中要做的一些事情

持久化框架在这里我使用的是MybatisPlus,在这里我推荐一下jpabeetlSQL,用着是真滴舒服

这一些相应的配置我就不赘述了

我们在Constant池中进行常量的定义

    ...
    @Getter
    public enum Message{
        STATUS_NOTREAD("未读"),
        STATUS_READ("已读"),
        STATUS_DELETED("已删除"),
        TYPE_SYSTEM("系统消息",0),
        TYPE_PRIVATE("私信",1),
        TYPE_NOTICE("站内通知",2)
        GROUP_TYPE_USER("用户组",0),
        GROUP_TYPE_ADMIN("管理组",1)
        ;

        private Integer val;
        private String name;
        Message(String name , Integer val){
            this.val = val ;
            this.name = name ;
        }
        Message(String name){
            this.name = name ;
        }
    }
    ...

同时,我们在VO层中添加我们的MessageVO用于接收传递的数据对象


package com.eendtech.witkey.vo;

import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.Date;

/**
 * @ author Seale
 * @ Description: 站内信VO对象
 * @ QQ:1801157108
 * @ Date 2020/2/3 18:51
 */
@Data
@Accessors(chain = true)
public class MessageVO implements Serializable {

    private static final long serialVersionUID = -5424113637283045181L;

    private String messageId ;
    private Integer sendUid ;
    private Integer getUid ;
    private Integer type ;
    private Date postDate ;
    private Integer groupId;
    private String content ;
    private String status ;

}

以下是自定义的Mapper文件,当前使用的持久化框架是MybatisPlus简称MP

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.eendtech.witkey.mapper.MessageMapper">
    <!--根据站内信的接收人id和站内信的类型进行查询-->
    <resultMap id="findMessageByGetUidAndTypeResult" type="com.eendtech.witkey.model.Message">
        <id property="id" column="id"/>
        <result property="getUid" column="getUid"/>
        <result property="status" column="status"/>
        <result property="messageId" column="messageId"/>
        <association property="messageText" javaType="MessageText">
            <id property="id" column="mid"/>
            <result property="sendId" column="sendId"/>
            <result property="content" column="content"/>
            <result property="type" column="type"/>
            <result property="group" column="group"/>
            <result property="postDate" column="postDate"/>
        </association>
    </resultMap>

    <resultMap id="findSendMessageBySendUidMap" type="com.eendtech.witkey.model.Message">
        <id property="id" column="id"/>
        <result property="getUid" column="getUid"/>
        <result property="status" column="status"/>
        <result property="messageId" column="messageId"/>
        <association property="messageText" javaType="MessageText">
            <id property="id" column="mid"/>
            <result property="sendId" column="sendId"/>
            <result property="content" column="content"/>
            <result property="groupId" column="groupId"/>
            <result property="type" column="type"/>
            <result property="postDate" column="postDate"/>
        </association>
    </resultMap>

    <sql id="selectContent">
        m.id, m.getUid, m.messageId, m.status, t.id as mid, t.sendId, t.content, t.type, t.postDate ,t.groupId
    </sql>
    <sql id="systemContent">
        id,sendId,content,groupId,type,postDate
    </sql>

    <select id="findMessageByGetUidAndType" resultMap="findSendMessageBySendUidMap" parameterType="integer">
        SELECT
        <include refid="selectContent" />
        FROM  inner_message m
        LEFT JOIN inner_message_text t
        ON m.messageId = t.id
        WHERE m.getUid = #{uid}
        And t.type = #{type}
    </select>

    <select id="findSendMessageBySendUid" resultMap="findSendMessageBySendUidMap" parameterType="integer">
        SELECT
        <include refid="selectContent" />
        FROM inner_message m
        LEFT JOIN inner_message_text t
        ON m.messageId = t.id
        where t.sendId = #{sendUid}
    </select>

    <select id="findGroupSystemMessageNotReadForGetUid" resultType="com.eendtech.witkey.model.MessageText">
        SELECT
        <include refid="systemContent"/>
        FROM
        inner_message_text as t
        WHERE
        (SELECT count(1) as num FROM inner_message as m WHERE m.messageId = t.id AND m.getUid = #{getUid}) = 0
        AND
        t.type = 0
    </select>

</mapper>

在这里讲解一下findGroupSystemMessageNotReadForGetUid,查找群发的未读系统消息通过接收者的uid,我们通过在inner_message中查找getUid是否存在,如果不存在并且inner_message_text中的id也不再inner_message中,那么这个时候返回的便是该用户接收到的系统群发的未读系统通知

具体的流程是这样的

MODEL

package com.eendtech.witkey.model;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;

import java.io.Serializable;

/**
 * @ author Seale
 * @ Description: 站内信实体
 * @ QQ:1801157108
 * @ Date 2020/2/3 16:22
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@TableName(value = "inner_message")
public class Message implements Serializable {
    private static final long serialVersionUID = 7887210545783690313L;
    @TableId(type = IdType.AUTO)
    private Integer id;
    private Integer getUid;
    private String messageId;
    private String status;

    private MessageText messageText;
}
package com.eendtech.witkey.model;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.Date;

/**
 * @ author Seale
 * @ Description: 站内信内容实体
 * @ QQ:1801157108
 * @ Date 2020/2/3 16:30
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@TableName(value = "inner_message_text")
public class MessageText implements Serializable {
    private static final long serialVersionUID = -7070081047200484184L;
    @TableId(type = IdType.UUID)
    private String id ;
    private Integer sendId;
    private String content;
    private Integer type;
    private Integer groupId;
    private Date postDate;

}

Service层

package com.eendtech.witkey.service.message;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.eendtech.witkey.model.Message;
import com.eendtech.witkey.model.MessageText;
import com.eendtech.witkey.vo.MessageVO;

import java.util.List;

/**
 * @ author Seale
 * @ Description:
 * @ QQ:1801157108
 * @ Date 2020/2/3 17:03
 */
public interface MessageService extends IService<Message> {
    /***
     * 函数名: addOne
     * 函数说明: 在message中添加一条私信
     * 创建时间: 2020/2/3 17:13
     * @Param message:
     * @return: java.lang.String
     */
    String addPrivateOne(MessageVO message);

    /***
     * 函数名: addSystemOne
     * 函数说明: 添加一条系统提示信息 (点对点)
     * 创建时间: 2020/2/3 19:06
     * @Param messageVO:
     * @return: java.lang.String
     */
    String addSystemOne(MessageVO messageVO);

    /***
     * 函数名: addSystemGroup
     * 函数说明: 添加一条全体的系统提示信息
     * 创建时间: 2020/2/5 20:40
     * @Param messageVO:
     * @return: java.lang.String
     */
    String addSystemGroup(MessageVO messageVO);
    /***
     * 函数名: addNoticeOne
     * 函数说明: 添加一条站内通知信息
     * 创建时间: 2020/2/3 19:06
     * @Param messageVO:
     * @return: java.lang.String
     */
    String addNoticeOne(MessageVO messageVO);

    /***
     * 函数名: updateOne
     * 函数说明: 更新一条message,这种修改原则上只适用于站内通知,更改内容
     * 创建时间: 2020/2/3 17:17
     * @Param message:
     * @return: java.lang.String
     */
    String updateOne(MessageVO messageVO);

    /***
     * 函数名: updateOneStatus
     * 函数说明: 修改一条站内信的状态,根据getUid和messageID
     * 创建时间: 2020/2/3 17:19
     * @Param message:
     * @return: java.lang.String
     */
    String updateOneStatusByGetUidAndMessageId(MessageVO messageVO);

    /***
     * 函数名: updateAllStatus
     * 函数说明: 根据当前的getUid修改所有站内信的状态
     * 创建时间: 2020/2/3 17:20
     * @Param message:
     * @return: java.lang.String
     *
     */
    String updateAllStatusByGetUid(MessageVO messageVO);

    /***
     * 函数名: delOne
     * 函数说明: 删除一条message,根据messageID进行删除,两个表中的内容都将被删除
     * 创建时间: 2020/2/3 17:30
     * @Param message:
     * @return: java.lang.String
     */
    String delOne(MessageVO messageVO);
    String delMany(List<MessageVO> messages);

    //************查询接口***************************//

    /***
     * 函数名: findMessageByGetUidAndType
     * 函数说明: 根据站内信的接收人id和站内信的类型进行查询
     * 创建时间: 2020/2/3 17:58
     * @Param getUid:
     * @Param type:
     * @return: com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.eendtech.witkey.model.Message>
     */
    Page<Message> findMessageByGetUidAndType(Integer getUid , Integer type , Integer page , Integer size);
    Page<Message> findMessageByGetUidAndType(Integer getUid , Integer type , Integer page );

    /***
     * 函数名: findSendMessageBySendUid
     * 函数说明: 根据发送人id查询当前id发送的站内私信
     * 创建时间: 2020/2/3 18:00
     * @Param sendUid:
     * @return: com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.eendtech.witkey.model.MessageText>
     */
    Page<Message> findSendMessageBySendUid(Integer sendUid,Integer page , Integer size);
    Page<Message> findSendMessageBySendUid(Integer sendUid,Integer page );

    /***
     * 函数名: findSendNoticeMessage
     * 函数说明: 查询当前用户组的系统通知(所有的)
     * 创建时间: 2020/2/3 18:08
     * @return: com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.eendtech.witkey.model.MessageText>
     */
    Page<MessageText> findSendSysMessage( Integer page , Integer size);
    Page<MessageText> findSendSysMessage( Integer page );

    /***
     * 函数名: findNotceMessageNotReadForGetUid
     * 函数说明: 查询当前用户组id的未读系统通知
     * 创建时间: 2020/2/4 13:57
     * @Param getUid:
     * @Param page:
     * @Param size:
     * @return: com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.eendtech.witkey.model.MessageText>
     */

    Page<MessageText> findSystemMessageNotReadForGetUid(Integer getUid , Integer page , Integer size);
    Page<MessageText> findSystemMessageNotReadForGetUid(Integer getUid , Integer page );

    /***
     * 函数名: setGroupSystemMessageReadForGetUid
     * 函数说明: 将群发系统未读通知设置成已读
     * 创建时间: 2020/2/4 20:14
     * @Param mid:
     * @Param getUid:
     * @return: java.lang.String
     */
    String setGroupSystemMessageReadForGetUid(String mid,Integer getUid);
    /***
     * 函数名: groupSendNotice
     * 函数说明: 发送用户组站内消息
     * 创建时间: 2020/2/4 13:59
     * @Param vo:
     * @return: java.lang.String
     */

    String groupSendSystem(MessageVO vo);
}
package com.eendtech.witkey.service.message.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.eendtech.witkey.constants.BaseConstant;
import com.eendtech.witkey.mapper.MessageMapper;
import com.eendtech.witkey.model.Message;
import com.eendtech.witkey.model.MessageText;
import com.eendtech.witkey.service.message.MessageService;
import com.eendtech.witkey.service.message.MessageTextService;
import com.eendtech.witkey.utils.BaseUtils;
import com.eendtech.witkey.vo.MessageVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * @ author Seale
 * @ Description:
 * @ QQ:1801157108
 * @ Date 2020/2/3 17:04
 */
@Transactional
@Service
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements MessageService {

    @Autowired
    MessageTextService messageTextService;

    @Autowired
    MessageMapper messageMapper;

    final static Integer DEFAULT_SIZE = 10 ;
    //在message中添加一条信息

    @Override
    public String addPrivateOne(MessageVO messageVO) {
        Date now = BaseUtils.getTimeNow();

        Message message;
        MessageText text = new MessageText();

        text.setContent(messageVO.getContent())
                .setType(BaseConstant.Message.TYPE_PRIVATE.getVal())
                .setPostDate(now)
                .setSendId(messageVO.getSendUid());
        //进行text表的插入
        boolean text_flag = messageTextService.save(text);
        //获取text表中的id
        String messageId = text.getId();
        message = initMessage(messageId, messageVO.getGetUid());
        boolean message_flag = save(message);
        if (text_flag || message_flag) {
            return "发送成功";
        }

        return "发送失败";
    }

    @Override
    public String addSystemOne(MessageVO messageVO) {
        // TODO: 2020/2/5 此方案暂不实现
        return null;
    }

    @Override
    public String addSystemGroup(MessageVO messageVO) {
        Date now = BaseUtils.getTimeNow();

        //Message message;
        MessageText text = new MessageText();

        text.setPostDate(now)
                .setType(BaseConstant.Message.TYPE_SYSTEM.getVal())
                .setContent(messageVO.getContent());
        //进行text的插入
        boolean text_flag = messageTextService.save(text);
        //取出messageId
        /*String messageId = text.getId();
        message = initMessage(messageId, messageVO.getGetUid());
        boolean message_falg = save(message);*/
        if (text_flag) return "发送成功";
        return "发送失败";
    }

    @Override
    public String addNoticeOne(MessageVO messageVO) {
        Date now = BaseUtils.getTimeNow();

        Message message;
        MessageText text = new MessageText();

        text.setPostDate(now)
                .setType(BaseConstant.Message.TYPE_NOTICE.getVal())
                .setContent(messageVO.getContent());
        //进行text的插入
        boolean text_flag = messageTextService.save(text);
        //取出messageId
        String messageId = text.getId();
        message = initMessage(messageId, messageVO.getGetUid());

        boolean message_falg = save(message);
        if (text_flag || message_falg) return "发送成功";

        return "发送失败";
    }

    @Override
    public String updateOne(MessageVO messageVO) {
        String messageId = messageVO.getMessageId();
        String content = messageVO.getContent();
        MessageText text = new MessageText();
        Date now = BaseUtils.getTimeNow();
        text.setPostDate(now)
                .setContent(content)
                .setId(messageId);
        boolean text_flag = messageTextService.updateById(text);
        //此时应该在message表中修改消息状态 -> 未读
        Message message = new Message();
        message.setStatus(BaseConstant.Message.STATUS_NOTREAD.getName());
        //进行message表中消息状态的修改
        boolean message_flag =
                lambdaUpdate()
                        .eq(Message::getMessageId, messageId)
                        .update(message);

        if (text_flag || message_flag) return "修改消息成功";
        return "修改消息失败";
    }

    @Override
    public String updateOneStatusByGetUidAndMessageId(MessageVO messageVO) {
        String messageId = messageVO.getMessageId();
        Integer getUid = messageVO.getGetUid();
        Message message = new Message();

        String status = messageVO.getStatus();

        if (choiceStatus(status) != null) {
            message.setStatus(choiceStatus(status));
            boolean flag =
                    lambdaUpdate()
                            .eq(Message::getGetUid, getUid)
                            .eq(Message::getMessageId, messageId)
                            .update(message);
            if (flag) return "成功";
        }

        return "状态改变失败";
    }

    @Override
    public String updateAllStatusByGetUid(MessageVO messageVO) {
        Integer getUid = messageVO.getGetUid();
        Message message = new Message();
        String status = messageVO.getStatus();

        //进行判断,已读或者删除状态
        if (choiceStatus(status) != null) {
            message.setStatus(choiceStatus(status));
            boolean flag =
                    lambdaUpdate()
                            .eq(Message::getGetUid, getUid)
                            .update(message);
            if (flag) return "成功";
        }

        return "状态修改失败";
    }

    @Override
    public String delOne(MessageVO messageVO) {
        //// TODO: 2020/2/3 当前版本不考虑复杂后台管理故暂不实现
        return null;
    }

    @Override
    public String delMany(List<MessageVO> messages) {
        //// TODO: 2020/2/3 当前版本不考虑复杂后台管理故暂不实现
        return null;
    }

    @Override
    public Page<Message> findMessageByGetUidAndType(Integer getUid, Integer type , Integer page , Integer size) {
        //根据站内信的接收人id和站内信的类型进行查询
        if (choiceType(type) != null){
            Page<Message> p = new Page<>();
            p.setCurrent(page)
                    .setSize(size)
                    .setRecords(messageMapper.findMessageByGetUidAndType(getUid,type,p));
            return p;
        }

        return null;
    }

    @Override
    public Page<Message> findMessageByGetUidAndType(Integer getUid, Integer type, Integer page) {
        return findMessageByGetUidAndType(getUid,type,page,DEFAULT_SIZE);
    }

    @Override
    public Page<Message> findSendMessageBySendUid(Integer sendUid, Integer page , Integer size) {
        Page<Message> p = new Page<>();
        p.setCurrent(page)
                .setSize(size)
                .setRecords(messageMapper.findSendMessageBySendUid(sendUid,p));
        return p;
    }
    @Override
    public Page<Message> findSendMessageBySendUid(Integer sendUid, Integer page ) {
        return findSendMessageBySendUid(sendUid,page,DEFAULT_SIZE);
    }

    @Override
    public Page<MessageText> findSendSysMessage(Integer page, Integer size) {
        Page<MessageText> p = new Page<>();
        LambdaQueryWrapper<MessageText> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MessageText::getType,BaseConstant.Message.TYPE_SYSTEM.getVal())
                .eq(MessageText::getGroupId,BaseConstant.Message.GROUP_TYPE_USER.getVal());
        p.setCurrent(page).setSize(size);
        return (Page<MessageText>) messageTextService.page(p,wrapper);
    }

    @Override
    public Page<MessageText> findSendSysMessage(Integer page) {
        return findSendSysMessage(page,DEFAULT_SIZE);
    }

    @Override
    public Page<MessageText> findSystemMessageNotReadForGetUid(Integer getUid, Integer page, Integer size) {
        Page<MessageText> p = new Page<>();
        p.setCurrent(page).setSize(size)
                .setRecords(messageMapper.findGroupSystemMessageNotReadForGetUid(getUid,p));
        return p;
    }

    @Override
    public Page<MessageText> findSystemMessageNotReadForGetUid(Integer getUid, Integer page) {
        return findSystemMessageNotReadForGetUid(getUid,page,DEFAULT_SIZE);
    }

    @Override
    public String setGroupSystemMessageReadForGetUid(String mid, Integer getUid) {
        Message message = new Message();
        message.setMessageId(mid)
                .setStatus(BaseConstant.Message.STATUS_READ.getName())
                .setGetUid(getUid);
        boolean flag = saveOrUpdate(message);
        if(flag) return "已读";
        return "失败";
    }

    @Override
    public String groupSendSystem(MessageVO vo) {
        MessageText text = new MessageText();
        text.setContent(vo.getContent())
                .setPostDate(BaseUtils.getTimeNow())
                .setType(BaseConstant.Message.TYPE_SYSTEM.getVal())
                .setGroupId(BaseConstant.Message.GROUP_TYPE_USER.getVal());
        boolean flag = messageTextService.saveOrUpdate(text);
        if (flag) return "发送成功";
        return "失败";
    }

    //*************************************************************************************************
    private Message initMessage(String messageId, Integer uid) {
        Message message = new Message();
        message.setStatus(BaseConstant.Message.STATUS_NOTREAD.getName())
                .setMessageId(messageId)
                .setGetUid(uid);
        return message;
    }

    private String choiceStatus(String status) {
        if (status.equals(BaseConstant.Message.STATUS_READ.getName()))
            return (BaseConstant.Message.STATUS_READ.getName());
        else if (status.equals(BaseConstant.Message.STATUS_DELETED.getName()))
            return (BaseConstant.Message.STATUS_DELETED.getName());
        return null;
    }
    private Integer choiceType(Integer type){
        if (type.equals(BaseConstant.Message.TYPE_SYSTEM.getVal()))
            return BaseConstant.Message.TYPE_SYSTEM.getVal();
        else if (type.equals(BaseConstant.Message.TYPE_PRIVATE.getVal()))
            return BaseConstant.Message.TYPE_PRIVATE.getVal();
        else if (type.equals(BaseConstant.Message.TYPE_NOTICE.getVal()))
            return BaseConstant.Message.TYPE_NOTICE.getVal();
        return null;
    }
}

简单的测试

封装一个返回工具集

package com.eendtech.witkey.utils;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;

/**
 * @ author Seale
 * @ Description: Json返回包集合类
 * @ QQ:1801157108
 * @ Date 2020/2/1 19:18
 */
@Getter@Setter
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ReturnsKit <T>{
    //状态码
    private Integer code;
    //结果
    private T result;
    //消息
    private String message;
    //状态
    private String status;
}

再编写测试Controller

@GetMapping("/getSys/{uid}")
    public ReturnsKit<Page<MessageText>> sys (@PathVariable Integer uid){
        Page<MessageText> page = messageService.findSystemMessageNotReadForGetUid(uid,1);

        return new ReturnsKit<Page<MessageText>>().setResult(page)
                .setCode(BaseConstant.Returns.SUCCESS.getCode())
                .setStatus(BaseConstant.Returns.SUCCESS.getStatus());
    }

最后

本篇探索只适合于本人的毕设内容,不代表可以运用于生产环境,这里只是讲一个大概的思路

控制器类还没完全写好,写好了放上来

补上完整的Controller层

package com.eendtech.witkey.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eendtech.witkey.constants.BaseConstant;
import com.eendtech.witkey.model.Message;
import com.eendtech.witkey.model.MessageText;
import com.eendtech.witkey.service.message.MessageService;
import com.eendtech.witkey.utils.BaseUtils;
import com.eendtech.witkey.utils.ReturnsKit;
import com.eendtech.witkey.vo.MessageVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @ author Seale
 * @ Description: 信息的接口控制类
 * @ QQ:1801157108
 * @ Date 2020/2/4 17:40
 */
@RestController
@RequestMapping("/api/message")
public class MessageController {
    @Autowired
    MessageService messageService;

    @GetMapping("/getNotReadSys/{uid}")
    public ReturnsKit<Page<MessageText>> getUidNotReadSystemMessage(@PathVariable("uid") Integer uid, Integer page, Integer size) {
        //查询当前用户组 uid的未读系统通知
        size = BaseUtils.initSize(size);
        page = BaseUtils.initPage(page);
        ReturnsKit<Page<MessageText>> returnsKit = new ReturnsKit<>();

        return returnsKit.setStatus(BaseConstant.Returns.SUCCESS.getStatus())
                .setCode(BaseConstant.Returns.SUCCESS.getCode())
                .setResult(messageService.findSystemMessageNotReadForGetUid(uid, page, size));
    }
    @GetMapping("/getReadSys/{uid}")
    public ReturnsKit<Page<Message>> getSys(@PathVariable Integer uid, Integer page , Integer size){
        page = BaseUtils.initPage(page);
        size = BaseUtils.initSize(size);
        ReturnsKit<Page<Message>> returnsKit = new ReturnsKit<>();
        if (verifyParam(uid,size,page)){
            return returnsKit.setCode(BaseConstant.Returns.SUCCESS.getCode())
                    .setStatus(BaseConstant.Returns.SUCCESS.getStatus())
                    .setResult(messageService.findMessageByGetUidAndType(uid,BaseConstant.Message.TYPE_SYSTEM.getVal(),page,size));
        }else
            return returnsKit.setCode(BaseConstant.Returns.PARAM_ERRO.getCode())
            .setStatus(BaseConstant.Returns.PARAM_ERRO.getStatus())
            .setMessage(BaseConstant.ReturnMessage.PARAM_NOT_NULL.getVal());

    }

    @PostMapping("/sendGroupSysMsg")
    public ReturnsKit<String> sendGroupSystemMessage(@RequestBody MessageVO vo) {
        //发送用户组站内系统消息
        ReturnsKit<String> returnsKit = new ReturnsKit<>();
        if (verifyParam(vo.getContent())) {
            String msg = messageService.groupSendSystem(vo);
            if (msg.equals("发送成功")) {
                return returnsKit.setCode(BaseConstant.Returns.SUCCESS.getCode())
                        .setStatus(BaseConstant.Returns.SUCCESS.getStatus())
                        .setMessage(msg);
            } else {
                return returnsKit.setCode(BaseConstant.Returns.FAIL.getCode())
                        .setStatus(BaseConstant.Returns.FAIL.getStatus())
                        .setMessage(msg);
            }
        }
        return returnsKit.setCode(BaseConstant.Returns.PARAM_ERRO.getCode())
                .setStatus(BaseConstant.Returns.PARAM_ERRO.getStatus())
                .setMessage(BaseConstant.ReturnMessage.PARAM_NOT_NULL.getVal());
    }

    @PostMapping("/readGroupSysMsg")
    public ReturnsKit<String> setGroupSystemMessageRead(@RequestBody MessageVO vo) {
        //将系统群发的系统通知设置为已读
        ReturnsKit<String> returnsKit = new ReturnsKit<>();
        if (verifyParam(vo.getGetUid(), vo.getMessageId())) {
            String msg = messageService.setGroupSystemMessageReadForGetUid(vo.getMessageId(), vo.getGetUid());
            if (msg.equals("已读")) {
                return returnsKit.setMessage(msg)
                        .setCode(BaseConstant.Returns.SUCCESS.getCode())
                        .setStatus(BaseConstant.Returns.SUCCESS.getStatus());
            } else {
                return returnsKit.setMessage(msg)
                        .setStatus(BaseConstant.Returns.FAIL.getStatus())
                        .setCode(BaseConstant.Returns.FAIL.getCode());
            }
        } else {
            return returnsKit.setMessage(BaseConstant.ReturnMessage.PARAM_NOT_NULL.getVal())
                    .setCode(BaseConstant.Returns.PARAM_ERRO.getCode())
                    .setStatus(BaseConstant.Returns.PARAM_ERRO.getStatus());
        }
    }

    @GetMapping("/getAllSysForGroup")
    public ReturnsKit<Page<MessageText>> getAllSysForGroup(Integer page, Integer size) {
        //查询当前已发送的系统通知(所有的)
        size = BaseUtils.initSize(size);
        page = BaseUtils.initPage(page);
        ReturnsKit<Page<MessageText>> returnsKit = new ReturnsKit<>();

        return returnsKit.setStatus(BaseConstant.Returns.SUCCESS.getStatus())
                .setCode(BaseConstant.Returns.SUCCESS.getCode())
                .setResult(messageService.findSendSysMessage(page, size));
    }

    @GetMapping("/getSendPrivate/{uid}")
    public ReturnsKit<Page<Message>> getSendMessageBySendUid(@PathVariable Integer uid, Integer page, Integer size) {
        //根据发送人id查询当前id发送的站内私信
        size = BaseUtils.initSize(size);
        page = BaseUtils.initPage(page);
        ReturnsKit<Page<Message>> returnsKit = new ReturnsKit<>();
        if (verifyParam(uid)) {
            return returnsKit.setResult(messageService.findSendMessageBySendUid(uid, page, size))
                    .setCode(BaseConstant.Returns.SUCCESS.getCode())
                    .setStatus(BaseConstant.Returns.SUCCESS.getStatus());
        } else {
            return returnsKit.setMessage(BaseConstant.ReturnMessage.PARAM_NOT_NULL.getVal())
                    .setCode(BaseConstant.Returns.PARAM_ERRO.getCode())
                    .setStatus(BaseConstant.Returns.PARAM_ERRO.getStatus());
        }
    }

    @GetMapping("/getPrivate/{uid}")
    public ReturnsKit<Page<Message>> getPrivateMsg(@PathVariable Integer uid, Integer page, Integer size) {
        //得到当前id收到的站内私信
        page = BaseUtils.initPage(page);
        size = BaseUtils.initSize(size);
        ReturnsKit<Page<Message>> returnsKit = new ReturnsKit<>();
        if (verifyParam(uid)) {
            return returnsKit.setStatus(BaseConstant.Returns.SUCCESS.getStatus())
                    .setCode(BaseConstant.Returns.SUCCESS.getCode())
                    .setResult(messageService.findMessageByGetUidAndType(uid, BaseConstant.Message.TYPE_PRIVATE.getVal(), page, size));
        } else {
            return returnsKit.setStatus(BaseConstant.Returns.PARAM_ERRO.getStatus())
                    .setCode(BaseConstant.Returns.PARAM_ERRO.getCode())
                    .setMessage(BaseConstant.ReturnMessage.PARAM_NOT_NULL.getVal());
        }
    }

    @GetMapping("/getNotice/{uid}")
    public ReturnsKit<Page<Message>> getNoticeMsg(@PathVariable Integer uid, Integer page, Integer size) {
        //得到当前id收到的站内通知
        page = BaseUtils.initPage(page);
        size = BaseUtils.initSize(size);
        ReturnsKit<Page<Message>> returnsKit = new ReturnsKit<>();
        if (verifyParam(uid)) {

            return returnsKit.setCode(BaseConstant.Returns.SUCCESS.getCode())
                    .setStatus(BaseConstant.Returns.SUCCESS.getStatus())
                    .setResult(messageService.findMessageByGetUidAndType(uid, BaseConstant.Message.TYPE_NOTICE.getVal(), page, size));
        } else {
            return returnsKit.setCode(BaseConstant.Returns.PARAM_ERRO.getCode())
                    .setStatus(BaseConstant.Returns.PARAM_ERRO.getStatus())
                    .setMessage(BaseConstant.ReturnMessage.PARAM_NOT_NULL.getVal());
        }
    }

    /***
     * 函数名: setAllNotSystemMsgRead
     * 函数说明: 当前接口设置所有的非系统通知为已读状态
     * 创建时间: 2020/2/5 16:17
     * @return: com.eendtech.witkey.utils.ReturnsKit<java.lang.String>
     */
    @PostMapping("/readNotSysAll/{uid}")
    public ReturnsKit<String> setAllNotSystemMsgRead(@PathVariable Integer uid) {

        ReturnsKit<String> returnsKit = new ReturnsKit<>();

        if (verifyParam(uid)) {
            MessageVO vo = new MessageVO();
            vo.setGetUid(uid)
                    .setStatus(BaseConstant.Message.STATUS_READ.getName());

            return returnsKit.setCode(BaseConstant.Returns.SUCCESS.getCode())
                    .setStatus(BaseConstant.Returns.SUCCESS.getStatus())
                    .setMessage(messageService.updateAllStatusByGetUid(vo));
        } else {
            return returnsKit.setCode(BaseConstant.Returns.PARAM_ERRO.getCode())
                    .setStatus(BaseConstant.Returns.PARAM_ERRO.getStatus())
                    .setMessage(BaseConstant.ReturnMessage.PARAM_NOT_NULL.getVal());
        }

    }

    @PostMapping("/readNotSys")
    public ReturnsKit<String> setNotSysMsgRead(@RequestBody MessageVO vo) {
        //设置一条站内信或者私信为已读
        ReturnsKit<String> returnsKit = new ReturnsKit<>();
        if (verifyParam(vo.getGetUid(), vo.getMessageId())) {
            String msg = messageService.updateOneStatusByGetUidAndMessageId(vo);
            if (msg.equals("成功")) {
                return returnsKit.setCode(BaseConstant.Returns.SUCCESS.getCode())
                        .setStatus(BaseConstant.Returns.SUCCESS.getStatus())
                        .setMessage(msg);
            } else {
                return returnsKit.setCode(BaseConstant.Returns.FAIL.getCode())
                        .setStatus(BaseConstant.Returns.FAIL.getStatus())
                        .setMessage(msg);
            }
        } else {
            return returnsKit.setCode(BaseConstant.Returns.PARAM_ERRO.getCode())
                    .setStatus(BaseConstant.Returns.PARAM_ERRO.getStatus())
                    .setMessage(BaseConstant.ReturnMessage.PARAM_NOT_NULL.getVal());
        }
    }

    @PostMapping("/updateSysMsg")
    public ReturnsKit<String> updateSys(@RequestBody MessageVO vo) {
        //修改一条系统通知
        ReturnsKit<String> returnsKit = new ReturnsKit<>();
        if (verifyParam(vo.getMessageId(), vo.getContent())) {
            String msg = messageService.updateOne(vo);
            if (msg.equals("修改消息成功")) {
                return returnsKit.setCode(BaseConstant.Returns.SUCCESS.getCode())
                        .setStatus(BaseConstant.Returns.SUCCESS.getStatus())
                        .setMessage(msg);
            } else {
                return returnsKit.setCode(BaseConstant.Returns.FAIL.getCode())
                        .setStatus(BaseConstant.Returns.FAIL.getStatus())
                        .setMessage(msg);
            }
        } else {
            return returnsKit.setCode(BaseConstant.Returns.PARAM_ERRO.getCode())
                    .setStatus(BaseConstant.Returns.PARAM_ERRO.getStatus())
                    .setMessage(BaseConstant.ReturnMessage.PARAM_NOT_NULL.getVal());
        }
    }

    @PostMapping("/sendNotice")
    //添加一条站内通知信息
    public ReturnsKit<String> sendNotice(@RequestBody MessageVO vo) {
        ReturnsKit<String> returnsKit = new ReturnsKit<>();
        if (verifyParam(vo.getGetUid(), vo.getContent())) {
            String msg = messageService.addNoticeOne(vo);
            if (msg.equals("发送成功")) {
                return returnsKit.setCode(BaseConstant.Returns.SUCCESS.getCode())
                        .setStatus(BaseConstant.Returns.SUCCESS.getStatus())
                        .setMessage(msg);
            } else {
                return returnsKit.setCode(BaseConstant.Returns.FAIL.getCode())
                        .setStatus(BaseConstant.Returns.FAIL.getStatus())
                        .setMessage(msg);
            }
        } else {
            return returnsKit.setCode(BaseConstant.Returns.PARAM_ERRO.getCode())
                    .setStatus(BaseConstant.Returns.PARAM_ERRO.getStatus())
                    .setMessage(BaseConstant.ReturnMessage.PARAM_NOT_NULL.getVal());
        }
    }

    @PostMapping("/sendSys")
    public ReturnsKit<String> sendSys(@RequestBody MessageVO vo) {
        ReturnsKit<String> returnsKit = new ReturnsKit<>();
        if (verifyParam(vo.getContent())) {
            String msg = messageService.addSystemGroup(vo);
            if (msg.equals("发送成功"))
                return returnsKit.setCode(BaseConstant.Returns.SUCCESS.getCode())
                        .setStatus(BaseConstant.Returns.SUCCESS.getStatus())
                        .setMessage(msg);
            else
                return returnsKit.setCode(BaseConstant.Returns.FAIL.getCode())
                        .setStatus(BaseConstant.Returns.FAIL.getStatus())
                        .setMessage(msg);
        } else
            return returnsKit.setCode(BaseConstant.Returns.PARAM_ERRO.getCode())
                    .setStatus(BaseConstant.Returns.PARAM_ERRO.getStatus())
                    .setMessage(BaseConstant.ReturnMessage.PARAM_NOT_NULL.getVal());
    }
    //发送私信 点对点
    @PostMapping("/sendPrivate")
    public ReturnsKit<String> sendPrivate(@RequestBody MessageVO vo){
        ReturnsKit<String> returnsKit = new ReturnsKit<>();
        if (verifyParam(vo.getContent(),vo.getGetUid(),vo.getSendUid())) {
            String msg = messageService.addPrivateOne(vo);
            if (msg.equals("发送成功"))
                return returnsKit.setCode(BaseConstant.Returns.SUCCESS.getCode())
                        .setStatus(BaseConstant.Returns.SUCCESS.getStatus())
                        .setMessage(msg);
            else
                return returnsKit.setCode(BaseConstant.Returns.FAIL.getCode())
                .setStatus(BaseConstant.Returns.FAIL.getStatus())
                .setMessage(msg);
        }else
            return returnsKit.setCode(BaseConstant.Returns.PARAM_ERRO.getCode())
            .setStatus(BaseConstant.Returns.PARAM_ERRO.getStatus())
            .setMessage(BaseConstant.ReturnMessage.PARAM_NOT_NULL.getVal());
    }

    //验证参数是否为空
    private boolean verifyParam(Object... objects) {
        for (Object o : objects) {
            if (o == null) {
                return false;
            }
        }
        return true;
    }
}

至此,一个简易的具备点对点和点对面的站内信模块就实现了!
这个时候我们通过ajax或者axios调用我们的restful接口就行了!


本作品采用知识共享署名 4.0 国际许可协议进行许可。

如果可以的话,请给我钱请给我点赞赏,小小心意即可!

Last modification:February 5, 2020
If you think my article is useful to you, please feel free to appreciate