spring boot webScoket 学习 demo

spring boot webScoket 学习 demo
spring boot webScoket 学习 demo
spring boot webScoket 学习 demo

Java后端部分

  1. 引入对应maven依赖

    <dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-websocket</artifactId>
    	</dependency>
    复制代码
  2. 注入ServerEndpointExporter

    @Configuration
    public class WebSocketConfig {
    
        /**
         * 服务器节点
         *
         * 如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理
         * @return
         */
        @Bean
        public ServerEndpointExporter serverEndpointExporter() {
            return new ServerEndpointExporter();
        }
    
    }
    复制代码
  3. 代码实现webSocket,具体的实现还要看业务需求,GuavaCacheUtil是我本地的一个guava的缓存工具类

    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import io.renren.common.exception.RRException;
    import io.renren.common.utils.GuavaCacheUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang.StringUtils;
    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.Iterator;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.atomic.AtomicInteger;
    /**
     * @Auther zxl
     * @Date 2020/3/8 16:49
     * @Description
     **/
    @ServerEndpoint("/websocket/{sToken}")
    @Component
    @Slf4j
    public class WebSocketServer {
    private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    /**
     * 管理员聊天用户数目
     */
    private static ConcurrentHashMap<String,Integer> adminUserCountMap = new ConcurrentHashMap<>();
    
    /**
     * 在线的管理员
     */
    private static AtomicInteger adminCount = new AtomicInteger(0);
    /**
     * 在线的用户
     */
    private static AtomicInteger userCount = new AtomicInteger(0);
    
    private Session session;
    
    private String sToken;
    
    private static final String SYS_STOKEN = "SYS";
    
    /**
     * 连接建立成功
     * @param session
     * @param sToken
     */
    @OnOpen
    public void onOpen(Session session,@PathParam("sToken") String sToken){
    
        if (sToken.endsWith("000")){
            // 测试使用
            GuavaCacheUtil.put(sToken,0);
        }
        if(GuavaCacheUtil.getIfPresent(sToken) == null){
            // sToken无效或失效
            return;
        }
        this.session = session;
        this.sToken = sToken;
        if (webSocketMap.containsKey(sToken)){
            webSocketMap.remove(sToken);
        }
        webSocketMap.put(sToken,this);
    
        if (sToken.startsWith("ADMIN")){
            adminCount.incrementAndGet();
            if (adminUserCountMap.containsKey(sToken)){
                adminUserCountMap.remove(sToken);
            }
            adminUserCountMap.put(sToken,0);
        }else if (sToken.startsWith("USER")){
            userCount.incrementAndGet();
            // 分配管理员
            String adminSToken = getAdmin();
            // 通知用户管理员sToken
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("msg",adminSToken);
            jsonObject.put("toUser",sToken);
            jsonObject.put("fromUser",SYS_STOKEN);
            jsonObject.put("code",1);
            this.sendMessage(jsonObject.toJSONString());
            // 管理员用户数+1
            adminUserCountMap.put(adminSToken,adminUserCountMap.get(adminSToken) + 1);
        }
    }
    @OnClose
    public void onClose(){
        if (webSocketMap.containsKey(sToken)){
            webSocketMap.remove(sToken);
        }
        if (sToken.startsWith("ADMIN")){
            adminCount.decrementAndGet();
        }else if (sToken.startsWith("USER")){
            userCount.decrementAndGet();
        }
        GuavaCacheUtil.remove(sToken);
    }
    
    @OnMessage
    public void onMessage(String message, Session session){
    
        JSONObject jsonObject = JSON.parseObject(message);
        String toUser = jsonObject.getString("toUser");
        if (StringUtils.isNotBlank(toUser)&&webSocketMap.containsKey(toUser)){
            jsonObject.put("fromUser",sToken);
            jsonObject.put("code",0);
            webSocketMap.get(toUser).sendMessage(jsonObject.toJSONString());
        }else {
            jsonObject.remove("toUser");
            jsonObject.remove("msg");
            jsonObject.put("toUser",sToken);
            jsonObject.put("fromUser",SYS_STOKEN);
            jsonObject.put("code",404);
            jsonObject.put("msg","对方已下线");
            webSocketMap.get(sToken).sendMessage(jsonObject.toJSONString());
        }
        log.info("sToken: {},message:{}",sToken,jsonObject.toJSONString());
    
    
    }
    
    @OnError
    public void onError(Session session, Throwable error) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("toUser",sToken);
        jsonObject.put("fromUser",SYS_STOKEN);
        jsonObject.put("code",500);
        jsonObject.put("msg","系统异常");
        webSocketMap.get(sToken).sendMessage(jsonObject.toJSONString());
        log.error("用户错误:"+sToken+",原因:"+error.getMessage());
    }
    
    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message){
        try {
            this.session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("socket error: {}",e);
        }
        log.info("socket send msg : {}",message);
    }
    
    /**
     * 获取聊天用户最少的管理员sToken
     * @return
     */
    private String getAdmin(){
    
        if (adminUserCountMap.size() == 0){
            return null;
        }
        String sToken = "";
        int count = 0;
        Iterator<Map.Entry<String,Integer>> iterator = adminUserCountMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String,Integer> m = iterator.next();
            if (StringUtils.isBlank(sToken)){
                sToken = m.getKey();
                count = m.getValue();
            }else if (m.getValue() < count){
                sToken = m.getKey();
                count = m.getValue();
            }
        }
        return sToken;
    }
    
    
    /**
     * 自定义发送游戏
     * @param msg
     * @param sToken
     */
    public static void sendMsg(String msg,String sToken){
        if (StringUtils.isNotBlank(sToken) && webSocketMap.containsKey(sToken)){
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("msg",msg);
            jsonObject.put("toUser",sToken);
            jsonObject.put("fromUser",SYS_STOKEN);
            jsonObject.put("code",0);
            webSocketMap.get(sToken).sendMessage(jsonObject.toJSONString());
        }else {
            throw new RRException("用户已下线");
        }
    }}
    
    复制代码
  4. 开放一个http接口用于推送消息,R是我自定义的全局返回对象

    /**
         * @Auther zxl
         * @Date 2020/3/8 19:11
         * @Description
         **/
        @RestController
        public class ScoketController {
        
            @RequestMapping("/push/{sToken}")
            public R pushToWeb(@RequestParam String message, @PathVariable String sToken) {
                WebSocketServer.sendMsg(message,sToken);
                return R.ok();
            }
        
        }
    复制代码

js前端实现,前端只是粗糙的实现了一下功能

  1. 管理员页面

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>管理员scoket</title>
    	</head>
    	<body id="body">
    		<h1>当前用户:<span id="userCount"></span></h1>
    	</body>
    	<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    	<script>
    		var socket;
    		var sToken;
    		var user_sToken = []
    		var userCount = 0
    		$(function(){
    			
    			getStoken();
    			initSocket();
    			$("#userCount").html(0)
    			
    		})
    		// 获取sToken
    		function getStoken(){
    			// 模拟sToken,测试使用管理员sToken(ADMIN开头,000结尾),真实环境掉接口获取sToken
    			sToken = "ADMIN1000"
    		}
    		// 初始化socket
    		function initSocket(){
    			if(typeof(WebSocket) == "undefined") {
    			    console.log("您的浏览器不支持WebSocket");
    				alert("您的浏览器不支持WebSocket");
    			}else{
    			    console.log("您的浏览器支持WebSocket");
    			    var socketUrl="http://localhost:8082/bocai-api/websocket/"+sToken;
    			    socketUrl=socketUrl.replace("https","ws").replace("http","ws");
    			    console.log(socketUrl);
    			    if(socket!=null){
    			        socket.close();
    			        socket=null;
    			    }
    			    socket = new WebSocket(socketUrl);
    			    //打开事件
    			    socket.onopen = function() {
    			        console.log("websocket已打开");
    					alert("socket打开成功")
    			    };
    			    //获得消息事件
    			    socket.onmessage = function(msg) {
    			        console.log(msg.data);
    					var data = JSON.parse(msg.data)
    					if(data.code != 0){
    						alert(data.msg)
    						return;
    					}
    					console.log(data)
    					console.log(user_sToken)
    					if($.inArray(data.fromUser,user_sToken) >= 0){
    						$("#"+data.fromUser).append('<tr><td>'+data.msg+'</td><td><td></tr>')
    						console.log('table添加新记录')
    					}else {
    						// 新用户消息
    						console.log('创建新table')
    						$("#body").append('<table style="margin-top:10px" border="2" bordercolor="black" width="500" cellspacing="0" cellpadding="5" id='+data.fromUser+'></table>')
    						$("#"+data.fromUser).append('<tr><td>通信用户:'+data.userName+data.mobile+'</td><td>用户sToken:'+data.fromUser+'</td></tr>')
    						$("#"+data.fromUser).append('<tr><td colspan="2"><input id=ip'+data.fromUser+' type="text"><button data-st='+data.fromUser+' onclick="sendMsg(this)">发送</button></td></tr>')
    						$("#"+data.fromUser).append('<tr><td>用户</td><td>我</td></tr>')
    						$("#"+data.fromUser).append('<tr><td>'+data.msg+'</td><td><td></tr>')
    						user_sToken.push(data.fromUser)
    						userCount++
    						$("#userCount").html(userCount)
    					}
    			    };
    			    //关闭事件
    			    socket.onclose = function() {
    			        console.log("websocket已关闭");
    			    };
    			    //发生了错误事件
    			    socket.onerror = function() {
    			        console.log("websocket发生了错误");
    			    }
    			}
    		}
    		function sendMsg(e){
    			var user_st = e.getAttribute("data-st")
    			console.log(user_st)
    			console.log($("#ip"+user_st).val())
    			var data = {msg:$("#ip"+user_st).val(),toUser:user_st,fromUser:sToken}
    			sendMessage(JSON.stringify(data))
    			$("#"+user_st).append('<tr><td></td><td>'+$("#ip"+user_st).val()+'</td></tr>')
    		}
    		function sendMessage(data) {
    		    if(typeof(WebSocket) == "undefined") {
    		        console.log("您的浏览器不支持WebSocket");
    		    }else {
    		        console.log("您的浏览器支持WebSocket");
    		        console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
    		        socket.send(data);
    		    }
    		}
    	</script>
    </html>
    
    复制代码
  2. 用户页面

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>用户scoket</title>
	</head>
	<body id="body">
		<h1>当前用户:<span id="userName"></span></h1>
		<table border="2" bordercolor="black" width="300" cellspacing="0" cellpadding="5" id="msgTable">
			<tr>
				<td  colspan="2">
					<input id="msg" type="text"><button  onclick="sendMsg()">发送</button>
				</td>
			</tr>
			<tr>
				<td>客服</td>
				<td>我</td>
			</tr>
		</table>

	</body>
	<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
	<script>
		var socket;
		var sToken;
		var admin_sToken;
		var userName = '小明'
		var mobile = '18539442736'
		$(function(){
			
			getStoken();
			initSocket();
			$("#userName").html(userName+mobile)
			
		})
		// 获取sToken
		function getStoken(){
			// 模拟sToken,测试使用管理员sToken(USER开头,000结尾),真实环境掉接口获取sToken
			sToken = "USER2000"
		}
		// 初始化socket
		function initSocket(){
			if(typeof(WebSocket) == "undefined") {
			    console.log("您的浏览器不支持WebSocket");
				alert("您的浏览器不支持WebSocket");
			}else{
			    console.log("您的浏览器支持WebSocket");
			    var socketUrl="http://39.105.129.210:8082/bocai-api/websocket/"+sToken;
			    socketUrl=socketUrl.replace("https","ws").replace("http","ws");
			    console.log(socketUrl);
			    if(socket!=null){
			        socket.close();
			        socket=null;
			    }
			    socket = new WebSocket(socketUrl);
			    //打开事件
			    socket.onopen = function() {
			        console.log("websocket已打开");
					alert("socket打开成功")
					
			    };
			    //获得消息事件
			    socket.onmessage = function(msg) {
			        console.log(msg.data);
					var data = JSON.parse(msg.data)
					if(data.code == 1){
						admin_sToken = data.msg
					}else if(data.code == 0){
						$("#msgTable").append('<tr><td>'+data.msg+'</td><td></td></tr>')
						console.log('table添加新记录')
					}else {
						alert(data.msg)
					}
					
			    };
			    //关闭事件
			    socket.onclose = function() {
			        console.log("websocket已关闭");
			    };
			    //发生了错误事件
			    socket.onerror = function() {
			        console.log("websocket发生了错误");
			    }
			}
		}
		function sendMsg(){
			var msg = $("#msg").val()
			var data = {userName:userName,mobile:mobile,msg:msg,toUser:admin_sToken,fromUser:sToken}
			sendMessage(JSON.stringify(data))
			$("#msgTable").append('<tr><td></td><td>'+msg+'</td></tr>')
		}
		function sendMessage(data) {
		    if(typeof(WebSocket) == "undefined") {
		        console.log("您的浏览器不支持WebSocket");
		    }else {
		        console.log("您的浏览器支持WebSocket");
		        console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
		        socket.send(data);
		    }
		}
	</script>
</html>

只是一个简单的demo,期待分享更优质的内容复制代码

原文 

https://juejin.im/post/5e652778e51d450edc0cd591

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » spring boot webScoket 学习 demo

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址