java后端和VUE2前端使用websocket实现与客户端之间接收及发送消息

客户端请求websocket接口,连接通道=》我这边业务成功客户端发消息=》客户端自动刷新。

接口:ws://localhost:8080/websocket/xx




import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * @author Administrator
 */
@Configuration
public class WebSocketConfig implements WebSocketConfigurer {

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

package com.xx.framework.web.service;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
@Component
@Slf4j
@ServerEndpoint("/websocket/{key}")
public class WebSocketService {
    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    private static CopyOnWriteArraySet<WebSocketService> webSockets = new CopyOnWriteArraySet<>();
    private static WebSocketService webSocketService;
    @PostConstruct
    public void init(){
        webSocketService = this;
    }

    /**
     * 连接成功后调用的方法
     * @param session
     * @param key
     */
    @OnOpen
    public void onOpen(Session session,@PathParam("key") String key){
        //key作为前端传给后端的参数值
        this.session = session;
        webSockets.add(this);
        log.info("websocket连接成功");
        log.info("websocket有新的连接,连接总数为"+webSockets.size());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(){
        this.session = null;
        webSockets.remove(this);
        log.info("websocket连接关闭");
    }

    /**
     * 收到客户端消息后调用的方法,根据业务要求进行处理,这里就简单地将收到的消息直接群发推送出去
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(Session session,String message){
        if (StrUtil.isNotBlank(message)){
            if(message.equals("heartbeat")){
                sendTextMessage(session,"已连接");
            }
        }
        log.info("WebSocket收到客户端消息:"+message);
    }

    /**
     * 实现服务器主动推送消息
     * @param session = sessionPool.get(key);
     * @param message
     */
    private void sendTextMessage(Session session, String message) {
        if (session != null){
            try {
                session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public void sendAllMessage(String message){
        log.info("websocket消息全部人员消息:"+message);
        for (WebSocketService apiWebSocketService:webSockets){
            try{
                if (apiWebSocketService.session.isOpen()){
                    apiWebSocketService.session.getAsyncRemote().sendText(message);
                }
            }catch (Exception e){
                e.printStackTrace();
                log.error("全部人员发送消息失败:",e.getMessage());
            }
        }
    }
    /**
     * 发生错误时的回调函数
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session,Throwable error){
        log.error("发生错误");
        error.printStackTrace();
    }

}

经测试,成功

如果是线上服务器连接,则需要在nginx里配置websocket相关内容,再重启nginx,代码如下


server {
        listen       443 ssl;
        server_name  api.kadecard.com;
        ssl_certificate      cert.pem;
        ssl_certificate_key  cert.key; 
         ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;
 
       # ssl_ciphers  HIGH:!aNULL:!MD5;
       # ssl_prefer_server_ciphers  on;
    
        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 / {
           proxy_pass http://xx:7878/;
     
        }    
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    
    #websocket 这里的websocket是后端websocket接口的接口名称 
      location /websocket {
            rewrite ^/ws$ / break;
            rewrite ^/ws(.*)$ $1 break;
            proxy_pass http://127.0.0.1:7878;
            proxy_http_version 1.1;    #websoket必须要使用的协议,http 1.1
            proxy_set_header Upgrade $http_upgrade;  #要使用websocket协议时,响应http升级请求
            proxy_set_header Connection "upgrade";
            proxy_set_header X-real-ip $remote_addr;
             proxy_set_header X-Forwarded-For $remote_addr;
        proxy_read_timeout 600s;
      }
    }

本地连接的时候用的是ws://,因为是http链接,但是如果是服务器连接,且支持https连接方式,则就需要用wss://的连接方式。

如果是在 宝塔配置,则如下:

location /websocket {
      ##后台服务器地址加上websocket的接口名称
      proxy_pass http://localhost:8084/websocket/; #这里是http不是ws,不用怀疑,代理的ip和port写ws访问的实际地址
      proxy_http_version 1.1; #这里必须使用http 1.1
      #下面两个必须设置,请求头设置为ws请求方式
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
}

还要检查接口权限是否开放:

类型:SecurityConfig
 
.antMatchers("/login", "/register", "/captchaImage","/rinter/**","/websocket/**").permitAll()

前端vue:

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
	<el-input type="text" v-model="msgNew" label="新值"></el-input>
	<el-button type="primary" @click="change()">改变值</el-button>
  </div>
</template>
 
<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data () {
          return {
              path:"ws://127.0.0.1:8088/websocket/"+this.algorithm(),
              socket:"",
			  msgNew:'',
          }
      },
      mounted () {
          // 初始化
          this.init()
      },
      methods: {
		  algorithm:function(){
		  	let abc=['a','b','c','d','e','f','g','h','i','g','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
		  	let [max,min]=[Math.floor(Math.random()*(10-7+1)+1),Math.floor(Math.random()*(17-10+1)+17)];
		  	abc=abc.sort(()=>0.4-Math.random()).slice(max,min).slice(0,8).join("");
		  	var a=new Date().getTime()+abc;
		  	return a
		  },
		  change(){
			  this.msg=this.msgNew;
			  this.socket.send(this.msgNew);
		  },
          init: function () {
              if(typeof(WebSocket) === "undefined"){
                  alert("您的浏览器不支持socket")
              }else{
                  // 实例化socket
                  this.socket = new WebSocket(this.path)
                  // 监听socket连接
                  this.socket.onopen = this.open
                  // 监听socket错误信息
                  this.socket.onerror = this.error
                  // 监听socket消息
                  this.socket.onmessage = this.getMessage
              }
          },
          open: function () {
              console.log("socket连接成功")
			  this.socket.send("heartbeat");
          },
          error: function () {
              console.log("连接错误")
			   this.init()
          },
          getMessage: function (msg) {
              console.log("数据接收:"+msg.data)
			  this.msg=msg.data
          },
          // 发送消息给被连接的服务端
          send: function (params) {
			  console.log("发送消息给服务端")
              this.socket.send(params)
          },
          close: function () {
              console.log("socket已经关闭")
          }
      },
      destroyed () {
          // 销毁监听
          this.socket.onclose = this.close
      }
}
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>
main.js文件配置:
 
import global from '@/utils/wsGlobal.js'
Vue.prototype.$global=global;
 
初始化的时候设置:
this.socket = new WebSocket(this.path+this.token)
this.$global.setWs(this.socket)
 
其他页面引用:
例如消息获取:
mounted() {
      
      this.$global.ws.onmessage=this.websocketonmessage
},
 methods: {
     websocketonmessage(e){
       console.log("数据接收"+e.data);
    }
}

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞流银河

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值