赞
踩
npm i ws -S
在app.js中添加如下代码:
//4、websocket的使用 //引入websocket const WebSocket=require('ws') //4-1、创建对象,绑定端口 const wss=new WebSocket.Server({ port:9998 }); //4-2、监听连接事件 wss.on('connection',(client)=>{ console.log("客户端连接成功。。。"); //4-3、监听接收消息事件 client.on('message',(msg)=>{ console.log("接收到来着客户端的信息:"+msg); //模拟客户端往服务端发送数据 client.send("hello websocket!i am app.js") }) })
ws.onopen
、接收数据事件ws.onmessage
、关闭连接事件ws.onclose
)ws.send
测试 一下,新建文件demo.html放在app.js同一级,代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button id="connId">连接</button> <button id="sendId" disabled="true">发送</button></br> 接收到的信息:<span id="msgId"></span> </body> <script> var conn=document.getElementById('connId') var send=document.getElementById('sendId') var msgId=document.getElementById('msgId') var ws=null conn.onclick=function(){ ws=new WebSocket("ws://localhost:9998") ws.onopen=()=>{ console.log("连接成功"); send.disabled=false//修改发送按钮可用状态 } ws.onmessage=(msg)=>{ console.log(msg); msgId.innerHTML=msg.data } ws.onclose=()=>{ console.log("关闭连接"); send.disabled=true } } send.onclick=function(){ console.log("开始发送"); ws.send("hello i am demo.html") } </script> </html>
将app.js里面关于websocket的代码提出到websocket_utils.js并导出
//4、websocket的使用 //引入websocket const WebSocket=require('ws') //4-1、创建对象,绑定端口 const wss=new WebSocket.Server({ port:9998 }); //服务端开启了监听 //4-2、监听连接事件 module.exports.listen=()=>{ wss.on('connection',(client)=>{ console.log("客户端连接成功。。。"); //4-3、监听接收消息事件 client.on('message',(msg)=>{ console.log("接收到来着客户端的信息:"+msg); //模拟客户端往服务端发送数据 client.send("hello websocket!i am app.js") }) }) }
在app.js里将websocket_utils.js导入并监听
//4、websocket的使用
//引入websocket_utils.js
const webSocketService=require('./utils/websocket_utils')
//开启服务端的监听
webSocketService.listen()
<!--websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
package com.furenqiang.system.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; /** * 开启WebSocket支持 * @author EricFRQ */ @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
package com.furenqiang.system.utils; import java.util.concurrent.atomic.AtomicInteger; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * 前后端交互的类实现消息的接收推送(自己发送给自己) * * @ServerEndpoint(value = "/test/one") 前端通过此URI和后端交互,建立连接 */ @ServerEndpoint(value = "/test/one") @Component public class WebSocketUtil { /** 记录当前在线连接数 */ private static AtomicInteger onlineCount = new AtomicInteger(0); private static final Logger logger=LoggerFactory.getLogger(WebSocketUtil.class); /** * 连接建立成功调用的方法 */ @OnOpen public void onOpen(Session session) { onlineCount.incrementAndGet(); // 在线数加1 logger.info("有新连接加入:{},当前在线人数为:{}", session.getId(), onlineCount.get()); } /** * 连接关闭调用的方法 */ @OnClose public void onClose(Session session) { onlineCount.decrementAndGet(); // 在线数减1 logger.info("有一连接关闭:{},当前在线人数为:{}", session.getId(), onlineCount.get()); } /** * 收到客户端消息后调用的方法 * * @param message * 客户端发送过来的消息 */ @OnMessage public void onMessage(String message, Session session) { logger.info("服务端收到客户端[{}]的消息:{}", session.getId(), message); this.sendMessage("Hello, " + message, session); } @OnError public void onError(Session session, Throwable error) { logger.error("发生错误"); error.printStackTrace(); } /** * 服务端发送消息给客户端 */ private void sendMessage(String message, Session toSession) { try { logger.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message); toSession.getBasicRemote().sendText(message); } catch (Exception e) { logger.error("服务端发送消息给客户端失败:{}", e); } } }
resources下新建static文件夹,static下新建index.html
<!DOCTYPE HTML> <html> <head> <title>My WebSocket</title> </head> <body> <input id="text" type="text" /> <button onclick="send()">Send</button> <button onclick="closeWebSocket()">Close</button> <div id="message"></div> </body> <script type="text/javascript"> var websocket = null; //判断当前浏览器是否支持WebSocket, 主要此处要更换为自己的地址 if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost:10012/test/one"); } else { alert('Not support websocket') } //连接发生错误的回调方法 websocket.onerror = function() { setMessageInnerHTML("error"); }; //连接成功建立的回调方法 websocket.onopen = function(event) { //setMessageInnerHTML("open"); } //接收到消息的回调方法 websocket.onmessage = function(event) { setMessageInnerHTML(event.data); } //连接关闭的回调方法 websocket.onclose = function() { setMessageInnerHTML("close"); } //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function() { websocket.close(); } //将消息显示在网页上 function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML += innerHTML + '<br/>'; } //关闭连接 function closeWebSocket() { websocket.close(); } //发送消息 function send() { var message = document.getElementById('text').value; websocket.send(message); } </script> </html>
访问地址http://localhost:10012/index.html
浏览器输入内容 点击发送send按钮
服务端
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * 前后端交互的类实现消息的接收推送(自己发送给自己) * * @ServerEndpoint(value = "/test/one") 前端通过此URI和后端交互,建立连接 */ @ServerEndpoint(value = "/websocket/one") @Component public class WebSocketUtil { /** 记录当前在线连接数 */ private static AtomicInteger onlineCount = new AtomicInteger(0); private static final Logger logger = LoggerFactory.getLogger(WebSocketUtil.class); /** 存放所有在线的客户端 */ private static Map<String, Session> clients = new ConcurrentHashMap<>(); /** * 连接建立成功调用的方法 */ @OnOpen public void onOpen(Session session) { onlineCount.incrementAndGet(); // 在线数加1 clients.put(session.getId(), session); logger.info("有新连接加入:{},当前在线人数为:{}", session.getId(), onlineCount.get()); } /** * 连接关闭调用的方法 */ @OnClose public void onClose(Session session) { onlineCount.decrementAndGet(); // 在线数减1 clients.remove(session.getId()); logger.info("有一连接关闭:{},当前在线人数为:{}", session.getId(), onlineCount.get()); } /** * 收到客户端消息后调用的方法 * * @param message 客户端发送过来的消息 */ @OnMessage public void onMessage(String message, Session session) { logger.info("服务端收到客户端[{}]的消息:{}", session.getId(), message); this.sendMessage(message, session); } @OnError public void onError(Session session, Throwable error) { logger.error("发生错误"); error.printStackTrace(); } /** * 服务端发送消息给客户端 */ public void sendMessage(String message, Session fromSession) { if (fromSession == null) { for (Map.Entry<String, Session> sessionEntry : clients.entrySet()) { fromSession = sessionEntry.getValue(); logger.info("服务端给客户端[{}]发送消息{}", fromSession.getId(), message); fromSession.getAsyncRemote().sendText(message); } } else { for (Map.Entry<String, Session> sessionEntry : clients.entrySet()) { Session toSession = sessionEntry.getValue(); // 排除掉自己 if (!fromSession.getId().equals(toSession.getId())) { logger.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message); toSession.getAsyncRemote().sendText(message); } } } } }
WebSocketUtil webSocketUtil = new WebSocketUtil();
//websocket推送给前端
webSocketUtil.sendMessage(jobInfo.toString(), null);
导出一个类WebSocketService,实现如下几步:
export default class WebSocketService{ /* * 单例模式 */ static instance=null static get Instance(){ if(!this.instance){ this.instance= new WebSocketService() } return this.instance } ws=null //连接服务器的方法 connect(){ if(!window.WebSocket){ return "您的浏览器不支持websocket" } this.ws=new WebSocket("ws://localhost:9998") this.ws.onopen=()=>{ console.log("连接成功"); } this.ws.onclose=()=>{ console.log("关闭连接"); } this.ws.onmessage=(msg)=>{ console.log(msg); } } }
在main.js里引入并调用
import WebSocketService from './utils/websocket_utils'
//websocket的连接并监听
WebSocketService.Instance.connect()
//websocket注册全局组件,可在其他页面使用this.$socket来获取到WebSocketService对象
Vue.prototype.$socket = WebSocketService.Instance
此时启动项目后,就可自动连接
资源包:node写的websocket引擎使用http协议连接的
1、下载依赖:npm install vue-socket.io@3.0.7 --s
2、使用:main.js里面引入
import VueSocketIO from "vue-socket.io";
Vue.use(
new VueSocketIO({
debug: true,
connection: "http://localhost:8040?userid=" + sessionStorage.getItem("inieToken"),
}))
3、使用页面中使用相应方法
<!-- 消息中心滚动消息 --> <template> <div class="msgDivClass"> <span class="msgSpanClass">{{ text }}</span> </div> </template> <script> export default { data() { return { timerId: null, msg: "滚动1234567890开始1234567890过程1234567890结束1234567890", text: "", socket: null, }; }, components: {}, computed: {}, mounted() { this.connSocket(); this.autoRoll(); }, created() {}, methods: { connSocket() { this.sockets.subscribe("notification", (data) => {//notification为服务端发送的方法名 data = JSON.parse(data); this.msg = data.content + ":" + data.description + "。"; this.autoRoll(); }); }, autoRoll() { let that = this; that.text = that.msg; this.timerId = setInterval(() => { that.text = that.text.substring(1, that.text.length) + that.text.substring(0, 1); }, 500); }, }, destroyed() { clearInterval(this.timerId); this.timerId = null; }, }; </script> <style scoped> .msgDivClass { width: 22%; height: 5%; border: 1px solid #809ca3; position: absolute; top: 3%; left: 0.5%; } .msgSpanClass { white-space: nowrap; /*强制span不换行*/ display: inline-block; /*将span当做块级元素对待*/ width: 100%; /*限制宽度*/ overflow: hidden; /*超出宽度部分隐藏*/ text-overflow: ellipsis; /*超出部分以点号代替*/ margin-top: 9%; font-size: 25px; color: #ffffff; } </style>
4、服务端代码如下:
var fs = require('fs'); var url = require("url"); var nicknames = {}; var app = require('http').createServer(function (request, response) { var pathname = url.parse(request.url).pathname; var responseJSON = { statusCode: 200, message: "", data: null }; response.writeHead(200, {"Content-Type": "text/plain; charset=utf-8"}); if (pathname == "/sendMsg") //处理post方式请求 { request.addListener("data", function (postdata) { var msgInfo = decodeURIComponent(postdata); var msgJSON = JSON.parse(msgInfo); var arruser = msgJSON.receiveId.split(","); var users = ""; for (var item in nicknames) { for (var i=0;i<arruser.length;i++) { var userId = item.toString().split("_")[0]; if (userId == arruser[i]) { msgJSON.receiveId = userId; nicknames[item].emit('notification', JSON.stringify(msgJSON)); users += userId+","; } } } responseJSON.data = users; }); request.addListener("end", function () { response.write(JSON.stringify(responseJSON)); response.end(); }); } else if (pathname == "/getuserbyid") { var item = url.parse(request.url).query; if (nicknames[item]) { responseJSON.data = { userid: item, referer: nicknames[item].handshake.headers.referer, address: nicknames[item].handshake.address }; } else { responseJSON.statusCode = 500; responseJSON.message = "用户不存在或未登录"; } response.write(JSON.stringify(responseJSON)); response.end(); } else if (pathname == "/getuserlist") { var userlist = []; for (var item in nicknames) { userlist.push({ userid: item, referer: nicknames[item].handshake.headers.referer, address: nicknames[item].handshake.address }); } response.writeHead(200, {"Content-Type": "text/plain"}); response.write(JSON.stringify(userlist)); response.end(); } else { response.writeHead(200, {"Content-Type": "text/plain"}); //消息发送状态 0:成功 1:失败 response.write("200"); response.end(); } }); var io = require('socket.io').listen(app); app.listen(8040); io.sockets.on('connection', function (socket) { var query = socket.handshake.query; if (query.userid) { if (!nicknames[query.userid + "_" + query.t]) { nicknames[query.userid + "_" + query.t] = socket; console.log("登录:" + query.userid + "_" + query.t); console.log(socket.handshake.address); console.log(socket.handshake.headers.referer); } } //监听用户退出 socket.on('disconnect', function () { //将退出的用户从在线列表中删除 if (nicknames.hasOwnProperty(query.userid + "_" + query.t)) { //删除 delete nicknames[query.userid + "_" + query.t]; console.log("退出:" + query.userid + "_" + query.t); } }); });
/* eslint-disable no-mixed-spaces-and-tabs */ /*------------------------- web socket方法封装 -------------------------*/ /*连接websocket*/ var ws; var port = '0'; //前一次端口号,断线重连时用到 var seq=0;//第几次请求握手 export const websocketFun = (parmas) => { var WebSocketsExist = true; try { ws = new WebSocket("ws://" + parmas.websocketip + ":" + parmas.websocketport); } catch (ex) { try { ws = new WebSocket("ws://" + this.$store.state.websocketip + ":" + this.$store.state.websocketport); } catch (ex) { WebSocketsExist = false; } } if (!WebSocketsExist) { return; } ws.onopen = WSonOpen; //ws.onmessage = WSonMessage; ws.onclose = WSonClose; ws.onerror = WSonError; return ws; } function WSonOpen() { var json={}; json.userid=sessionStorage.getItem("userId"); json.username=sessionStorage.getItem("username"); json.FSNo="01"; json.svrtype="8"; json.msgType="msg_HandShake"; json.port=port; json.reportflag="1"; json.format="0"; json.seq=seq; seq++; let str = JSON.stringify(json); let length=str.length; let len=length.toString(16); len=len.padStart(4, "0"); str=len+str; ws.send(str); } function WSonClose() { } function WSonError() { }
<template> <div class="meterSwitch"> <div class="header"> <div class="search"> <el-form size="mini" :inline="true" :model="search" class="demo-form-inline"> <el-form-item label="户号"> <el-input v-model="search.customerNum"></el-input> </el-form-item> <el-form-item label="户名"> <el-input v-model="search.customerName"></el-input> </el-form-item> <el-form-item label="电表地址"> <el-input v-model="search.meterAddress"></el-input> </el-form-item> <el-form-item> <el-button icon="el-icon-search" size="mini" type="primary" @click="getMeterSwitchList">查询</el-button> </el-form-item> </el-form> </div> <div class="Newly"> <el-button icon="el-icon-connection" size="mini" type="primary" @click="readingSelect">透抄</el-button> </div> </div> <div class="content"> <el-table :data="tableData" border style="width: 100%" height="100%" ref="multipleTable" tooltip-effect="dark" @selection-change="handleSelectionChange" > <el-table-column align="center" type="selection" width="55"></el-table-column> <el-table-column align="center" :show-overflow-tooltip="true" width="150" label="电表ID" prop="fileId" v-if="false" ></el-table-column> <el-table-column align="center" :show-overflow-tooltip="true" width="150" label="集中器ID" prop="upGoingId" v-if="false" ></el-table-column> <!-- <el-table-column type="index" width="50" prop="index"></el-table-column> --> <el-table-column align="center" :show-overflow-tooltip="true" width="120" label="户名" prop="customerName" ></el-table-column> <el-table-column align="center" :show-overflow-tooltip="true" width="120" label="户号" prop="customerNum" ></el-table-column> <el-table-column align="center" :show-overflow-tooltip="true" width="150" label="电表地址" prop="meterAddress" ></el-table-column> <el-table-column align="center" :show-overflow-tooltip="true" label="安装地址" prop="installAddress" ></el-table-column> <el-table-column align="center" :show-overflow-tooltip="true" width="150" prop="readingStatus" label="透抄结果" > <template slot-scope="scope"> <span v-if="scope.row.readingStatus==1" style="color: green">成功</span> <span v-else-if="scope.row.readingStatus==0" style="color: red">失败</span> <span v-else style="color: black">未透抄</span> </template> </el-table-column> <el-table-column align="center" :show-overflow-tooltip="true" width="150" label="数据内容" prop="readingData" ></el-table-column> </el-table> </div> <!-- 分页 --> <div class="block"> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="search.page" :page-sizes="pages" :page-size="search.size" layout="total,sizes, prev, pager, next, jumper" :total="params.total" ></el-pagination> </div> </div> </template> <script> import { websocketFun } from "@/request/websocketApi"; import { getMeterSwitchList, openSwitch } from "@/request/meterapi"; export default { data() { return { ws: "", search: { page: 1, size: 10, meterAddress: "", customerName: "", customerNum: "", organizationid: "", gid: "", type:'', }, // 分页 pages: [10, 20, 40], tableData: [], exchangeTableData: [], params: { total: 0 }, dealRows: [], multipleSelection: [] }; }, computed:{ tree(){ return this.$store.state.tree } }, watch: { tree:{ deep:true,//代表深层次的监听 immediate:true,//页面初始化的时候就立即触发一次 handler(val){ // console.log('vuex树',val) if(val.type===3){ this.search.meterAddress = val.name }else { this.search.meterAddress = '' } if(val.type===2){ this.search.customerName = val.name this.search.gid = val.gid this.search.type = val.type }else { this.search.customerName = '' } if(val.type===1){ this.search.gid = val.gid this.search.type = val.type } // console.log('this.search---',this.search) this.page = 1 this.getMeterSwitchList(); } } }, methods: { getMeterSwitchList() { getMeterSwitchList(this.search).then(res => { this.tableData = res.data.data; this.params.total = res.data.total; }); if (this.ws == "") { this.ws = websocketFun(this.$store.state); this.ws.onmessage = this.WSonMessage; } }, WSonMessage(event) { if (!event) { return; } let str = event.data; //要截取的字符串 let index = str.indexOf("{"); let result = str.substr(index, str.length); let events = eval("(" + result + ")"); if (events.result == "nak") { this.$message({ message: "与前置机连接被拒绝!", type: "error", duration: 3000 }); } else if (events.result == "ack") { console.log("与前置机连接成功!"); } else { console.log(events); if (events.errorCode == "ok") { this.$message({ message: "操作成功!", type: "success", duration: 3000 }); //同时修改数据库里电表下达状态,关于电表的数据在events.objJson里, //还需解析,然后根据电表地址 判断index,将数据写入到对应的列 // this.tableData[this.dealRow].readingStatus=1; // this.tableData[this.dealRow].readingData=events.objJson; } else if (events.errorCode == "notOnline") { this.$message({ message: "操作失败,集中器不在线!", type: "error", duration: 3000 }); //同时修改数据库里电表下达状态,关于电表的数据在events.objJson里, //还需解析,然后根据电表地址 判断index,将数据写入到对应的行 //events.objJson.forEach((val) => { this.multipleSelection.forEach(val => { this.tableData.forEach((v, i) => { if (val.fileId == v.fileId) { this.dealRows.push(i); } }); }); this.$refs.multipleTable.clearSelection(); for (let dealRow of this.dealRows) { this.tableData[dealRow].readingStatus = 0; this.tableData[dealRow].readingData = events.objJson; } this.dealRows = []; } else if (events.errorCode == "failed") { this.$message({ message: "操作失败!", type: "error", duration: 3000 }); } else { this.$message({ message: events, type: "error", duration: 3000 }); } } }, handleCurrentChange(val) { this.search.page = val; this.getMeterSwitchList(); }, handleSizeChange(val) { this.search.size = val; this.search.page = 1; this.getMeterSwitchList(); }, readingSelect() { if (this.multipleSelection.length == 0) { this.$message({ message: "请勾选后操作!", type: "warning", duration: 2000 }); } if (this.ws.readyState == 1) { for (let select of this.multipleSelection) { let electricmeter = {}; electricmeter.fileId = select.fileId; electricmeter.upGoingId = select.upGoingId; openSwitch(electricmeter).then(res => { let openSwitchStr = res.data.data; this.ws.send(openSwitchStr); console.log("已发送"); }); } } else { this.$message({ message: "未连接前置机!", type: "warning", duration: 2000 }); } console.log(this.multipleSelection); }, handleSelectionChange(val) { this.multipleSelection = val; } }, created() { this.getMeterSwitchList(); } }; </script> <style lang="scss"> .meterSwitch { height: 100%; .header { vertical-align: middle; .search { // display: inline-block; vertical-align: top; } .Newly { display: block; } } .content { height: calc(100% - 120px); margin-top: 10px; .el-form-item { width: 33% !important; } .demo-table-expand { font-size: 0; } .el-form-item__label { // width: 90px; color: #99a9bf !important; } .demo-table-expand .el-form-item { margin-right: 0; margin-bottom: 0; width: 50%; } } } </style>
1、安装vuex
import vuex from 'vuex'
2、在main.js里把vuex注册到vue全局组件里
import Vue from 'vue' import App from './App.vue' import router from './router' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' import store from './store/index.js' import Vuex from 'vuex' Vue.use(ElementUI) Vue.use(Vuex)//使用vuex Vue.config.productionTip = false import './assets/font/iconfont.css' // 引入echarts import echarts from 'echarts' Vue.prototype.$echarts = echarts // 引入reset.css import './assets/css/reset.css' import './assets/css/base.css' state: { websocketip:"193.168.1.100", websocketport:"20020", }, var store = new vuex.Store({//创建vuex中的store对象 state }) new Vue({ router, store, render: h => h(App) }).$mount('#app')
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。