从零开始的临时会话WEB项目(基于SSM框架)(三)

前面把用户登录弄好了,现在开始做websocket

后端代码:

package com.wc.controller;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import com.alibaba.fastjson.JSONObject;
import com.wc.service.MessageService;

@ServerEndpoint("/WebSocketServer/{userId}")
public class WebSocket {
	
	@Autowired
	@Qualifier("messageService")
	private MessageService messageService;
	
	private static Logger log = Logger.getLogger(WebSocket.class);
	// 在线人数
	private static int onlineCount = 0;
	// 在线用户列表
	private static Map<String, WebSocket> clients = new ConcurrentHashMap<String, WebSocket>();

    private Session session;
    private String userId;

    // 连接Socket触发
    @OnOpen
    public void onOpen(@PathParam("userId") String userId, Session session) throws IOException {
        this.userId = userId;
        this.session = session;
        // 在线人数+1
        addOnlineCount();
        // 把当前用户添加到在线用户列表
        clients.put(userId, this);
        log.info(userId + "已上线");
    }
    
    // 离线或关闭窗口、异常关闭浏览器触发
    @OnClose
    public void onClose() throws IOException {
        // 将当前用户从在线用户列表中移除
        clients.remove(userId);
        // 在线人数-1
        subOnlineCount();
        log.info(this.userId + "已离线");
    }
    
    // 前端websocket.send方法发送数据到服务端,服务端向客户端转推送消息
    @OnMessage
    public void onMessage(String messageJson) throws IOException {
    	
    	JSONObject json = JSONObject.parseObject(messageJson);
    	String type = json.getString("type").toLowerCase();
    	JSONObject data = json.getJSONObject("data");
    	if (type.equals("chatmessage")) {
    		//若为发送消息请求
        	String senderID = data.getJSONObject("mine").getString("id");
        	System.out.println("服务端接受到ID为"+senderID+"的数据发送请求");
        	System.out.println("数据内容:"+messageJson);
            
            JSONObject Todata = data.getJSONObject("to");
            String toId = String.valueOf(Todata.get("id"));
            
            //发送给指定ID的用户
            sendMessageTo(messageJson, toId);
		}else {
			//若为检查在线状态请求
			String toId = data.getString("toid");
			String myid = data.getString("myid");
			if (isline(toId)) {
				String state = "{\"type\":\"linestate\",\"state\":\"on\"}";
				sendMessageTo(state,myid);
			}else {
				String state = "{\"type\":\"linestate\",\"state\":\"off\"}";
				sendMessageTo(state,myid);
			}
	
		}

  
    }
    
    // 异常接收
    @OnError
    public void onError(Session session, Throwable error) {
    	System.out.println(error);
        log.info(this.userId + "发生异常");
        System.out.println("发生异常");
    }
    
    /**
     * 推送给所有在线用户
     * @param message 推送信息
     */
    public void sendMessageAll(String message) throws IOException {
        for (WebSocket item : clients.values()) {
            item.session.getAsyncRemote().sendText(message);
        }
    }
    
    /**
     * 推送给固定用户
     * @param message 推送信息
     * @param To 好友编号
     */
    public void sendMessageTo(String message, String To) throws IOException {
    	
    	for (WebSocket item : clients.values()) {
    		//遍历当前所有在线用户,向指定ID的用户发送消息
    		if (item.userId.equals(To)){
               item.session.getAsyncRemote().sendText(message);
    		   System.out.println("指定的发送对象:"+item+"UserID:"+item.userId);
    		}
        }
    }
    
    
    /**
     * 确认指定ID的用户是否在线
     * @param uid 用户ID
     */
    public boolean isline(String uid) throws IOException {
    	for (WebSocket item : clients.values()) {
    		//遍历当前所有在线用户,向指定ID的用户发送消息
    		if (item.userId.equals(uid)){
    		   System.out.println(item.userId+"在线");
    		   return true;
    		}
        }
		return false;
    }

    
    //获取当前在线人数
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
    //在线人数加一
    public static synchronized void addOnlineCount() {
        WebSocket.onlineCount++;
    }
    //在线人数减一
    public static synchronized void subOnlineCount() {
        WebSocket.onlineCount--;
    }
    //获取当前在线用户信息、WebSocket
    public static synchronized Map<String, WebSocket> getClients() {
        return clients;
    }
}

前端代码:

chat.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<base href="${pageContext.request.contextPath }/">
<meta name="viewport" content="width=device-width, initial-scale=1">
  <title>在线咨询</title>
  <link rel="stylesheet" href="layui/css/layui.css">
  <style>
  html{background-color: #333;}
  </style>
</head>
<body>
 
</body>
<script src="layui/layui.js"></script>
<script src="js/jquery-1.9.1.js"></script>
<script>

layui.config({
  layimPath: 'dist/' //配置 layim.js 所在目录
  ,layimAssetsPath: 'dist/layim-assets/' //layim 资源文件所在目录
}).extend({
  layim: layui.cache.layimPath + 'layim' //配置 layim 组件所在的路径
}).use('layim', function(layim){ //加载组件

  //基础配置
  layim.config({

    //初始化接口
     init: {

         mine: {
             "username": "${username }" //我的昵称
             ,"id": "${uid }" //我的ID
             ,"status": "online" //在线状态 online:在线、hide:隐身
             ,"remark": "" //我的签名
             ,"avatar": "" //我的头像
           }
    ,friend: []
    ,group: []
  }
      
    
    
    
    //上传图片接口
    ,uploadImage: {
      url: 'message/addImgaes.do'
      ,type: 'post'
    } 
    
    //上传文件接口
    ,uploadFile: {
      url: 'message/addFile.do'
      ,type: 'post'
    }
    
    ,isAudio: false //关闭聊天工具栏音频
    ,isVideo: false //关闭聊天工具栏视频
    
    ,brief: true //是否简约模式(若开启则不显示主面板)
    
    ,title: '我的咨询' //自定义主面板最小化时的标题
    //,right: '100px' //主面板相对浏览器右侧距离
    //,minRight: '90px' //聊天面板最小化时相对浏览器右侧距离
    ,initSkin: '5.jpg' //1-5 设置初始背景
    //,skin: ['aaa.jpg'] //新增皮肤
    ,isfriend: false //是否开启好友
    ,isgroup: false //是否开启群组
    ,min: false //是否始终最小化主面板,默认false
    ,notice: true //是否开启桌面消息提醒,默认false
    ,voice: false //声音提醒,默认开启,声音文件为:default.mp3
    ,maxlength:500//最长字符限制
    ,copyright:true
    //,msgbox: layui.cache.layimAssetsPath + 'html/msgbox.html' //消息盒子页面地址,若不开启,剔除该项即可
    //,find: layui.cache.layimAssetsPath + 'html/find.html' //发现页面地址,若不开启,剔除该项即可
    ,chatLog: 'jsp/chatrecord.jsp' //聊天记录页面地址,若不开启,剔除该项即可
    
  });


  //监听在线状态的切换事件
  layim.on('online', function(data){
    //console.log(data);
  });
  
  //监听签名修改
  layim.on('sign', function(value){
    //console.log(value);
  });
  

  //监听layim建立就绪
  layui.use('layim', function(layim){
	var userId = '${uid }';
  	// 服务端WebSocket的访问路径。(注意:路径前缀务必添加websocket的“ws://”。username为登录用户,与服务端WebSocket的username一致。)
  	
  	var action = 'ws://localhost:8080/WeChat/WebSocketServer/'+ userId;
  	// 初始化Socket
  	if('WebSocket' in window) {
  		websocket = new WebSocket(action); 
  	} else if('MozWebSocket' in window) {
  		websocket = new MozWebSocket(action);
  	} else {
  		websocket = new SockJS(action);
  	}
  	// 连接成功建立的回调方法  
  	websocket.onopen = function () {
  	    layer.msg('连接成功!');
  	}
    // 连接异常的回调方法  
  	websocket.onError = function () {
  		layer.msg('连接异常!');
  	}
    // 连接关闭的回调方法  
  	websocket.onclose = function () {
  		alert('连接断开,请关闭此页面,重新进入!');
  	}
  	
  	//接受到来自服务器的消息
  	websocket.onmessage = function(event){
  		//转为json格式
  		var json = JSON.parse(event.data);
  		var type = json.type;
  		
  		if(type == 'linestate'){
  			if(json.state=='on'){
  				layim.setChatStatus('<span style="color:#FF5722;">在线</span>');
  			}else{
  				alert("当前咨询师不在线!")
  				layim.setChatStatus('<span style="color:#FF5722;">离线</span>');
  			}
  			
  		}else if(type == 'chatMessage'){
  	  		var sendto = json.data.mine;
  	  		var obj = {
  	  				username:sendto.username,//发送者昵称
  	  				avatar:sendto.avatar,//发送者头像
  	  				id:sendto.id,//发送者ID
  	  				type:json.data.to.type,//发送消息类型
  	  				content:sendto.content//发送消息内容
  	  		}
  	  		//打印来自服务器的消息
  	  		console.log(json);
  	  		//一秒后触发layim接收到消息事件
  	  		setTimeout(function(){
  	  			layim.getMessage(obj);
  	  		},1000)
  	  		
  	  	  //将该条聊天记录保存到数据库
  	  	  $.ajax({
  	  		  url: "message/addMessage.do",
  	  		  async: false,//改为同步方式
  	  		  type: "POST",
  	  		  data: {"message":event.data},
  	  		  success: function (data) {
  	  			   console.log(data);	  
  	  		  }
  	  		  
  	  	  })
  		}

  		
  	},
  	
    //自定义会话
    layim.chat({
      name: "${username2 }"
      ,type: 'friend'
      ,avatar: ''
      ,id: '${uid2 }'
    });
  
	  
  });
  
  //监听发送消息(点击了发送)
  layim.on('sendMessage', function(res){
  	websocket.send(JSON.stringify({
        type: 'chatMessage', //用于在服务端区分消息类型
        data: res  //消息内容
          }));
  	
	  var toid = '${uid2 }';
	  var myid = '${uid }';
	  id = {toid: toid,myid:myid}
	  	websocket.send(JSON.stringify({
	        type: 'isline', //用于在服务端区分消息类型
	        data: id  //消息内容
	          }));	
    });

  

  
   //每次窗口打开或切换,即更新对方的状态
  layim.on('chatChange', function(res){
	  var toid = '${uid2 }';
	  var myid = '${uid }';
	  id = {toid: toid,myid:myid}
	  	websocket.send(JSON.stringify({
	        type: 'isline', //用于在服务端区分消息类型
	        data: id  //消息内容
	          }));	 
  });




});



</script>
</html>

work.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<base href="${pageContext.request.contextPath }/">
<meta name="viewport" content="width=device-width, initial-scale=1">
  <title>工作台</title>
  <link rel="stylesheet" href="layui/css/layui.css">
  <style>
  html{background-color: #333;}
  </style>
</head>
<body>
 
</body>
<script src="layui/layui.js"></script>
<script src="js/jquery-1.9.1.js"></script>
<script>

layui.config({
  layimPath: 'dist/' //配置 layim.js 所在目录
  ,layimAssetsPath: 'dist/layim-assets/' //layim 资源文件所在目录
}).extend({
  layim: layui.cache.layimPath + 'layim' //配置 layim 组件所在的路径
}).use('layim', function(layim){ //加载组件

  //基础配置
  layim.config({
  
    //初始化接口
     init: {

         mine: {
             "username": "${username }" //我的昵称
             ,"id": "${uid }" //我的ID
             ,"status": "online" //在线状态 online:在线、hide:隐身
             ,"remark": "" //我的签名
             ,"avatar": "" //我的头像
           }
    ,friend: []
    ,group: []
  }
      
    
    
    
    //上传图片接口
    ,uploadImage: {
      url: 'message/addImgaes.do'
      ,type: 'post'
    } 
    
    //上传文件接口
    ,uploadFile: {
        url: 'message/addFile.do'
        ,type: 'post'
    }
    
    ,isAudio: false //关闭聊天工具栏音频
    ,isVideo: false //关闭聊天工具栏视频
    
    ,brief: false //是否简约模式(若开启则不显示主面板)
    
    ,title: '我的咨询' //自定义主面板最小化时的标题
    //,right: '100px' //主面板相对浏览器右侧距离
    //,minRight: '90px' //聊天面板最小化时相对浏览器右侧距离
    ,initSkin: '5.jpg' //1-5 设置初始背景
    //,skin: ['aaa.jpg'] //新增皮肤
    ,isfriend: false //是否开启好友
    ,isgroup: false //是否开启群组
    ,min: false //是否始终最小化主面板,默认false
    ,notice: true //是否开启桌面消息提醒,默认false
    ,voice: false //声音提醒,默认开启,声音文件为:default.mp3
    ,maxlength:500//最长字符限制
    ,copyright:true
    //,msgbox: layui.cache.layimAssetsPath + 'html/msgbox.html' //消息盒子页面地址,若不开启,剔除该项即可
    //,find: layui.cache.layimAssetsPath + 'html/find.html' //发现页面地址,若不开启,剔除该项即可
    ,chatLog: 'jsp/chatrecord.jsp' //聊天记录页面地址,若不开启,剔除该项即可
    
  });


  //监听在线状态的切换事件
  layim.on('online', function(data){
    //console.log(data);
  });
  
  //监听签名修改
  layim.on('sign', function(value){
    //console.log(value);
  });
  

  //监听layim建立就绪
  layui.use('layim', function(layim){
	var userId = '${uid }';
  	// 服务端WebSocket的访问路径。(注意:路径前缀务必添加websocket的“ws://”。username为登录用户,与服务端WebSocket的username一致。)
  	
  	var action = 'ws://localhost:8080/WeChat/WebSocketServer/'+ userId;
  	// 初始化Socket
  	if('WebSocket' in window) {
  		websocket = new WebSocket(action); 
  	} else if('MozWebSocket' in window) {
  		websocket = new MozWebSocket(action);
  	} else {
  		websocket = new SockJS(action);
  	}
  	// 连接成功建立的回调方法
  	websocket.onopen = function () {
  		layer.msg('连接成功!');
  	}
    // 连接异常的回调方法  
  	websocket.onError = function () {
  		layer.msg('连接异常!');
  	}
    // 连接关闭的回调方法  
  	websocket.onclose = function () {
  		alert('连接断开,请关闭此页面!');
  	}
    
  	//接受到来自服务器的消息
  	websocket.onmessage = function(event){
  		//转为json格式
  		var json = JSON.parse(event.data);
  		var type = json.type;
  		if(type == 'linestate'){
  			if(json.state=='on'){
  				layim.setChatStatus('<span style="color:#FF5722;">在线</span>');
  			}else{				
  				layim.setChatStatus('<span style="color:#FF5722;">离线</span>');
  				alert("对方不在线!");
  			}
  			
  		}else if(type == 'chatMessage'){
  	  		var sendto = json.data.mine;
  	  		var obj = {
  	  				username:sendto.username,//发送者昵称
  	  				avatar:sendto.avatar,//发送者头像
  	  				id:sendto.id,//发送者ID
  	  				type:json.data.to.type,//发送消息类型
  	  				content:sendto.content//发送消息内容
  	  		}
  	  		//打印来自服务器的消息
  	  		console.log(json);
  	  		//一秒后触发layim接收到消息事件
  	  		setTimeout(function(){
  	  			layim.getMessage(obj);
  	  		},1000)
  	  		
  	  	  //将该条聊天记录保存到数据库
  	  	  $.ajax({
  	  		  url: "message/addMessage.do",
  	  		  async: false,//改为同步方式
  	  		  type: "POST",
  	  		  data: {"message":event.data},
  	  		  success: function (data) {
  	  			   console.log(data);	  
  	  		  }
  	  		  
  	  	  })
  		}

  		
  	}

  });
  
  //监听发送消息(点击了发送)
  layim.on('sendMessage', function(res){
  	websocket.send(JSON.stringify({
        type: 'chatMessage', //用于在服务端区分消息类型
        data: res  //消息内容
          }));
    });
  

  
   //每次窗口打开或切换,即更新对方的状态
  layim.on('chatChange', function(res){
	  var toid = res.data.id;
	  var myid = '${uid }';
	  id = {toid: toid,myid:myid}
	  	websocket.send(JSON.stringify({
	        type: 'isline', //用于在服务端区分消息类型
	        data: id  //消息内容
	          }));	  
    
  });


});



</script>
</html>

到这一步大家分别点击前面创建的test.jsp页面的两个按钮,在弹出的两个窗口发送文字就可以实现简单的在线交流了。

至于代码中的消息保存至数据库并查看,以及图片和文件的发送功能,咱们下一篇文章见。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰风雪浪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值