新增WebSocket模块

This commit is contained in:
wanggeng888 2021-03-04 18:32:05 +08:00
parent 787fb1bc15
commit b627437036
7 changed files with 531 additions and 22 deletions

View File

@ -98,6 +98,12 @@
<version>${cm-cloud.version}</version>
</dependency>
<dependency>
<groupId>com.cm</groupId>
<artifactId>cloud-common-websocket</artifactId>
<version>1.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.cm</groupId>
<artifactId>cloud-common-wechat</artifactId>

View File

@ -68,7 +68,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
"/wxminiapp/**",
"/route/file/**",
"/api/sms/getverificationcode/*",
"/api/user/getsignintype/**")
"/api/user/getsignintype/**",
"/ws")
.permitAll()
.and()
.authorizeRequests()

View File

@ -1,10 +1,6 @@
package com.cm.serviceusercenter.service.system.user;
import com.cm.common.exception.SearchException;
import com.cm.common.result.SuccessResultLayImData;
import java.util.List;
import java.util.Map;
import com.cm.common.plugin.interfaces.IUserImBaseService;
/**
* When you feel like quitting. Think about why you started
@ -16,14 +12,5 @@ import java.util.Map;
* @Date: 2021/1/15 10:55 上午
* @Version: 1.0
*/
public interface IUserImService {
/**
* 获取部门用户信息
*
* @param params
* @return
* @throws SearchException
*/
List<SuccessResultLayImData.Friend> listDepartmentUser(Map<String, Object> params) throws SearchException;
public interface IUserImService extends IUserImBaseService {
}

View File

@ -1,8 +1,11 @@
package com.cm.serviceusercenter.service.system.user.impl;
import com.alibaba.druid.util.StringUtils;
import com.cm.common.config.properties.ApiPathProperties;
import com.cm.common.constants.ISystemConstant;
import com.cm.common.exception.SearchException;
import com.cm.common.plugin.pojo.bos.department.DepartmentResourceBO;
import com.cm.common.plugin.pojo.bos.user.UserDepartmentResourceBO;
import com.cm.common.pojo.bos.UserInfoBO;
import com.cm.common.result.SuccessResultLayImData;
import com.cm.serviceusercenter.pojo.dtos.DepartmentUserDTO;
import com.cm.serviceusercenter.pojo.dtos.department.DepartmentSimpleDTO;
@ -13,10 +16,7 @@ import com.cm.serviceusercenter.service.system.user.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* When you feel like quitting. Think about why you started
@ -35,6 +35,47 @@ public class UserImService extends BaseService implements IUserImService {
private IDepartmentService departmentService;
@Autowired
private IUserService userService;
@Autowired
private ApiPathProperties apiPathProperties;
@Override
public SuccessResultLayImData<SuccessResultLayImData.InitData> getInitData() {
try {
// 个人信息
UserInfoBO currentUser = securityComponent.getCurrentUser();
SuccessResultLayImData.User mine = new SuccessResultLayImData.User();
mine.setId(currentUser.getUserId());
mine.setUsername(org.apache.commons.lang3.StringUtils.equals(currentUser.getUserUsername(), ISystemConstant.ADMIN) ? "系统管理员" : currentUser.getUserName());
if (org.apache.commons.lang3.StringUtils.isBlank(currentUser.getUserAvatar())) {
mine.setAvatar(DEFAULT_USER_AVATAR);
} else {
mine.setAvatar(apiPathProperties.getUserCenter() + "/route/file/downloadfile/true/" + currentUser.getUserAvatar());
}
mine.setStatus("online");
mine.setSign("暂无签名");
Map<String, Object> params = getHashMap(2);
// 用户所在部门集合
Set<SuccessResultLayImData.Friend> userFriendSet = new HashSet<>();
// 朋友
List<SuccessResultLayImData.Friend> friends = listDepartmentUser(params);
setFriends(currentUser, mine, friends, userFriendSet);
// 用户组
List<SuccessResultLayImData.Group> groups = new ArrayList<>();
setGroups(currentUser, friends, groups, userFriendSet);
SuccessResultLayImData.InitData initData = new SuccessResultLayImData.InitData();
initData.setMine(mine);
initData.setFriend(friends);
initData.setGroup(groups);
return new SuccessResultLayImData<>(0, "", initData);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
return new SuccessResultLayImData<>(400, e.getMessage(), null);
}
}
@Override
public List<SuccessResultLayImData.Friend> listDepartmentUser(Map<String, Object> params) throws SearchException {
@ -79,4 +120,139 @@ public class UserImService extends BaseService implements IUserImService {
}
return friends;
}
@Override
public SuccessResultLayImData<SuccessResultLayImData.MemberData> getMemberData(String departmentId) {
try {
List<String> departmentIds = new ArrayList<>();
departmentIds.add(departmentId);
List<UserDepartmentResourceBO> userDepartmentResourceBOS = userService.listUserDepartmentResourceByDepartmentIds(departmentIds);
SuccessResultLayImData.MemberData memberData = new SuccessResultLayImData.MemberData();
List<SuccessResultLayImData.User> list = new ArrayList<>();
memberData.setList(list);
for (UserDepartmentResourceBO userDepartmentResourceBO : userDepartmentResourceBOS) {
SuccessResultLayImData.User user = new SuccessResultLayImData.User();
user.setId(userDepartmentResourceBO.getUserId());
user.setUsername(userDepartmentResourceBO.getUserName());
user.setSign("暂无签名");
if (org.apache.commons.lang3.StringUtils.isBlank(userDepartmentResourceBO.getUserAvatar())) {
user.setAvatar(DEFAULT_USER_AVATAR);
} else {
user.setAvatar(apiPathProperties.getUserCenter() + "/route/file/downloadfile/true/" + userDepartmentResourceBO.getUserAvatar());
}
list.add(user);
}
// 添加管理员
SuccessResultLayImData.User adminUser = getAdminUser();
adminUser.setAvatar(DEFAULT_USER_AVATAR);
list.add(adminUser);
return new SuccessResultLayImData<>(0, "", memberData);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
return new SuccessResultLayImData<>(400, e.getMessage(), null);
}
}
@Override
public List<UserDepartmentResourceBO> listUserDepartmentResource(List<String> departmentIds) {
List<UserDepartmentResourceBO> userDepartmentResourceBOS = userService.listUserDepartmentResourceByDepartmentIds(departmentIds);
// 添加系统管理员
UserDepartmentResourceBO userDepartmentResourceBO = new UserDepartmentResourceBO();
userDepartmentResourceBO.setUserId("1");
userDepartmentResourceBO.setUserUsername(ISystemConstant.ADMIN);
userDepartmentResourceBO.setUserName("系统管理员");
userDepartmentResourceBO.setUserAvatar(DEFAULT_USER_AVATAR);
userDepartmentResourceBOS.add(userDepartmentResourceBO);
return userDepartmentResourceBOS;
}
/**
* 设置朋友列表
*
* @param currentUser
* @param mine
* @param friends
*/
private void setFriends(UserInfoBO currentUser, SuccessResultLayImData.User mine, List<SuccessResultLayImData.Friend> friends, Set<SuccessResultLayImData.Friend> userFriendSet) {
// 非管理员添加系统管理员
if (!org.apache.commons.lang3.StringUtils.equals(ISystemConstant.ADMIN, currentUser.getUserUsername())) {
// 加载管理员
SuccessResultLayImData.Friend adminFriend = new SuccessResultLayImData.Friend();
adminFriend.setId("admin");
adminFriend.setGroupname("管理员");
List<SuccessResultLayImData.User> users = new ArrayList<>();
users.add(getAdminUser());
adminFriend.setList(users);
friends.add(adminFriend);
}
for (int i = 0; i < friends.size(); i++) {
SuccessResultLayImData.Friend friend = friends.get(i);
for (int j = 0; j < friend.getList().size(); j++) {
SuccessResultLayImData.User user = friend.getList().get(j);
// 删除自己
if (org.apache.commons.lang3.StringUtils.equals(user.getId(), mine.getId())) {
userFriendSet.add(friend);
friend.getList().remove(j);
j--;
continue;
}
if (org.apache.commons.lang3.StringUtils.isBlank(user.getAvatar())) {
user.setAvatar(DEFAULT_USER_AVATAR);
} else {
user.setAvatar(apiPathProperties.getUserCenter() + "/route/file/downloadfile/true/" + user.getAvatar());
}
// 默认离线
user.setStatus("offline");
user.setSign("暂无签名");
}
// 删除用户为空的朋友组
if (friend.getList().isEmpty()) {
friends.remove(i);
i--;
}
}
}
/**
* 系统管理员
*
* @return
*/
private SuccessResultLayImData.User getAdminUser() {
SuccessResultLayImData.User user = new SuccessResultLayImData.User();
user.setId("1");
user.setStatus("offline");
user.setUsername("系统管理员");
return user;
}
/**
* 设置组
*
* @param currentUser
* @param friends
* @param groups
* @param userFriendIdSet
*/
private void setGroups(UserInfoBO currentUser, List<SuccessResultLayImData.Friend> friends, List<SuccessResultLayImData.Group> groups, Set<SuccessResultLayImData.Friend> userFriendSet) {
// 管理员添加所有组
if (org.apache.commons.lang3.StringUtils.equals(ISystemConstant.ADMIN, currentUser.getUserUsername())) {
for (SuccessResultLayImData.Friend friend : friends) {
SuccessResultLayImData.Group group = new SuccessResultLayImData.Group();
group.setId(friend.getId());
group.setGroupname(friend.getGroupname());
group.setAvatar(DEFAULT_GROUP_AVATAR);
groups.add(group);
}
return;
}
// 非管理员添加自己所在部门
for (SuccessResultLayImData.Friend friend : userFriendSet) {
SuccessResultLayImData.Group group = new SuccessResultLayImData.Group();
group.setId(friend.getId());
group.setGroupname(friend.getGroupname());
group.setAvatar(DEFAULT_GROUP_AVATAR);
groups.add(group);
}
}
}

View File

@ -1,6 +1,7 @@
server:
port: 7001
url: http://127.0.0.1:7001/usercenter
ws: ws://127.0.0.1:7001/usercenter/ws
title: 统一用户管理平台
login-page-name: 统一用户管理平台
servlet:

View File

@ -0,0 +1,336 @@
layui.define(['layim'], function(exports) {
var $ = layui.$;
var layim = layui.layim;
var Socket = {
Message: function() {
this.id = null;
this.type = null;
this.isSystem = false;
this.from = null;
this.to = null;
this.body = null;
this.timestamp = null;
},
Register: function() {
this.appId = null;
this.userId = null;
},
TypeEnum: {
REGISTER: 100,
MESSAGE: 101,
GROUP_MESSAGE: 102,
SYSTEM_MESSAGE: 103,
SYSTEM_GROUP_MESSAGE: 104,
SYSTEM_TARGET_MESSAGE: 105,
NOTICE: 106,
NOTICE_GROUP_MESSAGE: 107,
NOTICE_TARGET_MESSAGE: 108,
SEARCH_ONLINE_USER: 600,
SEARCH_ONLINE_USER_FRIEND: 601,
SEND_STATUS: 1100,
SEND_STATUS_ONLINE: 1101,
SEND_STATUS_OFFLINE: 1102
},
getUUID: function() {
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
},
initSocket: function(ws, layIM, options) {
var appId = Socket.getUUID();
var userId = options.mine.id;
function getFriend(userId) {
for(var i = 0, item; item = options.friend[i++];) {
for(var j = 0, jItem; jItem = item.list[j++];) {
if(jItem.id === userId) {
return jItem;
}
}
}
return null;
}
// 全部在线人员
function listOnlineUser() {
var message = new Socket.Message();
message.id = Socket.getUUID();
message.type = Socket.TypeEnum.SEARCH_ONLINE_USER;
message.timestamp = new Date().getTime();
message.from = userId;
message.to = userId;
// 消息体
message.body = userId;
socket.send(JSON.stringify(message));
}
// 注册socket服务
var socket = new WebSocket(ws);
socket.onclose = function() {
top.dialog.msg('消息服务器连接断开5s后重试');
setTimeout(function() {
Socket.initSocket(options);
}, 5000);
}
socket.onerror = function(event) {
console.error('消息服务器连接异常,请刷新页面重试', event);
}
socket.onopen = function() {
// 消息体
var message = new Socket.Message();
message.id = Socket.getUUID();
message.type = Socket.TypeEnum.REGISTER;
message.timestamp = new Date().getTime();
// 注册体
var register = new Socket.Register();
register.appId = appId;
register.userId = userId;
message.body = JSON.stringify(register);
// 注册设备
socket.send(JSON.stringify(message));
};
socket.onmessage = function(res) {
var data = JSON.parse(res.data);
if(data.type === 100) {
// 连接状态
var body = JSON.parse(data.body);
if(body.code == 200) {
console.log('消息服务器连接成功');
setTimeout(function() {
listOnlineUser();
}, 1000);
return;
}
} else if(data.type === 101 || data.type === 102) {
// 消息
var user;
if(data.from === options.mine.id) {
user = options.mine;
} else {
user = getFriend(data.from);
console.log(user);
if(user == null) {
user = {};
user.id = 'otherUser'+ new Date().getTime();
user.username = '未知用户';
user.avatar = 'assets/images/random-avatar2.jpg';
}
}
if(data.type === 101) {
layIM.getMessage({
username: user.username,
avatar: user.avatar,
id: user.id,
content: data.body,
fromid: data.from,
type: 'friend',
mine: data.from === options.mine.id ? true : false,
timestamp: data.timestamp
});
} else if(data.type === 102) {
layIM.getMessage({
username: user.username,
avatar: user.avatar,
id: data.to,
content: data.body,
fromid: data.from,
type: 'group',
mine: false,
timestamp: data.timestamp
});
}
} else if(data.type === 1100) {
// 发送状态
var body = JSON.parse(data.body);
if(body.code === 200) {
console.log('发送成功');
return;
} else if(body.code === 300) {
var user = getFriend(data.to);
if(user != null) {
layIM.getMessage({
system: true,
id: user.id,
type: 'friend',
content: body.msg
});
} else {
top.dialog.msg(body.msg);
}
return;
}
} else if(data.type === 1101) {
var onlineUserIdArray = JSON.parse(data.body);
for(var i = 0, item; item = onlineUserIdArray[i++];) {
var user = getFriend(item);
if(user == null) {
return;
}
user.status = 'online';
layim.setFriendStatus(item, 'online');
}
} else if(data.type === 1102) {
var onlineUserIdArray = JSON.parse(data.body);
for(var i = 0, item; item = onlineUserIdArray[i++];) {
var user = getFriend(item);
if(user == null) {
return;
}
user.status = 'offline';
layim.setFriendStatus(item, 'offline');
}
}
};
layIM.on('sendMessage', function(res) {
console.log(res);
var mine = res.mine;
// 消息体
var message = new Socket.Message();
message.id = Socket.getUUID();
if(res.to.type === 'friend') {
message.type = Socket.TypeEnum.MESSAGE;
} else if(res.to.type === 'group') {
message.type = Socket.TypeEnum.GROUP_MESSAGE;
}
message.timestamp = new Date().getTime();
message.from = mine.id;
message.to = res.to.id;
// 消息体查找消息体中的url
var content = mine.content;
// 是否图片
var imageMatchArray = mine.content.match(/img\[.*\]/g);
// 是否文件
var fileMatchArray = mine.content.match(/file\(.*\)\[.*\]/g);
// 是否视频
var videoMatchArray = mine.content.match(/video\[.*\]/g);
if(imageMatchArray == null && fileMatchArray == null && videoMatchArray == null) {
var urlArray = mine.content.match(/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)(:?\w+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/g);
if(urlArray != null && urlArray.length > 0) {
for(var i = 0, item; item = urlArray[i++];) {
content = content.replace(item, 'a('+ item +')['+ item +']');
}
}
}
message.body = content;
if(socket.readyState === 1) {
socket.send(JSON.stringify(message));
} else {
top.dialog.msg('发送异常,请刷新页面重试');
}
});
}
}
// 即使消息
layim.config({
init: {
url: 'api/user/im/getinitdata',
type: 'get',
data: {}
},
members: {
url: 'api/user/im/getmemberdata',
type: 'get',
data: {}
},
min: false,
isfriend: true,
isgroup: true,
copyright: true,
isAudio: false,
isVideo: false,
tool: [{
alias: 'image',
title: '发送图片',
icon: '&#xe64a;'
}, {
alias: 'file',
title: '发送文件',
icon: '&#xe621;'
}, {
alias: 'video',
title: '发送视频',
icon: '&#xe6ed;'
}
]
});
layim.on('ready', function(options) {
Socket.initSocket($('#wsUrl').val(), layim, options);
});
layim.on('chatChange', function(res) {
var data = res.data;
if(data.type === 'friend') {
layim.setChatStatus(data.sign);
}
});
layim.on('tool(image)', function(insert, send, obj) {
top.dialog.file({
type: 'image',
title: '发送图片',
width: '400px',
height: '420px',
maxFileCount: '1',
onClose: function() {
var uploadFileArray = top.dialog.dialogData.uploadFileArray;
if(typeof(uploadFileArray) != 'undefined' && uploadFileArray.length > 0) {
for(var i = 0, item; item = uploadFileArray[i++];) {
var fullUrl = $('#serverUrl').val() +'/route/file/downloadfile/true/'+ item.data;
insert('img['+ fullUrl +']');
send();
}
}
}
});
});
layim.on('tool(file)', function(insert, send, obj) {
top.dialog.file({
type: 'file',
title: '发送文件',
width: '400px',
height: '420px',
maxFileCount: '1',
onClose: function() {
var uploadFileArray = top.dialog.dialogData.uploadFileArray;
if(typeof(uploadFileArray) != 'undefined' && uploadFileArray.length > 0) {
for(var i = 0, item; item = uploadFileArray[i++];) {
var fullUrl = $('#serverUrl').val() +'/route/file/downloadfile/false/'+ item.data;
insert('file('+ fullUrl +')[ ]');
send();
}
}
}
});
});
layim.on('tool(video)', function(insert, send, obj) {
top.dialog.file({
type: 'video',
title: '发送视频',
width: '400px',
height: '420px',
maxFileCount: '1',
onClose: function() {
var uploadFileArray = top.dialog.dialogData.uploadFileArray;
if(typeof(uploadFileArray) != 'undefined' && uploadFileArray.length > 0) {
for(var i = 0, item; item = uploadFileArray[i++];) {
var fullUrl = $('#serverUrl').val() +'/route/file/downloadfile/true/'+ item.data;
insert('video['+ fullUrl +']');
send();
}
}
}
});
});
exports('im-socket', {});
})

View File

@ -152,6 +152,8 @@
<!-- 辅助元素,一般用于移动设备下遮罩 -->
<div class="layadmin-body-shade" layadmin-event="shade"></div>
<input type="hidden" id="serverUrl" th:value="${url}">
<input type="hidden" id="wsUrl" th:value="${ws}">
</div>
</div>
<script src="assets/layuiadmin/layui/layui.js"></script>
@ -160,7 +162,7 @@
base: 'assets/layuiadmin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'restajax', 'datamessage', 'dialog'], function() {
}).use(['index', 'restajax', 'datamessage', 'dialog', 'im-socket'], function() {
var $ = layui.$;
var layer = layui.layer;