zoukankan      html  css  js  c++  java
  • Websocket实现前后台通信,demo小测试

      新需求大概如下:用户登录系统,登录成功之后建立websocket连接,实现通信

      总体思路:前端不是我负责,只是简单的做个功能,先实现登录,把用户标识存入HttpSeesion,再建立websocket连接,拦截器HandshakeInterceptor拦截请求,把用户标识存入Map<String, Object> attributes,然后处理器handler处理各种操作。

    /** 
     * @author wangqq 
     * @version 创建时间:2018年11月1日 下午2:59:21 
     * 实现WebSocketConfigure配置自己的socket链接
     */
    @Configuration //用于定义配置类,可替换xml配置文件
    @EnableWebSocket
    @EnableWebMvc //启动Spring MVC特性
    public class WebsocketConfig implements WebSocketConfigurer {
    
        @Override
        public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
            // TODO Auto-generated method stub
            registry.addHandler(handler(), "show").addInterceptors(interceptor()).setAllowedOrigins("*");
        }
        
        @Bean
        public WebSocketHandler handler(){
            return new Hanlder();
        }
        
        @Bean  
        public HandshakeInterceptor interceptor() {  
            return new HandshakeInterceptor();  
        }  
    
    }
    registry.addHandler第一个参数是处理器,自己可以写,第二个参数是前后台建立链接的路径,
    addInterceptors 添加拦截,再握手之前之后,处理自己的业务
    setAllowedOrigins 解决跨域,*代表不限,如果要指定域名则要http或者https开头

    /** 
     * @author wangqq 
     * @version 创建时间:2018年11月1日 下午3:06:36 
     * 类说明 
     */
    public class Hanlder extends TextWebSocketHandler {
        private Logger logger = Logger.getLogger(Hanlder.class);
        private static final Map<Integer,WebSocketSession> hotels;
        
        static{
            hotels = new HashMap<Integer, WebSocketSession>();
        }
    
        @Override
        public void afterConnectionEstablished(WebSocketSession session)
                throws Exception {
            // TODO Auto-generated method stub
            Integer hotelid = IHelper.toInteger(session.getAttributes().get("hotelid"));
            logger.info("-----------------afterConnectionEstablished-----------------");
            if(null != hotelid){
                logger.info(String.format("酒店连接,id:%s", hotelid));
                hotels.put(hotelid, session);
    JSONObject json
    = new JSONObject(); json.put("code","testMessage"); session.sendMessage(new TextMessage(json.toString())); } //super.afterConnectionEstablished(session); } /** * js调用websocket.send时候,会调用该方法 */ @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { // TODO Auto-generated method stub logger.info(String.format("收到酒店(id:%s)发来消息,消息详情:%s", session.getAttributes().get("hotelid"),message.toString())); super.handleTextMessage(session, message); //这里可以给用户发消息 logger.info("执行Hanlder---------客户端收到请求"); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { // TODO Auto-generated method stub Integer hotelid = IHelper.toInteger(session.getAttributes().get("hotelid")); logger.info(String.format("用户退出,酒店id:%s", hotelid)); hotels.remove(hotelid); super.afterConnectionClosed(session, status); } /** * 给单个用户发消息 * @param hotelid * @param message * @throws IOException */ public void sendMessage(Integer hotelid,TextMessage message) throws Exception{ if(hotels.containsKey(hotelid)){ if(hotels.get(hotelid).isOpen()){ hotels.get(hotelid).sendMessage(message); } } } /** * 给所有在线用户发消息 * @param message * @throws IOException */ public void sendMessage(TextMessage message) throws Exception{ for(Integer id : hotels.keySet()){ WebSocketSession session = hotels.get(id); if(session.isOpen()){ session.sendMessage(message); } } } /** * 多个在线用户,不同消息 * @param data * @throws Exception */ public void sendMessage(Map<Integer, TextMessage> data) throws Exception{ for(Map.Entry<Integer, TextMessage> entry : data.entrySet()){ Integer hotelid = entry.getKey(); this.sendMessage(hotelid, entry.getValue()); } } /** * 多个用户,同一消息 * @param hotelids * @param message * @throws Exception */ public void sendMessage(List<Integer> hotelids,TextMessage message) throws Exception{ for(Integer id : hotelids){ this.sendMessage(id, message); } } }
    /** 
     * @author wangqq 
     * @version 创建时间:2018年11月2日 下午1:42:00 
     * 类说明 
     */
    public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {
        
        private Logger logger = Logger.getLogger(HandshakeInterceptor.class);
        
        @Override
        public boolean beforeHandshake(ServerHttpRequest request,
                ServerHttpResponse response, WebSocketHandler wsHandler,
                Map<String, Object> attributes) throws Exception {
            // TODO Auto-generated method stub
            logger.info("-----------beforeHandshake---------");
            if(request instanceof ServletServerHttpRequest){
                ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest)request;
                HttpSession session = serverHttpRequest.getServletRequest().getSession();
                if(null != session){
                    logger.info("拦截请求,存入attribute,酒店id:"+session.getAttribute("hotelid"));
                    if(null!=session.getAttribute("hotelid")){
                        attributes.put("hotelid", session.getAttribute("hotelid"));
                    }
                }
            }
            return super.beforeHandshake(request, response, wsHandler, attributes);
        }
        
        @Override
        public void afterHandshake(ServerHttpRequest request,
                ServerHttpResponse response, WebSocketHandler wsHandler,
                Exception ex) {
            // TODO Auto-generated method stub
            logger.info("-----------afterHandshake--------------");
            super.afterHandshake(request, response, wsHandler, ex);
        }
    }

    前端页面(简单的不能再简单,没有考虑浏览器支不支持)

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'index.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <!--
        <link rel="stylesheet" type="text/css" href="styles.css">
        -->
        <script language="JavaScript" src="jquery/jquery-1.11.3.min.js" charset="UTF-8"></script>
        <script type="text/javascript">
            var ws = 
            $(function(){
                $.ajaxSettings.async=false;
                $.post('<%=basePath%>/show/doSaveSession',{'hotelid':1},function(data){
                    console.log("执行保存session");//模拟先登录
                });
                $.ajaxSettings.async=true;
                ws = new WebSocket("ws://localhost:7001/show");
                
               ws.onopen = function () {
                  console.log("建立链接");
                
               }
               ws.onclose = function () {
                  console.log("onclose");
               }
         
               ws.onmessage = function (msg) {
                       console.log("----------------");
                    console.log(msg.data);
               }
            });
            
        </script>
    
      </head>
      
      <body>
        This is my JSP page. <br>
    
      </body>
    </html>

    执行结果:

    前台

    后台:

    ps:2018-11-19 更新,后来测试一下,不用提前登陆,直接在前端连socket的路径上面加参数,而后在拦截器的

    beforeHandshake中就可把连接的用户存入map
  • 相关阅读:
    Base64编码原理分析
    对 js 高程 Preflighted Reqeusts 的理解
    js 跨域 之 修改服务器配置-XAMPP-Apache (nginx 拉到最后!)
    js 模拟 select 的 click 事件
    串讲-解释篇:作用域,作用域链,执行环境,变量对象,活动对象,闭包
    js 匿名函数-立即调用的函数表达式
    Java I/O流输入输出,序列化,NIO,NIO.2
    Java8Lambda表达式
    设计模式之适配器模式
    设计模式之装饰器设计模式
  • 原文地址:https://www.cnblogs.com/Cassie-wang/p/9923437.html
Copyright © 2011-2022 走看看