1、在pom.xml中增加jar包支持
<!-- 添加 websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
2、增加websocket配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* describe: websocketConfig
* current user Maochao.zhu
* current system 2020/5/12
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
3、增加websocket服务支持类
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cn.zx.common.StringUtil;
import com.cn.zx.config.MyApplicationContextAware;
import com.cn.zx.po.sys.User;
import com.cn.zx.service.sys.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* describe: websocket服务支持
* current user Maochao.zhu
* current system 2020/5/12
*/
@ServerEndpoint(value = "/websocket/{userId}")
@Component
public class WebSocketServer {
public static Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
UserService userService;
//ConcurrentHashMap是线程安全的,而HashMap是线程不安全的。
//根据用户获取Session信息
private static ConcurrentHashMap<String, Session> mapUS = new ConcurrentHashMap<String,Session>();
//根据Session获取用户信息
private static ConcurrentHashMap<Session,String> mapSU = new ConcurrentHashMap<Session,String>();
//存储消息
private static ConcurrentHashMap<String,String> messageMap = new ConcurrentHashMap<String,String>();
/**
* 连接建立成功调用的方法
* @param session
* @param userId
*/
@OnOpen
public void onOpen(Session session,@PathParam("userId") Integer userId) {
mapUS.put(userId+"",session);
mapSU.put(session,userId+"");
logger.info("用户"+userId+"进入llws,当前在线人数为" + mapUS.size() );
//发送离线消息
sendMessage(session, userId+"");
}
/**
* 连接关闭调用的方法
* @param session
*/
@OnClose
public void onClose(Session session) {
String userId=mapSU.get(session);
if(userId!=null&&userId!=""){
mapUS.remove(userId);
mapSU.remove(session);
logger.info("用户"+userId+"退出llws,当前在线人数为" + mapUS.size());
}
}
/**
* 收到客户端消息后调用的方法
* @param message
* @param session
*/
@OnMessage
public void onMessage(String message, Session session) {
logger.info("############## 收到客户端消息:" + message );
if(StringUtil.isBlank(message)){
return;
}
JSONObject jsonObject= JSONObject.parseObject(message);
jsonObject = jsonObject.getJSONObject("data");
//请求数据为空
if(null==jsonObject){
return;
}
String type = jsonObject.getJSONObject("to").getString("type");
if(type.equals("onlineStatus")){
for(Session s:session.getOpenSessions()){ //循环发给所有在线的人
JSONObject toMessage=new JSONObject();
toMessage.put("id", jsonObject.getJSONObject("mine").getString("id"));
toMessage.put("content", jsonObject.getJSONObject("mine").getString("content"));
toMessage.put("type",type);
for (String value : mapSU.values()) {
try {
mapUS.get(value).getBasicRemote().sendText(toMessage.toString());
} catch (IOException e) {
logger.info(e.getMessage());
}
}
}
}else{
int toId=jsonObject.getJSONObject("to").getInteger("id");
JSONObject toMessage=new JSONObject();
toMessage.put("username",jsonObject.getJSONObject("mine").getString("username"));
toMessage.put("avatar", jsonObject.getJSONObject("mine").getString("avatar"));
toMessage.put("type",type);
toMessage.put("content", jsonObject.getJSONObject("mine").getString("content"));
if(type.equals("friend")||type.equals("fankui")){
toMessage.put("id", jsonObject.getJSONObject("mine").getInteger("id"));
}else{
toMessage.put("id", jsonObject.getJSONObject("to").getInteger("id"));
}
switch (type) {
case "friend": //单聊,记录到mongo
if(mapUS.containsKey(toId+"")){
mapUS.get(toId+"").getAsyncRemote().sendText(toMessage.toString());//发送消息给对方
logger.info("单聊-来自客户端的消息:" + toMessage.toString());
}else{//如果不在线 就记录到数据库,下次对方上线时推送给对方。
logger.info("单聊-对方不在线,消息已存入" + toMessage.toString());
messageMap.put(toId+"", toMessage.toString());
}
break;
case "group":
User userT= new User();
userT.setBranchId(toId);
userService = MyApplicationContextAware.getApplicationContext().getBean(UserService.class);
List<User> userList = userService.getImUserList(userT);
List<String> idStrList = new ArrayList<String>();
for(User u:userList){
idStrList.add(u.getId()+"");
}
String useridStr = JSON.toJSONString(idStrList);
JSONArray memberList=JSONArray.parseArray(useridStr); //获取群成员userId列表
if(memberList.size()>0){
for(int i=0;i<memberList.size();i++){ //发送到在线用户(除了发送者)
if(!memberList.get(i).equals(jsonObject.getJSONObject("mine").getInteger("id")+"")){
if(null==mapUS.get(memberList.get(i))){
messageMap.put(memberList.get(i)+"", toMessage.toString());
continue;//不在线、不能发送消息
}
mapUS.get(memberList.get(i)).getAsyncRemote().sendText(toMessage.toString());
logger.info("群聊-来自客户端的消息:" + toMessage.toString());
}
}
}
break;
default:
break;
}
}
}
/**
* 发生错误时调用的方法
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
String userId=mapSU.get(session);
if(userId!=null&&userId!=""){
mapUS.remove(userId);
mapSU.remove(session);
logger.info("用户"+userId+"退出llws!当前在线人数为" + mapUS.size());
}
logger.info("#############################llws发生错误!"+userId);
}
/**
* 用户上线以后发送保存的离线消息
* @param session
* @param userId
*/
public void sendMessage(Session session,String userId) {
String message = messageMap.get(userId);
if(null!=message && !"".equals(message)){
mapUS.get(userId).getAsyncRemote().sendText(message);
//发送成功以后移除消息存储
messageMap.remove(userId);
}
}
}
4、页面采用layUI的即时通讯LayIM前端页面调用websocket服务, 前端下载地址:https://layim.layui.com/
var socket = new WebSocket('ws://ip地址/websocket/'+ userId);
//连接成功时触发
socket.onopen = function(){
console.log("WebSocket is open now.");
};
//初始化
layim.config({
init:{
url:"初始化数据接口地址"
},
members: {
url:"获取群成员接口地址",
data:{
"id":"id"
}
},
notice: false,
isfriend: true
});
//监听查看群员
layim.on("members", function(data){
console.log(data);
});
layim.on('sendMessage', function(res){
var mine = res.mine; //包含我发送的消息及我的信息
var to = res.to; //对方的信息
//socket关闭
if(socket.readyState!= socket.OPEN){
console.log("--------socket closed--")
}
socket.send(JSON.stringify({
type: 'chatMessage' //用于在服务端区分消息类型
,data: {
"mine":mine,
"to":to
}
}));
});
//监听收到的聊天消息,假设你服务端emit的事件名为:chatMessage
socket.onmessage = function(res){
var message = JSON.parse(res.data);
layim.getMessage(message);
};
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
socket.close();
};
//监听签名修改
layim.on('sign', function(value){
console.log(value);
});
});
来源:oschina
链接:https://my.oschina.net/u/3204029/blog/4278655