当前位置: 首页 > news >正文

jsch设置代理_Springboot2(20)轻松搞定WebSocket

实现后台向前端推送信息

pom.xml引入依赖

org.springframework.boot

spring-boot-starter-websocket

WebSocketConfig

启用WebSocket的支持也是很简单,几句代码搞定

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**

* 开启WebSocket支持

* @author zhengkai

*/

@Configuration

public class WebSocketConfig {

@Bean

public ServerEndpointExporter serverEndpointExporter() {

return new ServerEndpointExporter();

}

}

WebSocketServer

因为WebSocket是类似客户端服务端的形式(采用ws协议),那么这里的WebSocketServer其实就相当于一个ws协议的Controller

直接@ServerEndpoint("/websocket")@Component启用即可,然后在里面实现@OnOpen,@onClose,@onMessage等方法

/**

* @Author: ynz

* @Date: 2018/12/22/022 10:35

*/

@ServerEndpoint("/websocket/{sid}")

@Component

@Slf4j

public class WebSocketServer {

//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。

private static int onlineCount = 0;

//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。

private static CopyOnWriteArraySet webSocketSet =

new CopyOnWriteArraySet();

//与某个客户端的连接会话,需要通过它来给客户端发送数据

private Session session;

//接收sid

private String sid="";

/**

* 连接建立成功调用的方法*/

@OnOpen

public void onOpen(Session session,@PathParam("sid") String sid) {

this.session = session;

webSocketSet.add(this); //加入set中

addOnlineCount(); //在线数加1

http://log.info("有新窗口开始监听:"+sid+",当前在线人数为" + getOnlineCount());

this.sid=sid;

try {

sendMessage("连接成功");

} catch (IOException e) {

log.error("websocket IO异常");

}

}

/**

* 连接关闭调用的方法

*/

@OnClose

public void onClose() {

webSocketSet.remove(this); //从set中删除

subOnlineCount(); //在线数减1

http://log.info("有一连接关闭!当前在线人数为" + getOnlineCount());

}

/**

* 收到客户端消息后调用的方法

*

* @param message 客户端发送过来的消息*/

@OnMessage

public void onMessage(String message, Session session) {

http://log.info("收到来自窗口"+sid+"的信息:"+message);

//群发消息

for (WebSocketServer item : webSocketSet) {

try {

item.sendMessage(message);

} catch (IOException e) {

e.printStackTrace();

}

}

}

/**

*

* @param session

* @param error

*/

@OnError

public void onError(Session session, Throwable error) {

log.error("发生错误");

error.printStackTrace();

}

/**

* 实现服务器主动推送

*/

public void sendMessage(String message) throws IOException {

this.session.getBasicRemote().sendText(message);

}

/**

* 群发自定义消息

* */

public static void sendInfo(String message,@PathParam("sid") String sid)

throws IOException {

http://log.info("推送消息到窗口"+sid+",推送内容:"+message);

for (WebSocketServer item : webSocketSet) {

try {

//这里可以设定只推送给这个sid的,为null则全部推送

if(sid==null) {

item.sendMessage(message);

}else if(item.sid.equals(sid)){

item.sendMessage(message);

}

} catch (IOException e) {

continue;

}

}

}

public static synchronized int getOnlineCount() {

return onlineCount;

}

public static synchronized void addOnlineCount() {

WebSocketServer.onlineCount++;

}

public static synchronized void subOnlineCount() {

WebSocketServer.onlineCount--;

}

}

消息推送

至于推送新信息,可以再自己的Controller写个方法调用WebSocketServer.sendInfo();即可

@Controller

public class CheckCenterController {

//推送数据接口

@ResponseBody

@RequestMapping("/socket/push/{cid}")

public String pushToWeb(@PathVariable String cid,@RequestBody String message) {

try {

WebSocketServer.sendInfo(message,cid);

} catch (IOException e) {

e.printStackTrace();

}

return message;

}

}

页面发起socket请求

var socket = null;

function connect(){

if(typeof(WebSocket) == "undefined") {

console.log("您的浏览器不支持WebSocket");

}else{

console.log("您的浏览器支持WebSocket");

//实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接

socket = new WebSocket($("#url").val());

//打开事件

socket.onopen = function() {

console.log("Socket 已打开");

$("#status").html("已连接...");

//socket.send("这是来自客户端的消息" + location.href + new Date());

};

//获得消息事件

socket.onmessage = function(msg) {

console.log(msg.data);

$("#displayMsg").html( $("#displayMsg").html()+"
"+msg.data );

//发现消息进入 开始处理前端触发逻辑

};

//关闭事件

socket.onclose = function() {

console.log("Socket已关闭");

$("#status").html("未连接...");

socket = null;

};

//发生了错误事件

socket.onerror = function() {

alert("Socket发生了错误");

//此时可以尝试刷新页面

}

}

}

function send() {

if(socket == null){

alert("未连接");

return false;

}

socket.send($("#sendMsg").val());

}

function closeConnect(){

$("#status").html("已断开...");

socket.close();

}

连接地址:

连接

断开

未连接...

发送消息:

发送

接收到消息:

实现SSH WEB客户端

添加依赖

org.springframework.boot

spring-boot-starter-websocket

com.jcraft

jsch

0.1.54

WebSocketMessageBrokerConfigurer

配置消息代理,默认情况下使用内置的消息代理。 类上的注解@EnableWebSocketMessageBroker:此注解表示使用STOMP协议来传输基于消息代理的消息,此时可以在@Controller类中使用@MessageMapping

在方法registerStompEndpoints()里addEndpoint方法:添加STOMP协议的端点。这个HTTP URL是供WebSocket或SockJS客户端访问的地址;withSockJS:指定端点使用SockJS协议

在方法configureMessageBroker()里设置简单消息代理,并配置消息的发送的地址符合配置的前缀的消息才发送到这个broker

@Configuration

// 此注解表示使用STOMP协议来传输基于消息代理的消息,此时可以在@Controller类中使用@MessageMapping

@EnableWebSocketMessageBroker

public class SSHSocketConfig implements WebSocketMessageBrokerConfigurer {

/**

* setAllowedOrigins方法用来设置来自那些域名的请求可访问,默认为localhost

*/

@Override

public void registerStompEndpoints(StompEndpointRegistry registry) {

registry.addEndpoint("/websocket")

.setAllowedOrigins("*");

//SockJS客户端访问

/*registry.addEndpoint("/my-websocket").withSockJS();*/

}

/**

* 配置消息代理

* 启动Broker,消息的发送的地址符合配置的前缀来的消息才发送到这个broker

*/

public void configureMessageBroker(MessageBrokerRegistry registry) {

/**

* 配置消息代理

* 启动简单Broker,消息的发送的地址符合配置的前缀来的消息才发送到这个broker

*/

registry.enableSimpleBroker("/topic");

//只接收这前缀发送过来的消息

registry.setApplicationDestinationPrefixes("/send");//应用请求前缀

}

}

@Controller类 ,消息处理

@Controller

public class SSHController {

@Resource

private SimpMessagingTemplate messagingTemplate ;

static Map map = new HashMap<>();

/**

* 接收消息

*/

@MessageMapping("/receive/{id}")

// @SendTo("/topic/test")

public String receiver(@DestinationVariable("id") String id, String msg)

throws IOException {

SSHData sshData = map.get(id);

if(sshData != null){

OutputStream outputStream = map.get(id).getOutputStream();

outputStream.write((msg).getBytes());

outputStream.flush();

}else{

messagingTemplate.convertAndSend("/topic/"+id,"远程服务器未连接。。。\n\r");

}

return msg;

}

/**

* 建立SSH连接

*/

@RequestMapping("/connect")

@ResponseBody

public String connect(String user,String host,Integer port,String password,String id)

throws IOException {

SSHData sshData = map.get(id);

if(sshData != null){

sshData.release();

}

ChannelShell channelShell = SshUtils.getShellChannel( user, host, port , password, id);

if(channelShell == null){

messagingTemplate.convertAndSend("/topic/"+id,

"远程服务器连接失败,请检查用户或者密码是正确\n\r");

return "";

}

map.put(id,new SSHData(channelShell,messagingTemplate,id));

return "";

}

/**

* 断开连接

*/

@RequestMapping("/disconnect")

@ResponseBody

public String disConnect(String id) throws IOException {

SSHData sshData = map.get(id);

if(sshData != null){

sshData.release();

map.remove(id);

}

messagingTemplate.convertAndSend("/topic/"+id,"已断开连接。。。\n\r");

return "";

}

}

@MessageMapping:指定要接收消息的地址,类似@RequestMapping

@SendTo默认消息将被发送到与传入消息相同的目的地,但是目的地前面附加前缀(默认情况下为“/topic”}

@DestinationVariable接收URL的参数,类似@PathVariable

前端stomp、sockjs的配置

Stomp

websocket使用socket实现双工异步通信能力。但是如果直接使用websocket协议开发程序比较繁琐,我们可以使用它的子协议Stomp

SockJS

sockjs是websocket协议的实现,增加了对浏览器不支持websocket的时候的兼容支持 SockJS的支持的传输的协议有3类: WebSocket, HTTP Streaming, and HTTP Long Polling。默认使用websocket,如果浏览器不支持websocket,则使用后两种的方式。

SockJS使用”Get /info”从服务端获取基本信息。然后客户端会决定使用哪种传输方式。如果浏览器使用websocket,则使用websocket。如果不能,则使用Http Streaming,如果还不行,则最后使用 HTTP Long Polling。

IP:

Port:

用户名:

密码:

登录

断开

var stompClient ;

var term = new Terminal({

cols: 150,

rows: 35,

screenKeys: true,

useStyle: true,

cursorBlink: true

});

term.open(document.getElementById('terminal'));

term.on('data', function($data) {

//term.write($data);

stompClient.send("/send/receive/1",{}, $data );

});

document.οnkeydοwn=function(){

if (event.keyCode == 13){

term.write("\n\r");

}

}

$(document).ready(function() {

openSocket();

});

function openSocket() {

if(stompClient==null){

var socketPath ='ws://127.0.0.1:8080/websocket';

var socket = new WebSocket(socketPath);

stompClient = Stomp.over(socket);

var headers={

"Access-Control-Allow-Origin":"*",

"Access-Control-Allow-Credentials":"true",

"token":"kltoen"

};

stompClient.connect(headers, function(frame) {

$("#desc").html("WebSocket已连接");

stompClient.subscribe('/topic/1', function(event) {

term.write(event.body);

},headers);

},function (error) {

$("#desc").html("WebSocket连接失败");

});

window.setInterval(function(){ //每隔5秒钟发送一次心跳,避免websocket连接超时而自动断开

stompClient.send(" ");

},30000);

}

}

function connect() {

$.ajax({

type: "GET",

"&host="+$("#ip").val()+ "&port="+$("#port").val()+

"&password="+$("#password").val()+"&id=1"

});

}

function disconnect() {

$.ajax({

type: "GET",

});

}

测试

相关文章:

  • adb 输入回车命令_adb 常用命令
  • matlab向量与x正方向的夹角_高中数学:向量在几何中的应用
  • 怎么判断几行_孩子没有天赋怎么办?小陶虹的回答我点100个赞
  • 执行时间单位_排污许可申报之后环境管理台账及执行报告,你准备好了吗?
  • 人体一机竞技格斗机器人_2019中国智能机器人大赛在青岛举行
  • cad lisp 界址点号_CAD图纸多到打不完?没关系学会批量打印来多少都不怕
  • mysql 动态传入表名 存储过程_MySQL存储过程了解
  • zbbz 坐标标注lisp_CAD中还能这样快速标注尺寸?怪不得同事天天准时下班
  • zoom怎么解除静音_进入Zoom视频会议时为什么没有声音
  • rm删除级联目录的参数是_Linux:绝对路径和相对路径,cd 命令,rm 命令,history 命令详解...
  • 列表输出循环左移_python工厂第20层 多重列表2
  • 清空指令_python应用:linux常用指令
  • animation unity 速度_[Unity+shader]无限循环背景的制作
  • gmt时间转换格式 js_《Vue系列》timeago.js将时间戳转换成“几天前”“几分钟前”等格式...
  • 接收对象数组_分享一些数组对象常用的API
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • android百种动画侧滑库、步骤视图、TextView效果、社交、搜房、K线图等源码
  • hadoop入门学习教程--DKHadoop完整安装步骤
  • JavaScript 基础知识 - 入门篇(一)
  • Java编程基础24——递归练习
  • Java程序员幽默爆笑锦集
  • Java新版本的开发已正式进入轨道,版本号18.3
  • Laravel 菜鸟晋级之路
  • LeetCode刷题——29. Divide Two Integers(Part 1靠自己)
  • Nacos系列:Nacos的Java SDK使用
  • Spark RDD学习: aggregate函数
  • vue脚手架vue-cli
  • 回流、重绘及其优化
  • 记录:CentOS7.2配置LNMP环境记录
  • 做一名精致的JavaScripter 01:JavaScript简介
  • 我们雇佣了一只大猴子...
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目
  • #前后端分离# 头条发布系统
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (1)常见O(n^2)排序算法解析
  • (51单片机)第五章-A/D和D/A工作原理-A/D
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (附源码)计算机毕业设计高校学生选课系统
  • (九)信息融合方式简介
  • (十一)图像的罗伯特梯度锐化
  • (四)c52学习之旅-流水LED灯
  • (未解决)macOS matplotlib 中文是方框
  • (详细版)Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models
  • (一)认识微服务
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (译) 函数式 JS #1:简介
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (转)大型网站架构演变和知识体系
  • (转)关于多人操作数据的处理策略
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • .net core 6 集成和使用 mongodb
  • .net mvc部分视图
  • .NET/C# 项目如何优雅地设置条件编译符号?