深圳Java学习:WebSocket 整合 Springboot

深圳Java学习:WebSocket 整合 Springboot
WebSocket+Springboot
1.1 pom 文件的依赖和插件

org.springframework.boot
spring-boot-starter-parent
1.5.9.RELEASE


    
        junit
        junit
        3.8.1
        test
    
    
    
        javax.servlet
        javax.servlet-api
        3.1.0
    
    
        org.glassfish.web
        jsp
        2.2
    
    
    
        javax.websocket
        javax.websocket-api
        1.1
        provided
    
    
    
        net.sf.json-lib
        json-lib
        2.4
    
    
        org.springframework.boot
        spring-boot-starter-web
        
            
                org.springframework.boot
                spring-boot-starter-tomcat
            
        
    
    
    
        org.springframework
        spring-websocket
    
  
    
        ch.qos.logback
        logback-core
    
    
        ch.qos.logback
        logback-classic
    


    websocketspring

    
        
            org.springframework.boot
            spring-boot-maven-plugin
        
    

1.2 WebSocket 的配置文件
用于启动 websocket,注入处理器和拦截器
/**

  • Created by jackiechan on 2018/2/5/下午4:05
    /
    @Configuration //声明为配置文件
    @EnableWebSocket//启用 websocket
    public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
    System.out.println(“初始化路径拦截”);//指定所有/websocket开头的路径会被 websocket 拦截,设置处理器和拦截器
    webSocketHandlerRegistry.addHandler(chatMessageHandler(),"/websocket/
    ").addInterceptors(new ChatHandshakeInterceptor());
    }

    /**

    • 创建处理器
    • @return
      */
      @Bean
      public TextWebSocketHandler chatMessageHandler(){
      System.out.println(“创建 handler”);
      return new ChatMessageHandler();
      }
      }

1.3 ChatHandshakeInterceptor拦截器
用于每次 websocket 在握手之前进行拦截,可以在内部进行校验

/**

  • Created by jackiechan on 2018/2/5/下午4:16

  • WebSocket握手请求的拦截器. 检查握手请求和响应, 对WebSocketHandler传递属性
    /
    public class ChatHandshakeInterceptor extends HttpSessionHandshakeInterceptor {
    /
    *

    • 在握手之前执行该方法, 继续握手返回true, 中断握手返回false. 通过attributes参数设置WebSocketSession的属性

    • @param request

    • @param response

    • @param wsHandler

    • @param attributes

    • @return

    • @throws Exception
      */
      @Override
      public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
      Map attributes) throws Exception {
      //为了方便区分来源,在此以用户的名字来区分,名字我们通过要求用输入进行传递,所以在这里先从请求中获取到用户输入的名字,因为是使用的rest 风格,所以规定路径的最后一个字符串是名字
      System.out.println(“握手之前”);
      String s = request.getURI().toString();
      String s1 = s.substring(s.lastIndexOf("/") + 1);
      attributes.put(Constants.WEBSOCKET_USERNAME, s1);//给当前连接设置属性

      return super.beforeHandshake(request, response, wsHandler, attributes);
      }

    /**

    • 在握手之后执行该方法. 无论是否握手成功都指明了响应状态码和相应头.
    • @param request
    • @param response
    • @param wsHandler
    • @param ex
      */
      @Override
      public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
      Exception ex) {
      System.out.println(“After Handshake”);
      super.afterHandshake(request, response, wsHandler, ex);
      }

}

1.4 ChatMessageHandler消息处理器
用于收到消息的时候处理消息

/**

  • Created by jackiechan on 2018/2/5/下午4:11

  • 文本消息的处理器
    */
    public class ChatMessageHandler extends TextWebSocketHandler {

    private static final Map allClients;//用于缓存所有的用户和连接之间的关系
    private static Logger logger = Logger.getLogger(ChatMessageHandler.class);

    static {
    allClients = new ConcurrentHashMap();//初始化连接
    }

    /**

    • 当和用户成功建立连接的时候会调用此方法,在此方法内部应该保存连接
      */
      @Override
      public void afterConnectionEstablished(WebSocketSession session) throws Exception {
      System.out.println(“建立连接成功”);
      String name = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);//将在拦截器中保存的用户的名字取出来,然后作为 key 存到 map 中
      if (name != null) {
      allClients.put(name, session);//保存当前的连接和用户之间的关系
      }
      // 这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户

    }

    /**

    • 收到消息的时候会触发该方法
    • @param session 发送消息的用户的 session
    • @param message 发送的内容
    • @throws Exception
      */
      @Override
      protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
      //此处请根据自己的具体业务逻辑做处理
      JSONObject jsonObject= JSONObject.fromObject(new String(message.asBytes()));//将用户发送的消息转换为 json,实际开发中请根据自己的需求处理
      String toName = jsonObject.getString(“toName”);//获取数据中的收消息人的名字
      String content = jsonObject.getString(“content”);//获取到发送的内容
      String fromName = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);//获取当前发送消息的人的名字
      content = “收到来自:” +fromName+ “的消息,内容是:” + content;
      //拼接内容转发给接收者,实际开发中请参考自己的需求做处理
      TextMessage textMessage = new TextMessage(content);//将内容转换为 TextMessage
      sendMessageToUser(toName,textMessage);// 发送给指定的用户
      //sendMessageToUsers(message);//给所有人发送
      //super.handleTextMessage(session, message);
      }

    /**

    • 给某个用户发送消息
    • @param userName
    • @param message
      */
      public void sendMessageToUser(String userName, TextMessage message) {
      WebSocketSession webSocketSession = allClients.get(userName);//根据接收方的名字找到对应的连接
      if (webSocketSession != null&& webSocketSession.isOpen()) {//如果没有离线,如果离线,请根据实际业务需求来处理,可能会需要保存离线消息
      try {
      webSocketSession.sendMessage(message);//发送消息
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }

    /**

    • 给所有在线用户发送消息,此处以文本消息为例子

    • @param message
      */
      public void sendMessageToUsers(TextMessage message) {
      for (Map.Entry webSocketSessionEntry : allClients.entrySet()) {//获取所有的连接

       WebSocketSession session = webSocketSessionEntry.getValue();//找到每个连接
       if (session != null&& session.isOpen()) {
           try {
               session.sendMessage(message);
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
      

      }
      }

    /**

    • 出现异常的时候
    • @param session
    • @param exception
    • @throws Exception
      */
      @Override
      public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
      String name = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);
      if (session.isOpen()) {
      session.close();
      }
      logger.debug(“连接关闭”);
      allClients.remove(name);//移除连接
      }

    /**

    • 连接关闭后
    • @param session
    • @param closeStatus
    • @throws Exception
      */
      @Override
      public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
      logger.debug(“连接关闭”);
      String name = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);//找到用户对应的连接
      allClients.remove(name);//移除
      }

    @Override
    public boolean supportsPartialMessages() {
    return false;
    }

}
1.5 springboot 启动类
注意此类最好放在根包下

/**

  • Created by jackiechan on 2018/2/5/下午4:34
    */
    @SpringBootApplication
    @Configuration
    public class App {
    public static void main(String[] args) {
    SpringApplication.run(App.class, args);// spingboot }
    }
    }

1.6 web 方式启动项的配置类

/**

  • Created by jackiechan on 2018/2/5/下午4:34
    用于将项目打包成 war 包后发布
    */
    public class SpringBootStartApplication extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder)
    {
    return builder.sources(App.class);
    }
    }

1.7 html
与非 springboot 的方式内容一致

Title 用户名: 连接
接收者:
内容:
发送



1.8 启动测试

深圳Java学习:WebSocket 整合 Springboot_第1张图片

你可能感兴趣的:(深圳Java学习)