websocket篇

目录

应用篇


项目中用到后端主动推送的功能,简单记录下websocket。

springboot + tomcat + nginx + websocket的简单应用。项目采用前后端分离,前端用nginx代理为https类型,后端仍然是传统的http。

过程:

1、打开页面A,通过wss建立https长连接。

2、https仍然连接前台地址,通过nginx反向代理到后台的http地址。如果不这样,而是直接通过ws建立http连接后端,会报错https不允许访问http资源。

3、页面B发送ajax请求,处理业务逻辑并调用websocket的sendInfo方法,下面IWebSocketCcliveController类中的sendInfo()。

符合条件的页面A将会收到服务端推送过来的消息。

pom.xml里:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

springboot里:

  WebSocketConfig :

 坑一:如果项目最后打成war包放到tomcat中运行,则不需要这个配置。否则会报错

package cn.best.one.to.one.common.support.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

 IWebSocketCcliveController :

写法比较常规

@ServerEndpoint(value = "/interface/websocket/cclive/{itemId}")
@Component
public class IWebSocketCcliveController {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<IWebSocketCcliveController> webSocketSet = new CopyOnWriteArraySet<IWebSocketCcliveController>();

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    private String itemId;
    public String getItemId() {
        return itemId;
    }
    public void setItemId(String itemId) {
        this.itemId = itemId;
    }

    /**
     * 连接建立成功调用的方法*/
    @OnOpen
    public void onOpen(@PathParam(value="itemId") String itemId, Session session) {
        this.session = session;
        this.itemId = itemId;
        webSocketSet.add(this);     //加入set中
        addOnlineCount();           //在线数加1
        System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
        /*try {
            sendMessage("");
        } catch (IOException e) {
            System.out.println("IO异常");
        }*/
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //从set中删除
        subOnlineCount();           //在线数减1
        System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("来自客户端的消息:" + message);

        //群发消息
        for (IWebSocketCcliveController item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 发生错误时调用
     */
     @OnError
     public void onError(Session session, Throwable error) {
     System.out.println("发生错误");
     error.printStackTrace();
     }


     public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
     //this.session.getAsyncRemote().sendText(message);
     }


     /**
      * 根据itemId群发自定义消息
      * */
    public void sendInfo(String message,String itemId) throws IOException {
        for (IWebSocketCcliveController item : webSocketSet) {
            if(itemId.equals(item.getItemId())){
                try {
                    item.sendMessage(message);
                } catch (IOException e) {
                    continue;
                }
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        IWebSocketCcliveController.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        IWebSocketCcliveController.onlineCount--;
    }
}

前台:

长连接端:

<script type="application/javascript">
     var hrefItemId=111;    //携带的参数
     //地址一定是前台的https地址,不能是后台的http地址
     var websocket = new WebSocket("wss://lsy.xmt.cn//interface/websocket/cclive/"+hrefItemId);    
     //连接发生错误的回调方法
     websocket.onerror = function(event){
         alert(event.data);
         console.log(event.data);
     };

     //连接成功建立的回调方法
     websocket.onopen = function(event){
         alert(event.data);
         console.log(event.data);
     }

     //接收到消息的回调方法
     websocket.onmessage = function(event){
         alert(event.data);
         console.log(event.data);
     }

     //连接关闭的回调方法
     websocket.onclose = function(){
         alert("close");
     }

     //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
     window.onbeforeunload = function(){
         websocket.close();
     }
 </script>

nginx配置:

#前台页面--https设置
     server {
       listen 80;
       server_name lsy.xmt.cn;
       rewrite ^(.*) https://$server_name$1 permanent;
     }
     server {
       listen 443;
       server_name lsy.xmt.cn;
       ssl on;
       ssl_certificate   cert/ssl.crt;
       ssl_certificate_key  cert/ssl.key;
       ssl_session_timeout 5m;
       ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
       ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
       ssl_prefer_server_ciphers on;

       location ^~ /interface/websocket {
         #return 991;
         proxy_pass http://localhost:8080; #后台项目地址
          # WebScoket Support
         proxy_http_version 1.1;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection "upgrade";

         proxy_set_header Origin xxx;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header Host $http_host;
         proxy_set_header X-NginX-Proxy true;

         proxy_read_timeout 12000;  #websocket超时时间
        }


       location / {
          root /root/lsy/xmtweb;
          index index.html index.htm;
       }
     }

坑二:长连接会经常断开,解决办法有两种。方法一前台处理:检测到断开后重新连接。方法二后台nginx配置加proxy_read_timeout 12000;  增加websocket的超时时间

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值