7.私信列表 + 发送列表

目录

1.私信列表

1.1 数据访问层

1.2 业务层

1.3 表现层

1.4 私信详情

2.发送列表

2.1 数据访问层

2.2 业务层

2.3 表现层

2.4 设置已读状态 


1.私信列表

7.私信列表 + 发送列表_第1张图片

  • 私信列表:查询当前用户的会话列表,每个会话只显示一条最新的私信、支持分页列表
  • 私信详情:查询某个会话所包含的私信、支持分页显示

7.私信列表 + 发送列表_第2张图片

在 entity 包下新建 Message 实体类:

package com.example.demo.entity;

import java.util.Date;
/**
 * 私信列表实体类
 */
public class Message {

    private int id;
    private int fromId;
    private int toId;
    private String conversationId;//会话 id
    private String content;
    private int status;
    private Date createTime;

    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 getConversationId() {
        return conversationId;
    }

    public void setConversationId(String conversationId) {
        this.conversationId = conversationId;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Override
    public String toString() {
        return "Message{" +
                "id=" + id +
                ", fromId=" + fromId +
                ", toId=" + toId +
                ", conversationId='" + conversationId + '\'' +
                ", content='" + content + '\'' +
                ", status=" + status +
                ", createTime=" + createTime +
                '}';
    }
}

1.1 数据访问层

在 dao 包下创建 MessageMapper 接口:

  • 查询当前用户的会话列表,针对每个会话只返回一条最新的私信(根据用户id查询,并且支持分页功能)
  • 查询当前用户的会话数量(根据用户 id 查询)
  • 查询某个会话所包含的私信列表(根据会话 id 查询,并且支持分页功能)
  • 查询某个会话所包含的私信数量(根据会话 id 查询)
  • 查询未读私信的数量(根据用户 id 和 会话 id查询,会话 id 动态拼接)
package com.example.demo.dao;

import com.example.demo.entity.Message;

import java.util.List;

/**
 * 私信列表数据访问层逻辑
 */
public interface MessageMapper {

    //查询当前用户的会话列表,针对每个会话只返回一条最新的私信
    List selectConversations(int userId, int offset, int limit);

    //查询当前用户的会话数量
    int selectConversationCount(int userId);

    //查询某个会话所包含的私信列表
    List selectLetters(String conversationId, int offset, int limit);

    //查询某个会话所包含的私信数量
    int selectLetterCount(String conversationId);

    //查询未读私信的数量
    int selectLetterUnreadCount(int userId, String conversationId);
}

在 resources 资源文件下的 mapper 中添加配置文件message-mapper:





    
    
    
        id, from_id, to_id, conversation_id, content, status, create_time
    

    
    
    
    

    
    

    
    

    
    

1.2 业务层

在 service 包下新建 MessageService 类(业务查询):

  • 定义五个方法,调用 Mapper,实现业务即可,注入 MessageMapper
package com.example.demo.service;

import com.example.demo.dao.MessageMapper;
import com.example.demo.entity.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 私信列表业务组件
 */
@Service
public class MessageService {
    @Autowired
    private MessageMapper messageMapper;

    //查询当前用户的会话列表
    public List findConversations(int userId, int offset, int limit) {
        return messageMapper.selectConversations(userId, offset, limit);
    }

    //查询当前用户的会话数量
    public int findConversationCount(int userId) {
        return messageMapper.selectConversationCount(userId);
    }

    //查询某个会话所包含的私信列表
    public List findLetters(String conversationId, int offset, int limit) {
        return messageMapper.selectLetters(conversationId, offset, limit);
    }

    //查询某个会话所包含的私信数量
    public int findLetterCount(String conversationId) {
        return messageMapper.selectLetterCount(conversationId);
    }

    //查询未读私信的数量
    public int findLetterUnreadCount(int userId, String conversationId) {
        return messageMapper.selectLetterUnreadCount(userId, conversationId);
    }
}

1.3 表现层

在 controller 类下新建 MessageController 类处理私信详情请求:

  • 添加处理私信列表的方法:声明私信路径,请求为 GET 请求;传入 Model、分页 Page
  • 实现查询功能,注入 MessageService
  • 查询当前用户私信用户,注入 HostHolder
  • 设置分页信息(每页显示多少条数据、分页路径、一共多少条数据——查询当前会话的数据、传入 userId,需要获取 User)
  • 查询会话列表得到数据
  • 显示未读数量、每一次会话的未读数量、会话中包含多少条数据

  • 声明集合,用 Map 封装,将多个数据存入 Map 中
  • 遍历列表,新建 HashMap 重构数据:存入遍历的每一次数据、存入未读详细数据(用户 id、会话 id)、存入多少条数量(会话 id)、显示当前用户相对应的用户头像
  • 寻找目标 id:如果当前用户是消息的发起者,目标就是接收人;如果当前对象是消息的接收者,目标就是发起者
  • 将目标对象存入 HashMap 中(注入 UserService)
  • 将得到的 HashMap 存入集合当中,最后传入模板中

7.私信列表 + 发送列表_第3张图片

  • 查询未读消息数量(查询整个用户所有的未读消息数量),传入 Model 中显示,返回 Model 路径(/site/letter)
package com.example.demo.controller;

import com.example.demo.entity.Message;
import com.example.demo.entity.Page;
import com.example.demo.entity.User;
import com.example.demo.service.MessageService;
import com.example.demo.service.UserService;
import com.example.demo.util.HostHolder;
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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 私信列表表现层
 */
@Controller
public class MessageController {

    //实现查询功能,注入 MessageService
    @Autowired
    private MessageService messageService;

    //查询当前用户私信用户,注入 HostHolder
    @Autowired
    private HostHolder hostHolder;

    @Autowired
    private UserService userService;

    //添加处理私信列表的方法
    @RequestMapping(path = "/letter/list", method = RequestMethod.GET)
    public String getLetterList(Model model, Page page) {

        //设置分页信息(每页显示多少条数据、分页路径、一共多少条数据——查询当前会话的数据、传入 userId,需要获取 User)
        User user = hostHolder.getUser();
        page.setLimit(5);
        page.setPath("/letter/list");
        page.setRows(messageService.findConversationCount(user.getId()));

        //查询会话列表得到数据(显示未读数量、每一次会话的未读数量、会话中包含多少条数据)
        //声明集合,用 Map 封装,将多个数据存入 Map 中
        List conversationList = messageService.findConversations(
                user.getId(), page.getOffset(), page.getLimit());
        List> conversations = new ArrayList<>();
        //遍历列表,新建 HashMap 重构数据:存入遍历的每一次数据、存入未读详细数据(用户 id、会话 id)
        // 、存入多少条数量(会话 id)、显示当前用户相对应的用户头像
        if (conversationList != null) {
            for (Message message : conversationList) {
                Map map = new HashMap<>();
                map.put("conversation", message);
                map.put("letterCount", messageService.findLetterCount(message.getConversationId()));
                map.put("unreadCount", messageService.findLetterUnreadCount(user.getId(), message.getConversationId()));

                //寻找目标 id:如果当前用户是消息的发起者,目标就是接收人;如果当前对象是消息的接收者,目标就是发起者
                int targetId = user.getId() == message.getFromId() ? message.getToId() : message.getFromId();

                //将目标对象存入 HashMap 中(注入 UserService)
                map.put("target", userService.findUserById(targetId));
                //将得到的 HashMap 存入集合当中
                conversations.add(map);
            }
        }

        //最后传入模板中
        model.addAttribute("conversations", conversations);

        // 查询未读消息数量(查询整个用户所有的未读消息数量),传入 Model 中显示,返回 Model 路径(/site/letter)
        int letterUnreadCount = messageService.findLetterUnreadCount(user.getId(), null);
        model.addAttribute("letterUnreadCount", letterUnreadCount);

        return "/site/letter";
    }
}

1.4 私信详情

在 controller 类下 MessageController 类添加私信详情方法:

  • 声明访问路径(点击按钮,查看会话详情,需要传入会话 id,在路径中包含会话 id),查询方法为 GET 请求
  • 方法中获取路径中的会话 id 参数,并且支持分页,把模板传入
  • 设置分页信息(每页显示多少条数据、分页路径、行数)
  • 定义私信列表:分页查询(会话 id、分页),用集合表示,Message 封装

7.私信列表 + 发送列表_第4张图片

  • 对发信人进行补充:声明集合,存放 Map
  • 遍历集合:实例化 HashMap,然后放入私信,把 fromId 转化为 fromUser,将 Map 放入集合中
  • 将集合发送给模板

7.私信列表 + 发送列表_第5张图片

  • 补充上述的来自某个人的私信(当前登陆用户与之对话目标的名字,查询当前登录与之对话的用户显示出来)(创建私有方法传入 会话 id,拆封会话 id,与当前用户进行判断)
  • 查询私信目标,返回模板
    //添加私信详情方法
    //声明访问路径(点击按钮,查看会话详情,需要传入会话 id,在路径中包含会话 id),查询方法为 GET 请求
    @RequestMapping(path = "/letter/detail/{conversationId}", method = RequestMethod.GET)
    //方法中获取路径中的会话 id 参数,并且支持分页,把模板传入
    public String getLetterDetail(@PathVariable("conversationId") String conversationId, Page page, Model model) {
        //设置分页信息(每页显示多少条数据、分页路径、行数)
        page.setLimit(5);
        page.setPath("/letter/datail/" + conversationId);
        page.setRows(messageService.findLetterCount(conversationId));

        //定义私信列表:分页查询(会话 id、分页),用集合表示,Message 封装
        List letterList = messageService.findLetters(conversationId, page.getOffset(), page.getLimit());
        //对发信人进行补充:声明集合,存放 Map
        List> letters = new ArrayList<>();
        //遍历集合:实例化 HashMap,然后放入私信,把 fromId 转化为 fromUser,将 Map 放入集合中
        if (letterList != null) {
            for (Message message : letterList) {
                Map map = new HashMap<>();
                map.put("letter", message);
                map.put("fromUser", userService.findUserById(message.getFromId()));
                letters.add(map);
            }
        }
        model.addAttribute("letters", letters);

        // 私信目标——补充上述的来自某个人的私信(当前登陆用户与之对话目标的名字,查询当前登录与之对话的用户显示出来)
        model.addAttribute("target", getLetterTarget(conversationId));

        //查询私信目标,返回模板
        return "/site/letter-detail";
    }
    //创建私有方法传入 会话 id,拆封会话 id,与当前用户进行判断
    private User getLetterTarget(String conversationId) {
        String[] ids = conversationId.split("_");
        int id0 = Integer.parseInt(ids[0]);
        int id1 = Integer.parseInt(ids[1]);

        if (hostHolder.getUser().getId() == id0) {
            return userService.findUserById(id1);
        } else {
            return userService.findUserById(id0);
        }
    }

7.私信列表 + 发送列表_第6张图片

2.发送列表

7.私信列表 + 发送列表_第7张图片

  • 发送私信:采用异步的方式发送私信、发送成功后刷新私信列表
  • 设置已读:访问私信详情时,将显示的私信设置为已读状态

2.1 数据访问层

在 dao 包下的 MessageMapper 中添加消息、修改消息的状态的方法:

    //新增消息
    int insertMessage(Message message);

    //修改消息的状态:修改的状态为多个id,使用集合
    int updateStatues(List ids, int status);

在配置文件 message.xml 实现SQL:

    
    
        from_id, to_id, conversation_id, content, status, create_time
    

    
    
        insert into message()
        values(#{fromId},#{toId},#{conversationId},#{content},#{status},#{createTime})
    

    
    
        update message set status = #{status}
        where id in
        
            #{id}
        
    

2.2 业务层

在 MessageService 中新增消息方法:

  • 过滤标签
  • 过滤敏感词
  • 在创建一个方法:把消息变成已读(支持一次读取多条数据,使用集合)
    //注入敏感词
    @Autowired
    private SensitiveFilter sensitiveFilter;
     
    //增加消息的方法
    public int addMessage(Message message) {
        message.setContent(HtmlUtils.htmlEscape(message.getContent()));
        message.setContent(sensitiveFilter.filter(message.getContent()));
        return messageMapper.insertMessage(message);
    }

    //创建一个方法:把消息变成已读(支持一次读取多条数据,使用集合)
    public int readMessage(List ids) {
        return messageMapper.updateStatus(ids, 1);
    }

2.3 表现层

在 MessageController 中去写增加消息的请求方法:

  • 声明访问路径,请求方式为 POST 请求,提交数据
  • 异步请求添加 @ResponseBody

7.私信列表 + 发送列表_第8张图片

  •  页面表单需要传入 发私信给谁(接收人用户名)、私信内容
  • 通过用户名查询用户得到 id,在 Userservice 添加查询方法:
    //通过用户名查询用户得到 id
    public User findUserByName(String username) {
        return userMapper.selectByName(username);
    }
  • 利用当前数据构造要插入的对象(从当前用户取、发送给谁、会话 id(两个id使用 _ 拼接),id 小的在前面、内容、当前时间)
  • 做插入调用 messageService
  • 如果没报错,给页面返回状态0
  • 如果报错,后面统一处理异常
    //发送私信的方法
    @RequestMapping(path = "/letter/send", method = RequestMethod.POST)
    @ResponseBody //异步请求
    //页面表单需要传入 发私信给谁(接收人用户名)、私信内容
    public String sendLetter(String toName, String content) {
        User target = userService.findUserByName(toName);
        if (target == null) {
            return CommunityUtil.getJSONString(1, "目标用户不存在!");
        }

        //利用当前数据构造要插入的对象(从当前用户取、发送给谁、会话 id(两个id使用 _ 拼接),id 小的在前面、内容、当前时间)
        Message message = new Message();
        message.setFromId(hostHolder.getUser().getId());
        message.setToId(target.getId());
        if (message.getFromId() < message.getToId()) {
            message.setConversationId(message.getFromId() + "_" + message.getToId());
        } else {
            message.setConversationId(message.getToId() + "_" + message.getFromId());
        }
        message.setContent(content);
        message.setCreateTime(new Date());

        //做插入调用 messageService
        messageService.addMessage(message);
        //如果没报错,给页面返回状态0;如果报错,后面统一处理异常
        return CommunityUtil.getJSONString(0);
    }

前端页面 index.xml:

        
		
来自 落基山脉下的闲人 的私信
  • 用户头像

 

前端页面 letter.js:

$(function(){
	$("#sendBtn").click(send_letter);
	$(".close").click(delete_msg);
});

function send_letter() {
	$("#sendModal").modal("hide");

	var toName = $("#recipient-name").val();
	var content = $("#message-text").val();
	$.post(
	    CONTEXT_PATH + "/letter/send",
	    {"toName":toName,"content":content},
	    function(data) {
	        data = $.parseJSON(data);
	        if(data.code == 0) {
	            $("#hintBody").text("发送成功!");
	        } else {
	            $("#hintBody").text(data.msg);
	        }

	        $("#hintModal").modal("show");
            setTimeout(function(){
                $("#hintModal").modal("hide");
                location.reload();
            }, 2000);
	    }
	);
}

function delete_msg() {
	// TODO 删除数据
	$(this).parents(".media").remove();
}

7.私信列表 + 发送列表_第9张图片

当 xiaowen 看数据时,将显示的私信设置为已读状态

2.4 设置已读状态 

私信详情方法 补充将私信列表中未读消息提取出来,自动设置为已读:

  • 在集合中提取消息,补充方法:传入私信列表、实例化集合
  • 遍历数据,判断当前用户是否为接收者,是才能去变为已读并且消息的状态是不是0
     //添加私信详情方法
    //声明访问路径(点击按钮,查看会话详情,需要传入会话 id,在路径中包含会话 id),查询方法为 GET 请求
    @RequestMapping(path = "/letter/detail/{conversationId}", method = RequestMethod.GET)
    //方法中获取路径中的会话 id 参数,并且支持分页,把模板传入
    public String getLetterDetail(@PathVariable("conversationId") String conversationId, Page page, Model model) {
        //设置分页信息(每页显示多少条数据、分页路径、行数)
        page.setLimit(5);
        page.setPath("/letter/detail/" + conversationId);
        page.setRows(messageService.findLetterCount(conversationId));

        //定义私信列表:分页查询(会话 id、分页),用集合表示,Message 封装
        List letterList = messageService.findLetters(conversationId, page.getOffset(), page.getLimit());
        //对发信人进行补充:声明集合,存放 Map
        List> letters = new ArrayList<>();
        //遍历集合:实例化 HashMap,然后放入私信,把 fromId 转化为 fromUser,将 Map 放入集合中
        if (letterList != null) {
            for (Message message : letterList) {
                Map map = new HashMap<>();
                map.put("letter", message);
                map.put("fromUser", userService.findUserById(message.getFromId()));
                letters.add(map);
            }
        }
        model.addAttribute("letters", letters);

        // 私信目标——补充上述的来自某个人的私信(当前登陆用户与之对话目标的名字,查询当前登录与之对话的用户显示出来)
        model.addAttribute("target", getLetterTarget(conversationId));

        // 设置已读
        List ids = getLetterIds(letterList);
        if (!ids.isEmpty()) {
            messageService.readMessage(ids);
        }

        //查询私信目标,返回模板
        return "/site/letter-detail";
    }

    //在集合中提取消息
    private List getLetterIds(List letterList) {
        List ids = new ArrayList<>();

        if (letterList != null) {
            for (Message message : letterList) {
                if (hostHolder.getUser().getId() == message.getToId() && message.getStatus() == 0) {
                    ids.add(message.getId());
                }
            }
        }

        return ids;
    }

7.私信列表 + 发送列表_第10张图片

7.私信列表 + 发送列表_第11张图片

你可能感兴趣的:(论坛系统,个人论坛系统,spring,boot,spting,mvc,mybatis,redis,kafka,elasticsearch)