大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全家桶1年46,售后保障稳定
在线聊天系统
需求场景模拟
1.移动端给客服发送消息,客户在bs端后台收到消息并回复(本文以一个客服为例)
2.左侧聊天栏显示最新的消息和消息时间
3.需要查看对方是否已读自己的消息
开发需求
一、技术选型
使用websocket进行消息推送
优点:个人感觉开发简单,不需要部署第三方服务
缺点:无状态,页面每刷新一次就会产生一个新的session,某些情况下不稳定
还是那句话,技术没有什么好与坏,只有合适不合适,同时最终采用技术栈意味着你能
忍受它的缺点
二、需求分析
1.发送消息意味着需要发送人和接收人两个角色,同时需要对用户进行持久化
2.对接收人(发送人)来说,显示最新的消息和时间,就意味着显示双方消息记录的最后提条消息的内容和发送时间
3.消息已读意味着打开聊天对话框就要告诉对方,自己已读对方的消息。这里会产生两种情况:
①己方在线对方未在线,需要在对方上线时(即打开对话框)告诉对方自己已读对方的消息
解决方案
:存储消息数据,在自己打开对框的时候,获取聊天记录,并将聊天记录中对方给自己发的消息状态全部更新为已读。
②双方同时在线(聊天对话界面),这里稍微有点操作,那就是如何让双方及时的知道对方已读自己的消息。
场景及解决方案
:
场景:当自己给对方发送消息时,自己看到自己发给对方的消息已读(即便对方不给自己发消息)
解决
:
1.自己对对方发消息时,更新对方发给自己的全部消息为已读,对方读取消息
2.对方读取消息时,让对方告诉自己对方已读自己的消息,自己进行已读展示,通过一个共用接 口即可,当对方调用指定接口时,让对方告诉自己对方已读即可。
4.利用mongodb进行用户以及聊天记录的存储
效果演示
消息聊天演示:
消息时间演示:
消息未读演示:
软件需求实现
1.技术架构
PC端:vue+springboot
移动端:html+springboot
2.实现流程图:(仅供参考
)
一、数据库设计
1.sys_user
字段 | 说明 |
---|---|
userId | 用户id |
nickName | 昵称 |
heardUrl | 头像地址 |
sex | 性别 |
2.chat_msg
字段 | 说明 |
---|---|
createTime | 创建时间 |
msgKey | 通信key(sendId_receiveId) |
chatMsg | 通信消息 |
sendId | 发送id |
receiveId | 接收id |
readState | 查看状态 0未看 1已看 |
二、代码实现
说明:代码有所删减修改,但核心代码存在!!!请选择性复用代码
1.web端
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>9.0.39</version>
</dependency>
配置yml
#开发时服务端口号,部署无效
server:
port: 9019
servlet:
context-path: fmis
spring:
data:
mongodb:
host: 192.168.1.125
port: 27017
database: cangzhou
1.前端代码
index.vue
<template>
<div :class="classObj" class="app-wrapper">
<Logo></Logo>
<div class="clearfix"></div>
<sidebar class="sidebar-container" />
<div class="communicate" >
<el-button type="text" @click="talkRoomVisible = true" :class="{ breathing: unReadMessageNum && talkRoomVisible ==false}">
//对话图标
<img src="../../static/images/login/tips.png" alt />
</el-button>
</div>
<CommunicationInterface style=" position: absolute; z-index: 1000; top: 0; right: 0; left: 0; margin: auto; " v-if="talkRoomVisible" :userList="userList" />
</div>
</template>
<script> import message from "./mixin/message"; import CommunicationInterface from "@/dialog/chat.vue"; export default {
name: "Layout", components: {
Navbar, Sidebar, AppMain, Logo, CommunicationInterface, }, data() {
return {
}; }, mixins: [ResizeMixin, message], computed: {
sidebar() {
return this.$store.state.app.sidebar; }, device() {
return this.$store.state.app.device; }, fixedHeader() {
return this.$store.state.settings.fixedHeader; }, classObj() {
return {
hideSidebar: !this.sidebar.opened, openSidebar: this.sidebar.opened, withoutAnimation: this.sidebar.withoutAnimation, mobile: this.device === "mobile", }; }, unreadList() {
return this.userList.filter((e) => {
return e.unReadMsgNum > 0; }); }, }, methods: {
handleClickOutside() {
this.$store.dispatch("app/closeSideBar", {
withoutAnimation: false }); }, }, }; </script>
<style lang="scss" scoped> @import "~@/styles/mixin.scss"; @import "~@/styles/variables.scss"; .breathing {
animation: breathe 1s infinite; } @keyframes breathe {
0% {
opacity: 0.1; } 50% {
opacity: 1; } 100% {
opacity: 0.1; } } .hoverVisibleUnreadList{
position: absolute; bottom: 35px; right: -50px; width: 180px; line-height: 35px; display: none; border-radius: 3px; box-shadow: 0 0 2px #888888; } .communicate:hover .hoverVisibleUnreadList{
display: block } .app-wrapper {
@include clearfix; position: relative; height: 100%; width: 100%; &.mobile.openSidebar {
position: fixed; top: 0; } } .drawer-bg {
background: #000; opacity: 0.3; width: 100%; top: 0; height: 100%; position: absolute; z-index: 999; } .fixed-header {
position: fixed; top: 0; right: 0; z-index: 9; width: calc(100% - 0); // calc(100% - #{
$sideBarWidth}) transition: width 0.28s; } .hideSidebar .fixed-header {
width: calc(100% - 0px); } .mobile .fixed-header {
width: 100%; } .communicate {
position: absolute; z-index: 2000; height: 50px; width: 50px; bottom: 50px; right: 50px; border-radius: 50%; img {
width: 50px; } } </style>
chat.vue
<template>
<div>
<div class="box">
<div class="min">
<ul class="contactList">
<h3 style="border-bottom: 0.5px solid #337bf1">联系人列表</h3>
<li v-for="item in userListSortByLastTime" :key="item.nickName" @click="CreateConnection(item)" :class="{ red: item.userId === userId }" >
<div class="leftLi">
<!-- <img :src="require('../../../static/images/login/titleboy.png')" /> -->
<img :src="item.heardUrl" />
<div class="ListItem">
<div>
<div class="nickName">{
{ item.nickName }}</div>
<span style="vertical-align: top">{
{
item.lastMsgTime | dateFormat
}}</span>
</div>
<div class="ellipsis">
{
{ item.lastMsg }}
<span v-if="item.unReadMsgNum > 0">{
{
[item.unReadMsgNum]
}}</span>
</div>
</div>
<div class="delete" @click="delUserByUserId(item)">删除</div>
</div>
</li>
</ul>
<div class="chat">
<h3>{
{ contactsName || "聊天区域" }}</h3>
<div class="content" ref="reference">
<ul style="color: black">
<li v-for="item in content" :key="item.id" :style="item.flag ? 'text-align: right;' : 'text-align: left;'" >
<span>
<!-- <img v-show="!item.flag" :src="require('../../../static/images/login/titleboy.png')" /> -->
<img v-show="!item.flag" :src="heardUrl" />
<span class="times" v-show="item.flag">{
{
item.createTime
? item.createTime.substr(11, item.createTime.length)
: ""
}}</span>
<span :class="item.flag ? 'i' : 'he'">{
{ item.name }}</span>
<span class="time" v-show="!item.flag">{
{
item.createTime
? item.createTime.substr(11, item.createTime.length)
: ""
}}</span>
<img v-show="item.flag" :src="require('../../../static/images/login/titleboy.png')" />
<!-- <img v-show="item.flag" :src="heardUrl" /> -->
<div class="readOrUnread" v-if="item.flag">
{
{ item.readState == "1" ? "已读" : "未读" }}
</div>
</span>
</li>
</ul>
</div>
<div class="input">
<textarea cols="50" rows="10" v-model="text" @keydown.enter="submit" ></textarea>
</div>
</div>
</div>
</div>
</div>
</template>
<script> // import axios from 'axios' import * as API from "@/api/systemApplication"; import {
dateFormat } from "@/utils/index"; export default {
props: {
dialogVisible: {
type: Boolean, default: false, }, userList: {
type: Array, required: true, }, }, data() {
return {
// dialogVisible: true c: null, text: null, //输入的消息 content: [], //内容列表 scoket: "", sendId: 1, userId: "", contactsName: "", URL: window.ROOT, heardUrl: "", //右侧聊天框头像 }; }, computed: {
userListSortByLastTime() {
// 做排序,最新接收到的消息放在列表的最上面,需要后端提供年月日时分秒 return this.userList.sort((a, b) => {
let at = a.lastMsgTime ? `${
a.lastMsgTime}` : "1970-01-01 00:00:00"; // console.log(at,"at") let bt = b.lastMsgTime ? `${
b.lastMsgTime}` : "1970-01-01 00:00:00"; // console.log(bt,"bt") return new Date(bt).getTime() - new Date(at).getTime(); }); }, }, mounted() {
// 因为上面用了v-if 所以每次这个组件出来 都会走mounted this.userId = this.userList[0].userId; this.heardUrl = this.userList[0].heardUrl; // 获取当前聊天人的消息 this.getSelectedUserMessageList(); // 接收ws消息 this.$root.$on("pushNewMessage", this.pushNewMessage); this.$root.$emit("changeUnReadMsgNum", {
userId: this.userId, }); }, destroyed() {
// 取消接收ws消息 this.$root.$off("pushNewMessage", this.pushNewMessage); }, filters: {
dateFormat(v) {
if (!v) {
return; } // 如果是昨天发的消息,左侧列表中展示的时间只显示月、日 if (v.substr(0, 10) !== dateFormat(new Date()).substr(0, 10)) {
return dateFormat(v, "MM-DD"); } // 如果是今天发的消息,左侧列表中展示的时间显示时、分 return dateFormat(v, "HH:mm"); }, }, methods: {
delUserByUserId(item) {
this.$root.$emit("loadUserList", {
userId:item.userId, }); }, // 获取历史记录 getSelectedUserMessageList() {
API["storeHouseChatMsgHistory"]({
sendId: `${
this.sendId}`, receiveId: this.userId, pageSize: "100", currentPage: "1", }).then((res) => {
const {
data } = res; this.content = data.list.reverse(); this.scrollAuto(); }); }, pushNewMessage(news) {
if (news.code == 0) {
console.log(11112, news); for (var i = 0; i < this.content.length; i++) {
this.content[i].readState = 1; } return; } // 接收到的新消息 if (news.sendId != this.userId) return; // 这里判断id对不对再推数据 this.content.push({
flag: 0, name: news.chatMsg, readState: "0", }); this.scrollAuto(); // 这里是为了做消除用户列表中的未读,也就是未读变为已读,告诉后端消息已读 API["msgRead"]({
sendId: `${
this.sendId}`, receiveId: `${
this.userId}`, }); // 更改前端页面上的数据,不再提示几条未读 this.$root.$emit("changeUnReadMsgNum", {
userId: news.sendId, }); // if(news.code ==0){
// for(var i=0;i<this.content.length;i++){
// this.content[i].readState=1 // } // } }, // 按enter键(也就是要发送消息) submit() {
if (!this.text) {
return; } this.content.push({
flag: 1, name: this.text, readState: "0", }); // 修改左侧列表上展示的最后一条消息和时间 this.$root.$emit("changeLast", {
lastMsg: this.text, lastMsgTime: dateFormat(Date.now()), userId: this.userId, }); this.$root.$talkRoomWs.send( JSON.stringify({
linkType: "msg", sendId: `${
this.sendId}`, userId: this.sendId, receiveId: this.userId, msgKey: `${
this.sendId}_${
this.userId}`, chatMsg: this.text, readState: "0", }) ); this.text = null; this.scrollAuto(); }, // 这里是点击左侧成员列表时执行的函数 CreateConnection(item) {
if (this.userId === item.userId) return; this.contactsName = item.nickName; this.text = ""; this.content = []; this.userId = item.userId; this.getSelectedUserMessageList(); this.$root.$emit("changeUnReadMsgNum", item); API["msgRead"]({
sendId: `${
this.sendId}`, receiveId: `${
this.userId}`, }); // 点击左侧列表时,聊天框中的头像也要切换 for (var i = 0; i < this.userList.length; i++) {
if (this.userList[i].userId == item.userId) {
this.heardUrl = this.userList[i].heardUrl; } } }, scrollAuto() {
this.$nextTick(() => {
this.$refs["reference"].scrollTop = this.$refs["reference"].scrollHeight; }); }, }, }; </script>
<style lang="scss" scoped> h3 {
text-align: center; height: 40px; line-height: 40px; border-bottom: 0.5px solid #ccc; font-size: 16px; font-weight: 300; } .box {
margin-top: 150px; margin-left: 28%; width: 900px; border-radius: 10px; overflow: hidden; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04); .min {
display: flex; .contactList {
list-style: none; overflow: auto; height: 600px; width: 260px; background: #4387f6; color: azure; padding: 0px 5px; padding-left: 5px; .red {
background: #5d9aff; border-radius: 10px; } li {
cursor: pointer; text-align: left; box-sizing: border-box; padding: 14px 0px; padding-left: 5px; height: 65px; } .leftLi {
@extend .min; img {
height: 40px; display: block; } .ListItem {
@extend .min; padding-left: 5px; flex-direction: column; } div :first-child {
height: 30px; line-height: 20px; span {
color: #bed7ff; font-size: 12px; margin-left: 15px; } } div :last-child {
line-height: 0px; color: #bed7ff; font-size: 12px; span {
text-align: center; border-radius: 3px; } } } } .chat {
background: #f3f3f3; width: 700px; height: 600px; @extend .min; flex-direction: column; .content {
overflow: auto; height: 500px; span {
display: inline-block; padding: 0px 5px; line-height: 28px; @mixin name($px) {
transition: 0.5s; opacity: 0; transform: translate($px); } .time {
@include name(-20px); } .times {
@include name(20px); } } span:hover .time {
opacity: 1; transform: translate(0px); } span:hover .times {
opacity: 1; transform: translate(0px); } @mixin Bubble($color) {
background: $color; border-radius: 5px; border-bottom-left-radius: 20px; } .i {
color: #f3f3f3; @include Bubble(#5d9aff); max-width: 65%; text-align: left; word-wrap: break-word; word-break: break-all; overflow: hidden; padding: 8px 5px; } .he {
@include Bubble(#e9e9e9); max-width: 65%; word-wrap: break-word; word-break: break-all; overflow: hidden; padding: 8px 5px; } } .input {
height: 180px; border-top: 0.5px solid #f3f3f3; textarea {
width: 100%; border: 0px; resize: none; } } } } } ul > li {
width: 100px; text-align: center; width: 100%; margin-top: 3px; } img {
height: 45px; vertical-align: top; border-radius: 50%; } .content li > span {
position: relative; } .content li {
margin-top: 15px; } .readOrUnread {
font-size: 12px; margin-right: 47px; line-height: 12px; } .ellipsis {
width: 100px; height: 12px; line-height: 12px !important; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .nickName {
display: inline-block; width: 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .leftLi {
position: relative; } .delete {
position: absolute; bottom: 3px; right: 45px; color: #fff; } </style>
message.js
import * as API from "@/api/systemApplication";
export default {
data() {
return {
sendId: 1, // todo 客服id,默认为1
scoket: null,
userList: [], //联系人列表
talkRoomVisible: false,
}
},
computed: {
// 未读消息的数量
unReadMessageNum() {
let unReadNum = 0;
for (let i = 0; i < this.userList.length; i++) {
const e = this.userList[i];
// 注意这里的unReadMsgNum可能不是数字
if (e.unReadMsgNum && typeof e.unReadMsgNum == 'number') {
unReadNum += e.unReadMsgNum
}
}
return unReadNum
}
},
mounted() {
// 初始化ws
this.initWs();
// 获取左侧用户列表
this.getList();
// 如果聊天窗口是开启状态,按esc键,则关闭聊天窗口
this.initCloseTalkRoom()
// 修改前端页面上左侧列表展示的未读条数
this.$root.$on("changeUnReadMsgNum", this.changeUnReadMsgNum);
// 修改左侧列表上展示的最后一条消息和时间
this.$root.$on("changeLast", this.changeLast);
// 删除聊天室左侧列表中的项,再重新加载用户列表
this.$root.$on("loadUserList", this.loadUserList);
},
methods: {
initWs() {
// let url = this.URL;
// this.$root.$talkRoomWs = new WebSocket("ws://192.168.1.169:9019/fmis-api/ws/asset");
let url = window.ROOT;
this.$root.$talkRoomWs = new WebSocket(`${
url.replace("http", "ws")}/ws/asset`);
let ws = this.$root.$talkRoomWs;
ws.onopen = (e) => {
console.log(`WebSocket 连接状态: ${
ws.readyState}`);
};
ws.onmessage = (data) => {
try {
let news = JSON.parse(data.data)
// 用新信息覆盖旧消息
if (news.unReadNumLst) {
for (let i = 0; i < news.unReadNumLst.length; i++) {
const e = news.unReadNumLst[i];
let index = this.userList.findIndex(item => item.userId == e.userId)
if (index > -1) {
// this.userList[index].lastMsg = e.lastMsg
// this.userList[index].lastMsgTime = e.lastMsgTime
// this.userList[index].unReadMsgNum = e.unReadMsgNum
Object.assign(this.userList[index], e)
} else {
// todo 新增的逻辑
this.userList.push(e)
}
}
}
this.$root.$emit('pushNewMessage', news)
} catch (err) {
// console.log(err);
}
};
ws.onclose = (data) => {
console.log("WebSocket连接已关闭");
};
setTimeout(() => {
ws.send(
JSON.stringify({
linkType: "bind",
sendId: this.sendId,
})
);
}, 500);
},
// 获取左侧的用户列表
getList() {
API["storeHouseWsUserList"]({
sendId: this.sendId,
userId: this.sendId,
}).then((res) => {
const {
data } = res;
this.userList = data;
});
},
// 如果聊天窗口是开启状态,按esc键,则关闭聊天窗口
initCloseTalkRoom() {
window["onkeydown"] = (e) => {
if (e.keyCode === 27 && this.talkRoomVisible) {
this.talkRoomVisible = false
}
};
},
// 修改前端页面上左侧列表展示的未读条数
changeUnReadMsgNum(item) {
let index = this.userList.findIndex((e) => e.userId == item.userId);
console.log(index);
if (index > -1) {
this.userList[index].unReadMsgNum = 0;
}
console.log(this.userList[index].unReadMsgNum);
},
// 修改左侧列表上展示的最后一条消息和时间
changeLast(obj) {
this.userList.find((item) => {
if (item.userId === obj.userId) {
item.lastMsg = obj.lastMsg;
item.lastMsgTime = obj.lastMsgTime;
}
});
},
loadUserList(item) {
console.log(item,"item")
let postData= {
userId:item.userId
}
API["delUserByUserId"](postData).then((res) => {
console.log(res);
if (res.code) {
this.$message({
message: res.message,
type: "success",
});
this.getList()
}
});
}
}
}
systemApplication.js
// 获取列表
export function storeHouseWsUserList(data) {
return request({
url: '/chat/userList',
method: 'post',
data
})
}
// 获取历史连天记录
export function storeHouseChatMsgHistory(data) {
return request({
url: '/chat/msgHistory',
method: 'post',
data
})
}
// 已读未读
export function msgRead(data) {
return request({
url: '/chat/msgRead',
method: 'post',
data
})
}
// 删除左侧列表中的项
export function delUserByUserId(data) {
return request({
url: '/chat/delUserByUserId',
method: 'post',
data
})
}
2.后端代码
WebSocketServer
import com.alibaba.fastjson.JSONObject;
import com.jinmdz.fmis.api.api.model.storehouse.chat.ChatMsg;
import com.jinmdz.fmis.api.global.CacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
/** * @author lvyq * @version 1.0 * @description: TODO * @date 2021/8/17 16:30 */
@ServerEndpoint(value = "/ws/asset")
@Component
public class WebSocketServer {
private static ChatService chatService;
@Autowired
public void setChatService(ChatService chatService) {
WebSocketServer.chatService = chatService;
}
@PostConstruct
public void init() {
System.out.println("websocket 加载");
}
private static Logger log = LoggerFactory.getLogger(WebSocketServer.class);
private static final AtomicInteger OnlineCount = new AtomicInteger(0);
// concurrent包的线程安全Set,用来存放每个客户端对应的Session对象。
private static CopyOnWriteArraySet<Session> SessionSet = new CopyOnWriteArraySet<Session>();
/** * 连接建立成功调用的方法 */
@OnOpen
public void onOpen(Session session) {
SessionSet.add(session);
int cnt = OnlineCount.incrementAndGet();
log.info("有连接加入,当前连接数为:{}", cnt);
SendMessage(session, "连接成功");
}
/** * 连接关闭调用的方法 */
@OnClose
public void onClose(Session session) {
SessionSet.remove(session);
int cnt = OnlineCount.decrementAndGet();
log.info("有连接关闭,当前连接数为:{}", cnt);
}
/** * 收到客户端消息后调用的方法 * @param message 客户端发送过来的消息 */
@OnMessage
public void onMessage(String message, Session session) {
log.info("来自客户端的消息:{}",message);
try{
JSONObject jsonObject = JSONObject.parseObject(message);
String linkType = jsonObject.getString("linkType");
String sendId = jsonObject.getString("sendId");
if (linkType.equals("bind")){
CacheManager.set("bind_"+sendId,session);
SendMessage(session, "连接成功");
}else if (linkType.equals("msg")){
//聊天
ChatMsg msg = new ChatMsg();
//发消息
String chatMsg = jsonObject.getString("chatMsg");
String receiveId = jsonObject.getString("receiveId");
msg.setChatMsg(chatMsg);
msg.setSendId(sendId);
msg.setMsgKey(sendId+"_"+receiveId);
msg.setReceiveId(receiveId);
msg.setReadState("0");
chatService.sendOne(msg);}
}catch (Exception e){
e.printStackTrace();
}
}
/** * 出现错误 * @param session * @param error */
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误:{},Session ID: {}",error.getMessage(),session.getId());
error.printStackTrace();
}
/** * 发送消息,实践表明,每次浏览器刷新,session会发生变化。 * @param session * @param message */
public static void SendMessage(Session session, String message) {
try {
//session.getBasicRemote().sendText(String.format("%s (From Server,Session ID=%s)",message,session.getId()));
log.info("sessionID="+session.getId());
session.getBasicRemote().sendText(message);
} catch (IOException e) {
log.error("发送消息出错:{}", e.getMessage());
e.printStackTrace();
}
}
/** * 指定Session发送消息 * @param sessionId * @param message * @throws IOException */
public static void SendMessageById(String message,String sessionId) throws IOException {
Session session = null;
for (Session s : SessionSet) {
if(s.getId().equals(sessionId)){
session = s;
break;
}
}
if(session!=null){
SendMessage(session, message);
}
else{
log.warn("没有找到你指定ID的会话:{}",sessionId);
}
}
/** * @description: 指定发送 * @author: lvyq * @date: 2021/9/24 11:30 * @version 1.0 */
public static void SendMessageByRecId(String message,String receiveId) throws IOException {
Session session= CacheManager.get("bind_"+receiveId);
String sessionId = "";
if (session!=null){
sessionId=session.getId();
}
for (Session s : SessionSet) {
if(s.getId().equals(sessionId)){
session = s;
break;
}
}
if(session!=null){
SendMessage(session, message);
}
else{
log.warn("没有找到你指定ID的会话:{}",sessionId);
}
}
ChatController
import com.jinmdz.fmis.api.api.model.storehouse.chat.ChatMsg;
import com.jinmdz.fmis.api.api.model.storehouse.chat.SysUser;
import com.jinmdz.fmis.api.api.service.ChatService;
import com.jinmdz.fmis.api.api.service.WebSocketServer;
import com.jinmdz.fmis.api.base.BaseController;
import com.jinmdz.fmis.core.base.BaseResult;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.IOException;
/** * @author lvyq * @version 1.0 * @description: TODO-消息通信 * @date 2021/9/26 14:50 */
@RestController
@RequestMapping("/chat")
public class ChatController extends BaseController {
@Resource
private ChatService chatService;
@Resource
private WebSocketServer webSocketServer;
/** * @description: 消息记录 * @author: lvyq * @date: 2021/9/26 15:19 * @version 1.0 */
@PostMapping("/msgHistory")
public BaseResult msgHistory(@RequestBody ChatMsg data) throws IOException {
return chatService.msgHistory(data);
}
/** * @description: 消息已读 * @author: lvyq * @date: 2021/9/26 16:27 * @version 1.0 */
@PostMapping("/msgRead")
private BaseResult msgRead(@RequestBody ChatMsg data) throws IOException {
return chatService.msgRead(data);
}
/** * @description: 全体发送 * @author: lvyq * @date: 2021/11/11 13:38 * @version 1.0 */
@GetMapping("/sendAll/{msg}")
public void sendAll(@PathVariable("msg") String msg) throws IOException {
WebSocketServer.BroadCastInfo(msg);
}
/** * @description: 发消息给某人 * @author: lvyq * @date: 2021/9/24 11:15 * @version 1.0 */
@PostMapping("/sendOne")
public void sendOne(@RequestBody ChatMsg data) throws IOException {
chatService.sendOne(data);
}
/** * @description: 获取用户列表 * @author: lvyq * @date: 2021/9/24 13:43 * @version 1.0 */
@PostMapping("/userList")
private BaseResult userList(@RequestBody SysUser data){
return chatService.userListDev(data);
}
/** * @description: 根据userId删除用户 * @author: lvyq * @date: 2021/11/19 13:29 * @version 1.0 */
@PostMapping("/delUserByUserId")
public BaseResult delUserByUserId(@RequestBody SysUser data){
return chatService.delUserByUserId(data.getUserId());
}
}
ChatService
import com.alibaba.fastjson.JSONObject;
import com.jinmdz.fmis.api.api.model.storehouse.chat.ChatMsg;
import com.jinmdz.fmis.api.api.model.storehouse.chat.SysUser;
import com.jinmdz.fmis.api.api.service.repository.SysUserRepository;
import com.jinmdz.fmis.api.base.BaseService;
import com.jinmdz.fmis.api.model.system.UserItem;
import com.jinmdz.fmis.core.base.BaseResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** * @author lvyq * @version 1.0 * @description: TODO * @date 2021/9/24 10:06 */
@Service
public class ChatService extends BaseService {
@Resource
private MongoTemplate mongoTemplate;
/** * @description: 获取用户列表 * @author: lvyq * @date: 2021/9/24 10:12 * @version 1.0 */
public BaseResult userList(UserItem userItem, SysUser data) {
String receiveId = userItem.getId().toString();
List<SysUser> sysUserList = userLst(receiveId);
return successData(sysUserList);
}
/** * @description: 发消息给某人 * @author: lvyq * @date: 2021/9/24 11:16 * @version 1.0 */
public void sendOne(ChatMsg data) throws IOException {
mongoTemplate.save(data);
//TODO 更新消息 接收者_发送者
String msg_key = data.getReceiveId()+"_"+data.getSendId();
String receiveId = data.getReceiveId();
HashMap<String,Object> map = new HashMap<>();
JSONObject mav = new JSONObject();
Query queryMsg = new Query().addCriteria(Criteria.where("readState").is("0").and("msgKey").is(msg_key));
Update update = new Update().set("readState","1");
//批量修改
mongoTemplate.updateMulti(queryMsg,update,ChatMsg.class,"chat_msg");
mav.put("sendId",data.getSendId());
mav.put("chatMsg",data.getChatMsg());
mav.put("unReadNumLst",userLst(receiveId));
WebSocketServer.SendMessageByRecId(mav.toJSONString(),receiveId);
}
/** * @description: 消息列表信息-unLogin * @author: lvyq * @date: 2021/9/26 17:50 * @version 1.0 */
public BaseResult userListDev(SysUser data) {
String receiveId = data.getUserId();
List<SysUser> sysUserList = userLst(receiveId);
return successData(sysUserList);
}
/** * @description: 消息记录 * @author: lvyq * @date: 2021/9/26 15:20 * @version 1.0 */
public BaseResult msgHistory(ChatMsg data) throws IOException {
int page = data.getCurrentPage();
if (page<0){
page=1;
}
page=page-1;
int size = data.getPageSize();
if (size<0){
size=20;
}
if (StringUtils.isNotEmpty(data.getSendId()) && StringUtils.isNotEmpty(data.getReceiveId())){
String msgKeyOne= data.getSendId()+"_"+data.getReceiveId();
String msgKeyTwo = data.getReceiveId()+"_"+data.getSendId();
Criteria orCri1 = new Criteria();
Criteria orCri2 = new Criteria();
orCri1.andOperator(Criteria.where("msgKey").is(msgKeyOne));
orCri2.andOperator(Criteria.where("msgKey").is(msgKeyTwo));
Query query = new Query().addCriteria(new Criteria().orOperator(orCri1,orCri2));
long total = mongoTemplate.count(query,ChatMsg.class);
Pageable pageable = PageRequest.of(page,size, Sort.by(Sort.Direction.DESC,"createTime"));
query.with(pageable);
List<ChatMsg> list = mongoTemplate.find(query,ChatMsg.class);
HashMap<String, Object> map = new HashMap<>();
if (list != null) {
for (ChatMsg chatMsg:list){
chatMsg.setName(chatMsg.getChatMsg());
if (chatMsg.getSendId().equals(data.getSendId())){
chatMsg.setFlag(1);
}else {
chatMsg.setFlag(0);
}
}
Map<String, Object> pageMap = new HashMap<>();
map.put("list", list);
pageMap.put("total", total);
pageMap.put("pageSize", data.getPageSize());
pageMap.put("currentPage", data.getCurrentPage());
map.put("pager", pageMap);
}
Query queryMsg = new Query().addCriteria(Criteria.where("readState").is("0").and("sendId").is(data.getReceiveId()).and("receiveId").is(data.getSendId()));
Update update = new Update().set("readState","1");
mongoTemplate.updateMulti(queryMsg,update,ChatMsg.class,"chat_msg");
//消息已读通知
/*JSONObject mav = new JSONObject(); mav.put("state",true); mav.put("msg","消息已读"); WebSocketServer.SendMessageByRecId(mav.toJSONString(),data.getReceiveId());*/
return successData(map);
}else {
return failure("非法参数");
}
}
/** * @description: 将消息修改为已读 * @author: lvyq * @date: 2021/9/26 16:27 * @version 1.0 */
public BaseResult msgRead(ChatMsg data) throws IOException {
Query query = new Query().addCriteria(Criteria.where("readState").is("0").and("sendId").is(data.getReceiveId()).and("receiveId").is(data.getSendId()));
Update update = new Update().set("readState","1");
mongoTemplate.updateMulti(query,update,ChatMsg.class,"chat_msg");
//消息已读通知
JSONObject mav = new JSONObject();
mav.put("state",true);
mav.put("msg","消息已读");
mav.put("code",0);
WebSocketServer.SendMessageByRecId(mav.toJSONString(),data.getReceiveId());
return success("操作成功");
}
/** * @description: 获取集合 * @author: lvyq * @date: 2021/9/26 17:46 * @version 1.0 */
private List<SysUser> userLst(String receiveId){
List<SysUser> sysUserList = mongoTemplate.findAll(SysUser.class);
for (SysUser sysUser:sysUserList){
String sendId = sysUser.getUserId();
String msgKey = sendId+"_"+receiveId;
if (sendId.equals(receiveId)){
continue;
}
//最新一条记录
String msgKeyOne= sendId+"_"+receiveId;
String msgKeyTwo = receiveId+"_"+sendId;
Criteria orCri1 = new Criteria();
Criteria orCri2 = new Criteria();
orCri1.andOperator(Criteria.where("msgKey").is(msgKeyOne));
orCri2.andOperator(Criteria.where("msgKey").is(msgKeyTwo));
Query msgQuery = new Query().addCriteria(new Criteria().orOperator(orCri1,orCri2));
Pageable pageable = PageRequest.of(0,1, Sort.by(Sort.Direction.DESC,"createTime"));
msgQuery.with(pageable);
List<ChatMsg> list = mongoTemplate.find(msgQuery,ChatMsg.class);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
if (list.size()>0){
sysUser.setLastMsg(list.get(0).getChatMsg());
sysUser.setLastMsgTime(simpleDateFormat.format(list.get(0).getCreateTime()));
}else {
sysUser.setLastMsg("");
sysUser.setLastMsgTime("");
}
Query query = new Query().addCriteria(Criteria.where("readState").is("0").and("msgKey").is(msgKey));
long unReadNum = mongoTemplate.count(query, ChatMsg.class);
sysUser.setUnReadMsgNum(unReadNum);
}
return sysUserList;
}
/** * @description:时间转换 * @author: lvyq * @date: 2021/9/27 16:48 * @version 1.0 */
private String changeTime(Date createTime) {
Date date = new Date();
SimpleDateFormat formatDay = new SimpleDateFormat("MM-dd");
if (formatDay.format(date).equals(formatDay.format(createTime))){
SimpleDateFormat formatMin = new SimpleDateFormat("HH:mm");
return formatMin.format(createTime);
}else {
return formatDay.format(createTime);
}
}
/** * @description: 根据userId删除用户 * @author: lvyq * @date: 2021/11/19 13:29 * @version 1.0 */
public BaseResult delUserByUserId(String userId) {
Query query = new Query().addCriteria(Criteria.where("userId").is(userId));
mongoTemplate.findAndRemove(query,SysUser.class);
return success("操作成功");
}
}
ChatMsg
import com.fasterxml.jackson.annotation.JsonFormat;
import com.jinmdz.fmis.core.base.BasePageData;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
/** * @author lvyq * @version 1.0 * @description: 消息通信 * @date 2021/9/24 9:00 */
@Data
@Document("chat_msg")
public class ChatMsg extends BasePageData {
@Id
private String id;
/** * 创建时间 */
@JsonFormat(pattern = yyyy_MM_dd_HH_mm_ss)
private Date createTime=new Date();
/** * 通信key(sendId_receiveId) */
private String msgKey;
/** * 通信消息 */
private String chatMsg;
/** * 发送id */
private String sendId;
/** * 接收id */
private String receiveId;
/** * 查看状态 0未看 1已看 */
private String readState;
/** *1为我 0 为他 */
@Transient
private Integer flag;
@Transient
private String name;
}
SysUser
import com.jinmdz.fmis.core.base.BasePageData;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;
/** * @author lvyq * @version 1.0 * @description: TODO * @date 2021/9/24 9:14 */
@Data
@Document("sys_user")
public class SysUser extends BasePageData {
@Id
private String id;
/** * 用户id */
private String userId;
/** * 昵称 */
private String nickName;
/** * 头像地址 */
private String heardUrl;
/** * 性别 */
private Integer sex;
/** * 登录状态 0未登录 1已登录 */
private Integer loginState;
/** * 用户发给自己且未读的消息数 */
@Transient
private long unReadMsgNum;
/** * 最新一条消息 */
@Transient
private String lastMsg;
/** * 最新一条消息时间 */
@Transient
private String lastMsgTime;
}
2.移动端
1.前端代码:
说明:userid在登录系统时存储在了cookie中
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
<title>问题解答</title>
<script src="../../common/js/GBCookie.js"></script>
<style type="text/css"> body {
overflow: hidden; } h3 {
text-align: center; height: 40px; line-height: 40px; border-bottom: 0.5px solid #ccc; font-size: 16px; font-weight: 300; } .chat {
background: #f3f3f3; /*width: 700px;*/ /*height: 600px;*/ width: 100vw; height: 100vh; } .chat > h3 {
height: 5vh; line-height: 5vh; } .content {
overflow: auto; /*height: 500px;*/ height: 75vh; } ul {
list-style: none; } ul > li {
width: 100px; text-align: center; line-height: 50px; width: 100%; margin-top: 3px; } img {
height: 45px; vertical-align: bottom; border-radius: 50%; } .input {
height: 180px; border-top: 0.5px solid #f3f3f3; } textarea {
width: 100%; border: 0px; resize: none; height: 20vh; } span {
display: inline-block; padding: 0px 5px; height: 37px; /*line-height: 37px;*/ line-height: 30px; } span:hover .times {
opacity: 1; transform: translate(0px); } span:hover .time {
opacity: 1; transform: translate(0px); } .times {
-webkit-transition: 0.5s; transition: 0.5s; opacity: 0; -webkit-transform: translate(20px); transform: translate(20px); } .time {
-webkit-transition: 0.5s; transition: 0.5s; opacity: 0; -webkit-transform: translate(-20px); transform: translate(-20px); } .he {
background: #e9e9e9; border-radius: 5px; border-bottom-right-radius: 15px; } .i {
color: #f3f3f3; background: #5d9aff; border-radius: 5px; border-bottom-left-radius: 14px; } .state {
font-size: 12px; } .readOrUnread {
/*position: absolute;*/ /*right: 55px;*/ /*bottom: -39px;*/ /*font-size: 12px;*/ margin-right: 55px; } .content li > span {
position: relative; } .content li {
margin-top: 15px; } li .i, li .he {
max-width: 50vw; word-wrap: break-word; word-break: break-all; text-align: left; height: auto; padding: 7px 5px; } </style>
<script src="../../common/vue/vue.min.js"></script>
<script src="../../common/axios/axios.min.js"></script>
<link rel="stylesheet" href="../../common/css/base.css">
</head>
<body>
<div id="app">
<div class="chat"><h3>客服<span class="state"></span></h3>
<div class="content" ref="reference">
<ul style="color: black">
<li v-for="item in content" :key="item.id" :style="item.flag ? 'text-align: right;' : 'text-align: left;'">
<span>
<img v-show="!item.flag" src="../img/icon/01.png" />
<span class="times" v-show="item.flag">{
{
item.createTime
? item.createTime.substr(11, item.createTime.length)
: ""
}}</span>
<span :class="item.flag ? 'i' : 'he'">{
{ item.name }}</span>
<span class="time" v-show="!item.flag">{
{
item.createTime
? item.createTime.substr(11, item.createTime.length)
: ""}}
</span>
<img v-show="item.flag" :src="heardUrl" />
<div class="readOrUnread" v-if="item.flag">
{
{ item.readState == "1" ? "已读" : "未读" }}
</div>
</span>
</li>
</ul>
</div>
<div class="input">
<textarea cols="50" rows="10" v-model="text" @keydown.enter="submit" ></textarea>
</div>
</div>
</div>
<script type="text/javascript"> var app = new Vue({
el: "#app", data() {
return {
text: "", content: [], socket: "", userId: "", openId: "", heardUrl: "", webUrl: "" } }, created() {
this.openId = getCookie('openId'); }, mounted() {
this.getWebUrl() this.getSysUserInfoByUserId() }, methods: {
submit() {
if (!this.text) {
return; } this.content.push({
flag: 1, name: this.text, }); this.socket.send( JSON.stringify({
linkType: "msg", sendId: this.openId, userId: this.openId, receiveId: 1, msgKey: this.openId + '_1', chatMsg: this.text, readState: 0, }) ); this.text = null; this.scrollAuto(); }, scrollAuto() {
this.$nextTick(() => {
this.$refs["reference"].scrollTop = this.$refs["reference"].scrollHeight }); }, history() {
axios({
method: "post", url: "../../../chat/msgHistory", data: {
receiveId: 1, sendId: this.openId, pageSize: "20", currentPage: "1", } }).then((res) => {
if (res) {
const {
data} = res; this.content = data.data.list.reverse(); this.scrollAuto(); } }) this.msgRead() }, msgRead() {
let url = `http://${
this.webUrl}/chat/msgRead` console.log(url, "url") axios({
method: "post", url: url, data: {
sendId: this.openId, receiveId: `1`, } }) }, getWebUrl() {
axios({
method: "POST", url: "../../../chat/getWebUrl", }).then((res) => {
if (res) {
const {
data} = res this.webUrl = data.webUrl this.history() this.initWs() } }) }, initWs() {
if (typeof (WebSocket) == "undefined") {
console.log("遗憾:您的浏览器不支持WebSocket"); } else {
console.log("恭喜:您的浏览器支持WebSocket"); this.socket = new WebSocket(`ws://${
this.webUrl}/ws/asset`); //连接打开事件 this.socket.onopen = function () {
console.log("Socket 已打开"); //session与用户id绑定 this.socket.send("{\"linkType\":\"bind\",\"sendId\":\""${
this.sendId}"\"} "); }; //收到消息事件 this.socket.onmessage = (data) => {
console.log(data) if (data.data !== '连接成功') {
let news = JSON.parse(data.data); this.content.push({
flag: 0, name: news.chatMsg, }); //对方接收到消息之后,把未读改为已读 if (news.code == 0) {
this.content.pop() for (var i = 0; i < this.content.length; i++) {
this.content[i].readState = 1 } } this.msgRead() this.scrollAuto(); } }; // socket. //连接关闭事件 this.socket.onclose = function () {
console.log("Socket已关闭"); }; //发生了错误事件 this.socket.onerror = function () {
alert("Socket发生了错误"); } //窗口关闭时,关闭连接 window.unload = function () {
this.socket.close(); }; } setTimeout(() => {
this.socket.send( JSON.stringify({
linkType: "bind", sendId: this.openId, }) ); }, 500); }, //通过openId获取用户头像信息 getSysUserInfoByUserId() {
axios({
method: "GET", url: "../../../chat/getSysUserInfoByUserId", params: {
"openId": this.openId } }).then((res) => {
if (res.data.success) {
if (res.data.data) {
this.heardUrl = res.data.data.heardUrl console.log(this.heardUrl) } } }) } } }) </script>
</body>
</html>
GBCookie.js
function setCookie(c_name, value, expiredays) {
var exdate = new Date()
exdate.setDate(exdate.getDate() + expiredays)
document.cookie = c_name + "=" + escape(value) +
((expiredays == null) ? "" : ";expires=" + exdate.toGMTString())
}
//取回cookie
function getCookie(c_name) {
if (document.cookie.length > 0) {
c_start = document.cookie.indexOf(c_name + "=")`在这里插入代码片`
if (c_start != -1) {
c_start = c_start + c_name.length + 1
c_end = document.cookie.indexOf(";", c_start)
if (c_end == -1) c_end = document.cookie.length
return unescape(document.cookie.substring(c_start, c_end))
}
}
return ""
}
2.后端代码
引入mongodb依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
yml配置
#mongodb 配置
spring:
data:
mongodb:
host: 192.168.1.125
port: 27017
database: cangzhou
# 客服消息地址
websocket:
url: 192.168.1.209:9019/fmis
WxChatController
import com.alibaba.fastjson.JSONObject;
import com.jinmdz.common.response.CommonCode;
import com.jinmdz.entity.wechat.SysUser;
import com.jinmdz.entity.wechat.WeChatResult;
import com.jinmdz.model.chat.ChatMsg;
import com.jinmdz.service.ChatService;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/** * @author lvyq * @version 1.0 * @description: TODO * @date 2021/11/12 13:18 */
@RestController
@RequestMapping("/chat")
public class WxChatController {
@Resource
public MongoTemplate mongoTemplate;
@Resource
private ChatService chatService;
/** * @description: 添加用户-测试 * @author: lvyq * @date: 2021/11/18 16:08 * @version 1.0 */
@PostMapping("/saveUser")
public WeChatResult saveUser(@RequestBody SysUser user){
Query query = new Query().addCriteria(Criteria.where("userId").is(user.getUserId()));
Update update = new Update().set("nickName",user.getNickName()).set("heardUrl",user.getHeardUrl());
SysUser sysUser= mongoTemplate.findOne(query,SysUser.class);
if (sysUser!=null){
mongoTemplate.updateFirst(query,update,SysUser.class);
}else {
mongoTemplate.insert(user);
}
return new WeChatResult(CommonCode.SUCCESS);
}
/** * @description: 消息记录 * @author: lvyq * @date: 2021/11/12 13:18 * @version 1.0 */
@PostMapping("/msgHistory")
public JSONObject msgHistory(@RequestBody ChatMsg data){
return chatService.msgHistory(data);
}
/** * @description: 获取ws的地址 * @author: lvyq * @date: 2021/11/16 14:45 * @version 1.0 */
@PostMapping("/getWebUrl")
public JSONObject getWebUrl(){
return chatService.getWebUrl();
}
/** * @description: 根据用户openId获取用户基本信息 * @author: lvyq * @date: 2021/11/18 16:27 * @version 1.0 */
@GetMapping("/getSysUserInfoByUserId")
public WeChatResult getSysUserInfoByUserId(String openId){
if (StringUtils.isEmpty(openId)){
return new WeChatResult(CommonCode.INVALID_PARAM);
}
Query query = new Query().addCriteria(Criteria.where("userId").is(openId));
SysUser sysUser = mongoTemplate.findOne(query,SysUser.class);
return new WeChatResult(sysUser);
}
}
ChatService
import com.alibaba.fastjson.JSONObject;
import com.jinmdz.model.chat.ChatMsg;
/** * @author lvyq * @version 1.0 * @description: TODO * @date 2021/11/12 13:18 */
public interface ChatService {
JSONObject msgHistory(ChatMsg data);
JSONObject getUnReadNum(ChatMsg data);
JSONObject getWebUrl();
}
ChatServiceImpl
import com.alibaba.fastjson.JSONObject;
import com.jinmdz.model.chat.ChatMsg;
import com.jinmdz.service.ChatService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** * @author lvyq * @version 1.0 * @description: TODO * @date 2021/11/12 13:19 */
@Service
public class ChatServiceImpl implements ChatService {
@Resource
private MongoTemplate mongoTemplate;
@Value("${websocket.url}")
public String WebUrl;
/** * @description: 消息记录 * @author: lvyq * @date: 2021/9/26 15:20 * @version 1.0 */
@Override
public JSONObject msgHistory(ChatMsg data) {
JSONObject mav = new JSONObject();
int page = data.getCurrentPage();
if (page<0){
page=1;
}
page=page-1;
int size = data.getPageSize();
if (size<0){
size=20;
}
if (!StringUtils.isEmpty(data.getSendId()) && !StringUtils.isEmpty(data.getReceiveId())){
String msgKeyOne= data.getSendId()+"_"+data.getReceiveId();
String msgKeyTwo = data.getReceiveId()+"_"+data.getSendId();
Criteria orCri1 = new Criteria();
Criteria orCri2 = new Criteria();
orCri1.andOperator(Criteria.where("msgKey").is(msgKeyOne));
orCri2.andOperator(Criteria.where("msgKey").is(msgKeyTwo));
Query query = new Query().addCriteria(new Criteria().orOperator(orCri1,orCri2));
long total = mongoTemplate.count(query,ChatMsg.class);
Pageable pageable = PageRequest.of(page,size, Sort.by(Sort.Direction.DESC,"createTime"));
query.with(pageable);
List<ChatMsg> list = mongoTemplate.find(query,ChatMsg.class);
HashMap<String, Object> map = new HashMap<>();
if (list != null) {
for (ChatMsg chatMsg:list){
chatMsg.setName(chatMsg.getChatMsg());
if (chatMsg.getSendId().equals(data.getSendId())){
chatMsg.setFlag(1);
}else {
chatMsg.setFlag(0);
}
}
Map<String, Object> pageMap = new HashMap<>();
map.put("list", list);
pageMap.put("total", total);
pageMap.put("pageSize", data.getPageSize());
pageMap.put("currentPage", data.getCurrentPage());
map.put("pager", pageMap);
}
Query queryMsg = new Query().addCriteria(Criteria.where("readState").is("0").and("sendId").is(data.getReceiveId()).and("receiveId").is(data.getSendId()));
Update update = new Update().set("readState","1");
mongoTemplate.updateFirst(queryMsg,update,ChatMsg.class);
mav.put("state",true);
mav.put("data",map);
return mav;
}else {
mav.put("state",false);
mav.put("msg","非法参数");
return mav;
}
}
/** * @description: 未读消息条数 * @author: lvyq * @date: 2021/11/16 14:20 * @version 1.0 */
@Override
public JSONObject getUnReadNum(ChatMsg data) {
JSONObject mav = new JSONObject();
Query query = new Query();
query.addCriteria(Criteria.where("readState").is("0").and("sendId").is(data.getSendId()).and("receiveId").is(data.getReceiveId()));
long count = mongoTemplate.count(query,ChatMsg.class);
mav.put("state",true);
mav.put("unReadNum",count);
return mav;
}
/** * @description: 获取websocket地址 * @author: lvyq * @date: 2021/11/16 14:47 * @version 1.0 */
@Override
public JSONObject getWebUrl() {
JSONObject mav = new JSONObject();
mav.put("state",true);
mav.put("webUrl",WebUrl);
return mav;
}
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/179383.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...