Spring WebSocket实现消息推送

5人阅读 评论(0) 收藏 举报
分类:

支持原创,原文链接


第一步: 添加Spring WebSocket的依赖jar包

(注:这里使用maven方式添加 手动添加的同学请自行下载相应jar包放到lib目录)

复制代码
        <!-- 使用spring websocket依赖的jar包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
            <version>${spring.version}</version>
        </dependency>            
复制代码

第二步:建立一个类实现WebSocketConfigurer接口

复制代码
package com.quicksand.push;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.handler.TextWebSocketHandler;


@Configuration
@EnableWebMvc
@EnableWebSocket
public class SpringWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketHandler(),"/websocket/socketServer.do").addInterceptors(new SpringWebSocketHandlerInterceptor());
        registry.addHandler(webSocketHandler(), "/sockjs/socketServer.do").addInterceptors(new SpringWebSocketHandlerInterceptor()).withSockJS();
    }
 
    @Bean
    public TextWebSocketHandler webSocketHandler(){
        return new SpringWebSocketHandler();
    }

}
复制代码

 第三步:继承WebSocketHandler对象。该对象提供了客户端连接,关闭,错误,发送等方法,重写这几个方法即可实现自定义业务逻辑

复制代码
package com.quicksand.push;

import java.io.IOException;
import java.util.ArrayList;
import org.apache.log4j.Logger;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;


public class SpringWebSocketHandler extends TextWebSocketHandler {
    private static final ArrayList<WebSocketSession> users;//这个会出现性能问题,最好用Map来存储,key用userid
    private static Logger logger = Logger.getLogger(SpringWebSocketHandler.class);
    static {
        users = new ArrayList<WebSocketSession>();
    }
    
    public SpringWebSocketHandler() {
        // TODO Auto-generated constructor stub
    }

    /**
     * 连接成功时候,会触发页面上onopen方法
     */
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("connect to the websocket success......当前数量:"+users.size());
        users.add(session);
        //这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户
        //TextMessage returnMessage = new TextMessage("你将收到的离线");
        //session.sendMessage(returnMessage);
    }
    
    /**
     * 关闭连接时触发
     */
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        logger.debug("websocket connection closed......");
        String username= (String) session.getAttributes().get("WEBSOCKET_USERNAME");
        System.out.println("用户"+username+"已退出!");
        users.remove(session);
        System.out.println("剩余在线用户"+users.size());
    }

    /**
     * js调用websocket.send时候,会调用该方法
     */
    @Override    
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        super.handleTextMessage(session, message);
    }

    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        if(session.isOpen()){session.close();}
        logger.debug("websocket connection closed......");
        users.remove(session);
    }

    public boolean supportsPartialMessages() {
        return false;
    }
    
    
    /**
     * 给某个用户发送消息
     *
     * @param userName
     * @param message
     */
    public void sendMessageToUser(String userName, TextMessage message) {
        for (WebSocketSession user : users) {
            if (user.getAttributes().get("WEBSOCKET_USERNAME").equals(userName)) {
                try {
                    if (user.isOpen()) {
                        user.sendMessage(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }
    
    /**
     * 给所有在线用户发送消息
     *
     * @param message
     */
    public void sendMessageToUsers(TextMessage message) {
        for (WebSocketSession user : users) {
            try {
                if (user.isOpen()) {
                    user.sendMessage(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
复制代码

第四步:继承HttpSessionHandshakeInterceptor对象。该对象作为页面连接websocket服务的拦截器,代码如下:

复制代码
package com.quicksand.push;
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

/**
 * WebSocket拦截器
 * @author WANG
 *
 */
public class SpringWebSocketHandlerInterceptor extends HttpSessionHandshakeInterceptor {
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("Before Handshake");
        if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
            HttpSession session = servletRequest.getServletRequest().getSession(false);
            if (session != null) {
                //使用userName区分WebSocketHandler,以便定向发送消息
                String userName = (String) session.getAttribute("SESSION_USERNAME");
                if (userName==null) {
                    userName="default-system";
                }
                attributes.put("WEBSOCKET_USERNAME",userName);
            }
        }
        return super.beforeHandshake(request, response, wsHandler, attributes);
        
    }
    
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
            Exception ex) {
        // TODO Auto-generated method stub
        super.afterHandshake(request, response, wsHandler, ex);
    }
}
复制代码

第5步 让SpringWebSocketConfig配置类随spring容器启动 spring文件中加入如下代码:

<!-- websocket相关扫描,主要扫描:WebSocketConfig  如果前面配置能扫描到此类则可以不加 -->
<context:component-scan base-package="com.quicksand.push"/>

 

 

-------------------------------------------------------------------------到这里就算完成啦 下面准备测试-------------------------------------------------------------

1.定义一个控制器用来做连接标识和发送消息

复制代码
package com.quicksand.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.socket.TextMessage;

import com.quicksand.push.SpringWebSocketHandler;

@Controller
public class WebsocketController {
    @Bean//这个注解会从Spring容器拿出Bean
    public SpringWebSocketHandler infoHandler() {
        return new SpringWebSocketHandler();
    }

    @RequestMapping("/websocket/login")
    public ModelAndView login(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String username = request.getParameter("username");
        System.out.println(username+"登录");
        HttpSession session = request.getSession(false);
        session.setAttribute("SESSION_USERNAME", username);
        //response.sendRedirect("/quicksand/jsp/websocket.jsp");
        return new ModelAndView("websocket");
    }

    @RequestMapping("/websocket/send")
    @ResponseBody
    public String send(HttpServletRequest request) {
        String username = request.getParameter("username");
        infoHandler().sendMessageToUser(username, new TextMessage("你好,测试!!!!"));
        return null;
    }
}
复制代码

 

2.建立登录页面

复制代码
<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
<h2>Hello World!</h2>
<body>
    <!-- ship是我的项目名-->
    <form action="websocket/login.do">
        登录名:<input type="text" name="username"/>
        <input type="submit" value="登录"/>
    </form>
</body>
</body>
</html>
复制代码

 

3.建立发消息页面

复制代码
<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<script type="text/javascript" src="http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script>
<script type="text/javascript" src="http://cdn.bootcss.com/sockjs-client/1.1.1/sockjs.js"></script>
<script type="text/javascript">
    var websocket = null;
    if ('WebSocket' in window) {
        websocket = new WebSocket("ws://localhost:8080/quicksand/websocket/socketServer.do");
    } 
    else if ('MozWebSocket' in window) {
        websocket = new MozWebSocket("ws://localhost:8080/quicksand/websocket/socketServer.do");
    } 
    else {
        websocket = new SockJS("http://localhost:8080/quicksand/sockjs/socketServer.do");
    }
    websocket.onopen = onOpen;
    websocket.onmessage = onMessage;
    websocket.onerror = onError;
    websocket.onclose = onClose;
              
    function onOpen(openEvt) {
        //alert(openEvt.Data);
    }
    
    function onMessage(evt) {
        alert(evt.data);
    }
    function onError() {}
    function onClose() {}
    
    function doSend() {
        if (websocket.readyState == websocket.OPEN) {          
            var msg = document.getElementById("inputMsg").value;  
            websocket.send(msg);//调用后台handleTextMessage方法
            alert("发送成功!");  
        } else {  
            alert("连接失败!");  
        }  
    }

   window.close=function()
   {
     websocket.onclose();
   }

</script>
请输入:<textarea rows="5" cols="10" id="inputMsg" name="inputMsg"></textarea>
<button onclick="doSend();">发送</button>
</body>
</html>
复制代码

 

测试结果如下图:

 

查看评论

Spring+Websocket实现消息的推送

  • 2017年10月11日 16:34
  • 1006KB
  • 下载

Spring+Websocket实现消息的推送 【转】

文章出处:Spring+Websocket实现消息的推送 本文主要有三个步骤 1、用户登录后建立websocket连接,默认选择websocket连接,如果浏览器不支持,则使用sockjs进行模拟连...
  • woshizhangliang999
  • woshizhangliang999
  • 2016-01-26 11:05:28
  • 2568

spring 结合 websocket 做的小例子 支持消息推送给所有用户

  • 2015年07月13日 00:22
  • 191KB
  • 下载

使用spring boot +WebSocket实现(后台主动)消息推送

有个需求:APP用户产生某个操作,需要让后台管理系统部分人员感知(表现为一个页面消息)。最早版本是后台管理系统轮训,每隔一段时间轮训一次,由于消息重要,每隔几秒就查一次。这样做明显很不雅!会消耗大量资...
  • zhangdehua678
  • zhangdehua678
  • 2017-12-27 16:40:44
  • 10644

SpringMVC整合websocket实现消息推送及触发

1.创建websocket握手协议的后台 (1)HandShake的实现类 /** *Project Name: price *File Name: HandShake.java *Pac...
  • liuyunshengsir
  • liuyunshengsir
  • 2016-09-10 17:20:20
  • 15543

Spring boot websocket消息推送

Spring boot webSocket消息推送
  • Veggiel
  • Veggiel
  • 2016-08-24 14:19:52
  • 3084

使用Spring WebSocket实现消息推送

第一步: 添加Spring WebSocket的依赖jar包 (注:这里使用maven方式添加 手动添加的同学请自行下载相应jar包放到lib目录) 使用spring webso...
  • zmx729618
  • zmx729618
  • 2017-11-20 17:43:50
  • 449

在Spring Boot框架下使用WebSocket实现消息推送

Spring Boot的学习持续进行中。前面两篇博客我们介绍了如何使用Spring Boot容器搭建Web项目(使用Spring Boot开发Web项目)以及怎样为我们的Project添加HTTPS的...
  • u012702547
  • u012702547
  • 2016-12-23 16:48:37
  • 56133

基于spring websocket实现广播及点对点推送功能

本文针对 Web 开发中实现服务器往客户端推送消息的关键技术 websocket 进行重点说明,并且基于spring websocket 实现服务器对客户端的广播及点对点推送功能,供大家参考讨论。...
  • chenjhit
  • chenjhit
  • 2017-07-19 15:02:19
  • 2204
    常用链接
    最新评论