• 6_2_站内信


    站内信

    一 需求描述

    站内信是当前用户与所有用户间对话的一个功能。

    站内信模块需实现三个功能:

    1. 互相发送站内信(写出接口,没有单独页面,用@ResponseBody直接在Postman进行验证);

    2. 显示当前用户的所有站内信(与多个用户间);

    3. 显示当前用户与某个指定用户间的对话消息。

     

    二 具体实现

    实现流程:DB>Model>Dao>Service>Controller>HTML

    1.DB创建表Message

     1 DROP TABLE IF EXISTS `message`;
     2 CREATE TABLE `message`(
     3   `id` INT NOT NULL AUTO_INCREMENT,
     4    `from_id` INT NOT NULL,
     5    `to_id` INT NOT NULL ,
     6     `content` TEXT NOT NULL ,
     7     `created_date` DATETIME NOT NULL ,
     8     `has_read` INT NULL ,
     9     `conversation_id` VARCHAR(45) NOT NULL ,
    10     PRIMARY KEY (`id`),
    11      INDEX `conversation_index` (`conversation_id` ASC),
    12     INDEX `created_date` (`created_date` ASC)
    13 ) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8;
    View Code

    2. Model:

    package com.nowcoder.model;
    
    import org.springframework.stereotype.Component;
    
    import java.util.Date;
    
    /**
     * Created by Administrator on 2017/4/29.
     */
    @Component
    public class Message {
        private int id;
        private int fromId;
        private int toId;
        private String content;
        private Date createdDate;
        private int hasRead;
        private String conversationId;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public int getFromId() {
            return fromId;
        }
    
        public void setFromId(int fromId) {
            this.fromId = fromId;
        }
    
        public int getToId() {
            return toId;
        }
    
        public void setToId(int toId) {
            this.toId = toId;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
        public Date getCreatedDate() {
            return createdDate;
        }
    
        public void setCreatedDate(Date createdDate) {
            this.createdDate = createdDate;
        }
    
        public int getHasRead() {
            return hasRead;
        }
    
        public void setHasRead(int hasRead) {
            this.hasRead = hasRead;
        }
    
        public String getConversationId() {
            return conversationId;
        }
    
        public void setConversationId(String conversationId) {
            this.conversationId = conversationId;
        }
    }
    View Code

    3. Dao:

    int addMessage(Message message);发送站内信
    List<Message> getConversationDetail(@Param("conversationId") String conversationId,
    @Param("offset") int offset,
    @Param("limit") int limit); : 获取与某个具体用户的站内信
    List<Message> getConversationList(@Param("userId") int userId,
    @Param("offset") int offset,
    @Param("limit") int limit); : 获取站内信列表
    int getConvesationUnreadCount(@Param("userId") int userId,
    @Param("conversationId") String conversationId); :统计未读信息
    package com.nowcoder.dao;
    
    import com.nowcoder.model.Message;
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Select;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import java.util.List;
    
    /**
     * Created by Administrator on 2017/4/29.
     */
    @Mapper
    public interface MessageDao {
    
        String TABLE_NAME = "message";
        String INSERT_FIELDS = "from_id, to_id, content, created_date, has_read, conversation_id";
        String SELECT_FIELDS = "id," + INSERT_FIELDS;
    
        @Insert({"insert into", TABLE_NAME, "(", INSERT_FIELDS, ") " +
                " values(#{fromId}, #{toId}, #{content}, #{createdDate}, #{hasRead}, #{conversationId})"})
        int addMessage(Message message);
    
        @Select({"select ", SELECT_FIELDS, " from ", TABLE_NAME,
                " where conversation_id=#{conversationId} order by id desc limit #{offset}, #{limit}"})
        List<Message> getConversationDetail(@Param("conversationId") String conversationId,
                                            @Param("offset") int offset,
                                            @Param("limit") int limit);
    
        @Select({"select", INSERT_FIELDS, " ,count(conversation_id) AS id from (select * from ",TABLE_NAME,
                 " where from_id=#{userId} or to_id=#{userId} order by id desc) tt group by conversation_id " +
                         " order by created_date limit #{offset}, #{limit}"})
        List<Message> getConversationList(@Param("userId") int userId,
                                          @Param("offset") int offset,
                                          @Param("limit") int limit);
    
        /**
         * 获取当前用户与指定用户间(conversationId)的对应未读信息
         * @param userId
         * @return
         */
        @Select({"select count(has_read) from ", TABLE_NAME, " where has_read=0 and to_id=#{userId} and conversation_id=#{conversationId}"})
        int getConvesationUnreadCount(@Param("userId") int userId,
                                      @Param("conversationId") String conversationId);
    
    
    }
    View Code

    4.Service:

    package com.nowcoder.service;
    
    import com.nowcoder.dao.MessageDao;
    import com.nowcoder.model.Message;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    /**
     * Created by Administrator on 2017/4/29.
     */
    @Service
    public class MessageService {
    
        @Autowired
        MessageDao messageDao;
    
        /**
         * 用户之间发送信息
         * @param message
         * @return
         */
        public int addMessage(Message message){
            return messageDao.addMessage(message);
        }
    
        public List<Message> getConversationDetail(String conversationId, int offset, int limit){
            return messageDao.getConversationDetail(conversationId, offset, limit);
        }
    
        public List<Message> getConversationList(int userId, int offset, int limit){
            return messageDao.getConversationList(userId, offset, limit);
        }
    
        /**
         * 获取当前用户与指定用户间(conversationId)的对应未读信息
         * @param userId
         * @return
         */
        public int getConvesationUnreadCount(int userId, String conversationId){
            return messageDao.getConvesationUnreadCount(userId, conversationId);
        }
    
    
    
    }
    View Code

    5. Controller: MessageController

    (1)发送信息:

        /**
         * 发送信息
         * 发送那一方的id +  收到信息的那一方 id =  会话conversationId
         *          : 即a发送给b 和 b 发送给a  的消息在a,b之间的站内信中心都能看见
         * @param fromId 发送那一方的id
         * @param toId 收到信息的那一方id
         * @param content
         * @return
         */
        @RequestMapping(path = {"/msg/addMsg/"}, method = RequestMethod.POST)
        @ResponseBody
        public String addMessage(@RequestParam("fromId") int fromId,
                                 @RequestParam("toId") int toId,
                                 @RequestParam("content") String content){
            try {
                Message message = new Message();
                message.setFromId(fromId);
                message.setToId(toId);
                message.setContent(content);
                message.setCreatedDate(new Date());
                message.setHasRead(0);// 0 代表未读 1 代表已读
                message.setConversationId(fromId < toId ? String.format("%d_%d", fromId, toId) : String.format("%d_%d", toId, fromId));
    
                messageService.addMessage(message);
                return ToutiaoUtil.getJSONString(0);
            }catch (Exception e){
                logger.error("私信发送失败" + e.getMessage());
                return  ToutiaoUtil.getJSONString(1, "私信发送失败!");
            }
    
        }

    (2)获取当前用户站内信列表:

    /**
         * 当前用户的所有站内信,包括与所有用户的信息
         * @param model
         * @return
         */
        @RequestMapping(path = {"/msg/list"}, method = {RequestMethod.GET})
        public String conversationList(Model model){
    
            try{
                int localUserId = hostHolder.getUser().getId();
                List<Message> conversationListList =
                        messageService.getConversationList(localUserId, 0, 20);
                List<ViewObject> conversationVOs = new ArrayList<>();
                for(Message msg : conversationListList){
    
                    ViewObject vo = new ViewObject();
                    vo.set("conversation", msg);
    
                    //获取与当前用户对话的user信息
                    //如果是我方发送(msg.getFromId() == localUserId),则user.id为消息发送的toId
                    //如果不是我方发送(即我方为接收方),则user.id 为消息发送的fromId
                    int targetId = (msg.getFromId() == localUserId) ? msg.getToId() : msg.getFromId();
                    User user = userService.getUser(targetId);
                    vo.set("user", user);
    
                    int unread = messageService.getConvesationUnreadCount(localUserId, msg.getConversationId());
                    vo.set("unread", unread);
    
                    conversationVOs.add(vo);
                }
                model.addAttribute("conversations", conversationVOs);
            }catch (Exception e){
                logger.error("获取站内信列表失败! " + e.getMessage());
            }
            return "letter";
        }

    (3)获取与指定用户间的站内信:

        /**
         * 当前用户与指定用户间的对话消息;
         * @param model
         * @param conversationId 与指定用户对话的id
         * @return
         */
        @RequestMapping(path = {"/msg/detail"}, method = {RequestMethod.GET})
            public String conversationDetail(Model model, @RequestParam("conversationId") String conversationId){
    
            try{
                //当前用户与多个用户的所有的站内信
                List<Message> conversationList = messageService.getConversationDetail(conversationId, 0 ,10);
                List<ViewObject> messages = new ArrayList<>();
                for(Message msg : conversationList){
                    ViewObject vo = new ViewObject();
                    vo.set("message", msg);
    
                    //获取当前用户收到信息方的user(即获取我方收到所有信息对应的用户)
                    User user = userService.getUser(msg.getFromId());
                    if(user == null){
                        continue;
                    }
                    vo.set("headUrl", user.getHeadUrl());
                    vo.set("userId", user.getId());
                    messages.add(vo);
                }
                model.addAttribute("messages", messages);
            }catch (Exception e){
                logger.error("获取与用户的对话消息失败 !" + e.getMessage());
            }
            return "letterDetail";
    
        }

    Controller所有的code:

    package com.nowcoder.controller;
    
    import com.nowcoder.model.HostHolder;
    import com.nowcoder.model.Message;
    import com.nowcoder.model.User;
    import com.nowcoder.model.ViewObject;
    import com.nowcoder.service.MessageService;
    import com.nowcoder.service.UserService;
    import com.nowcoder.util.ToutiaoUtil;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    /**
     * Created by Administrator on 2017/4/29.
     */
    @Controller
    public class MessageController {
    
        private static final Logger logger = LoggerFactory.getLogger(MessageController.class);
    
        @Autowired
        MessageService messageService;
        @Autowired
        UserService userService;
        @Autowired
        HostHolder hostHolder;
    
        /**
         * 当前用户的所有站内信,包括与所有用户的信息
         * @param model
         * @return
         */
        @RequestMapping(path = {"/msg/list"}, method = {RequestMethod.GET})
        public String conversationList(Model model){
    
            try{
                int localUserId = hostHolder.getUser().getId();
                List<Message> conversationListList =
                        messageService.getConversationList(localUserId, 0, 20);
                List<ViewObject> conversationVOs = new ArrayList<>();
                for(Message msg : conversationListList){
    
                    ViewObject vo = new ViewObject();
                    vo.set("conversation", msg);
    
                    //获取与当前用户对话的user信息
                    //如果是我方发送(msg.getFromId() == localUserId),则user.id为消息发送的toId
                    //如果不是我方发送(即我方为接收方),则user.id 为消息发送的fromId
                    int targetId = (msg.getFromId() == localUserId) ? msg.getToId() : msg.getFromId();
                    User user = userService.getUser(targetId);
                    vo.set("user", user);
    
                    int unread = messageService.getConvesationUnreadCount(localUserId, msg.getConversationId());
                    vo.set("unread", unread);
    
                    conversationVOs.add(vo);
                }
                model.addAttribute("conversations", conversationVOs);
            }catch (Exception e){
                logger.error("获取站内信列表失败! " + e.getMessage());
            }
            return "letter";
        }
        /**
         * 当前用户与指定用户间的对话消息;
         * @param model
         * @param conversationId 与指定用户对话的id
         * @return
         */
        @RequestMapping(path = {"/msg/detail"}, method = {RequestMethod.GET})
            public String conversationDetail(Model model, @RequestParam("conversationId") String conversationId){
    
            try{
                //当前用户与多个用户的所有的站内信
                List<Message> conversationList = messageService.getConversationDetail(conversationId, 0 ,10);
                List<ViewObject> messages = new ArrayList<>();
                for(Message msg : conversationList){
                    ViewObject vo = new ViewObject();
                    vo.set("message", msg);
    
                    //获取当前用户收到信息方的user(即获取我方收到所有信息对应的用户)
                    User user = userService.getUser(msg.getFromId());
                    if(user == null){
                        continue;
                    }
                    vo.set("headUrl", user.getHeadUrl());
                    vo.set("userId", user.getId());
                    messages.add(vo);
                }
                model.addAttribute("messages", messages);
            }catch (Exception e){
                logger.error("获取与用户的对话消息失败 !" + e.getMessage());
            }
            return "letterDetail";
    
        }
    
        /**
         * 发送信息
         * 发送那一方的id +  收到信息的那一方 id =  会话conversationId
         *          : 即a发送给b 和 b 发送给a  的消息在a,b之间的站内信中心都能看见
         * @param fromId 发送那一方的id
         * @param toId 收到信息的那一方id
         * @param content
         * @return
         */
        @RequestMapping(path = {"/msg/addMsg/"}, method = RequestMethod.POST)
        @ResponseBody
        public String addMessage(@RequestParam("fromId") int fromId,
                                 @RequestParam("toId") int toId,
                                 @RequestParam("content") String content){
            try {
                Message message = new Message();
                message.setFromId(fromId);
                message.setToId(toId);
                message.setContent(content);
                message.setCreatedDate(new Date());
                message.setHasRead(0);// 0 代表未读 1 代表已读
                message.setConversationId(fromId < toId ? String.format("%d_%d", fromId, toId) : String.format("%d_%d", toId, fromId));
    
                messageService.addMessage(message);
                return ToutiaoUtil.getJSONString(0);
            }catch (Exception e){
                logger.error("私信发送失败" + e.getMessage());
                return  ToutiaoUtil.getJSONString(1, "私信发送失败!");
            }
    
        }
    
    }
    View Code

    对应HTML:

    所有站内信letter.html:

    #parse("header.html")
        <div id="main">
            <div class="container">
                <ul class="letter-list">
                    #foreach($conversation in $conversations)
                    <li id="conversation-item-10005_622873">
                        <a class="letter-link" href="/msg/detail?conversationId=$!{conversation.conversation.conversationId}"></a>
                        <div class="letter-info">
                            <span class="l-time">$!date.format('yyyy-MM-dd HH:mm:ss', $!{conversation.conversation.createdDate})</span>
                            <div class="l-operate-bar">
                                <a href="javascript:void(0);" class="sns-action-del" data-id="10005_622873">
                                删除
                                </a>
                                <a href="/msg/detail?conversationId=$!{conversation.conversation.conversationId}">
                                    共$!{conversation.conversation.id}条会话
                                </a>
                            </div>
                        </div>
                        <div class="chat-headbox">
                            <span class="msg-num">
                                $!{conversation.unread}
                            </span>
                            <a class="list-head" href="/user/$!{conversation.user.id}">
                                <img alt="头像" src="$!{conversation.user.headUrl}">
                            </a>
                        </div>
                        <div class="letter-detail">
                            <a title="$!{conversation.user.name}" class="letter-name level-color-1">
                                $!{conversation.user.name}
                            </a>
                            <p class="letter-brief">
                                <a href="/msg/detail?conversationId=$!{conversation.conversation.conversationId}">
                                    $!{conversation.conversation.content}
                                </a>
                            </p>
                        </div>
                    </li>
                    #end
                </ul>
    
            </div>
            <script type="text/javascript">
              $(function(){
    
                // If really is weixin
                $(document).on('WeixinJSBridgeReady', function() {
    
                  $('.weixin-qrcode-dropdown').show();
    
                  var options = {
                    "img_url": "",
                    "link": "http://nowcoder.com/j/wt2rwy",
                    "desc": "",
                    "title": "读《Web 全栈工程师的自我修养》"
                  };
    
                  WeixinJSBridge.on('menu:share:appmessage', function (argv){
                    WeixinJSBridge.invoke('sendAppMessage', options, function (res) {
                      // _report('send_msg', res.err_msg)
                    });
                  });
    
                  WeixinJSBridge.on('menu:share:timeline', function (argv) {
                    WeixinJSBridge.invoke('shareTimeline', options, function (res) {
                      // _report('send_msg', res.err_msg)
                    });
                  });
    
                  // $(window).on('touchmove scroll', function() {
                  //   if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
                  //     $('div.backdrop').show();
                  //     $('div.share-help').show();
                  //   } else {
                  //     $('div.backdrop').hide();
                  //     $('div.share-help').hide();
                  //   }
                  // });
    
                });
    
              })
            </script>
        </div>
    #parse("footer.html")
    View Code

    与某个用户的站内信letterDetail.html:

    #parse("header.html")
        <div id="main">
            <div class="container">
                <ul class="letter-chatlist">
                    #foreach($msg in $messages)
                        <li id="msg-item-4009580">
                            <a class="list-head" href="/user/$!{msg.userId}">
                                <img alt="头像" src="$!{msg.headUrl}">
                            </a>
                            <div class="tooltip fade right in">
                            <div class="tooltip-arrow"></div>
                            <div class="tooltip-inner letter-chat clearfix">
                            <div class="letter-info">
                            <p class="letter-time">$date.format('yyyy-MM-dd HH:mm:ss', $!{msg.message.createdDate})</p>
                            <a href="javascript:void(0);" id="del-link" name="4009580">删除</a>
                            </div>
                            <p class="chat-content">
                                $!{msg.message.content}
                            </p>
                            </div>
                            </div>
                        </li>
                    #end
                </ul>
    
            </div>
            <script type="text/javascript">
              $(function(){
    
                // If really is weixin
                $(document).on('WeixinJSBridgeReady', function() {
    
                  $('.weixin-qrcode-dropdown').show();
    
                  var options = {
                    "img_url": "",
                    "link": "http://nowcoder.com/j/wt2rwy",
                    "desc": "",
                    "title": "读《Web 全栈工程师的自我修养》"
                  };
    
                  WeixinJSBridge.on('menu:share:appmessage', function (argv){
                    WeixinJSBridge.invoke('sendAppMessage', options, function (res) {
                      // _report('send_msg', res.err_msg)
                    });
                  });
    
                  WeixinJSBridge.on('menu:share:timeline', function (argv) {
                    WeixinJSBridge.invoke('shareTimeline', options, function (res) {
                      // _report('send_msg', res.err_msg)
                    });
                  });
    
                  // $(window).on('touchmove scroll', function() {
                  //   if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
                  //     $('div.backdrop').show();
                  //     $('div.share-help').show();
                  //   } else {
                  //     $('div.backdrop').hide();
                  //     $('div.share-help').hide();
                  //   }
                  // });
    
                });
    
              })
            </script>
        </div>
    #parse("footer.html")
    View Code

    效果图:

    当前用户所有的站内信列表:

     与某个具体用户的站内信:

     

  • 相关阅读:
    html 带渐变的吸顶效果 vue
    Linux添加环境变量
    C#集合通论
    Android adb 命令导出数据库
    查看签名方式及签名信息
    啥 啥 啥,服务治理是个啥
    令牌桶、漏斗、冷启动限流在sentinel的应用
    MySQL事务
    MySQL优化
    MySQL视图、存储过程、函数、触发器
  • 原文地址:https://www.cnblogs.com/noaman/p/6789325.html
Copyright © 2020-2023  润新知