一、导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
二、新建WebSocket配置类
@Component
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
三、新建WebSocket服务端,在其中处理websocket逻辑
@Component //注册到容器中
@ServerEndpoint("/webSocket") //接收websocket请求路径
@Slf4j
public class WebSocket {
//当前连接(每个websocket连入都会创建一个WebSocket实例)
private Session session;
//定义一个websocket容器存储session,即存放所有在线的socket连接
private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<>();
//处理连接建立
@OnOpen
public void opOpen(Session session){
this.session = session;
log.info("【有新的客户端连接了】:{}",session.getId());
webSocketSet.add(this); //将新用户加入在线组
log.info("【websocket消息】有新的连接,总数:{}",webSocketSet.size());
}
//处理连接关闭
@OnClose
public void Onclose(){
webSocketSet.remove(this);
log.info("【websocket消息】连接断开,总数:{}",webSocketSet.size());
}
//接受消息
@OnMessage
public void onMessage(String message){
log.info("【websocket消息】收到客户端发来的消息:{}",message);
}
// 群发消息
public void sendMessage(String message) {
for (WebSocket webSocket : webSocketSet) {
log.info("【websocket消息】广播群发消息,message={}",message);
try {
webSocket.session.getBasicRemote().sendText(message);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
jsch连接配置
一、引入依赖
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
二、配置工具类,并在工具类中拉入websocket进行消息发送
注意springContextHolder的作用是websocket的特殊属性导致Autowired用不了,直接Autowired会拉入一个null对象。
@Slf4j
public class JSchUtil {
private String ipAddress; //主机ip
private String username; // 账号
private String password; // 密码
private int port; // 端口号
Session session;
private static WebSocket webSocket = SpringContextHolder.getBean(WebSocket.class);
在JschUtil中的发送方法中使用websocket发送消息
/**
* 执行相关的命令(交互式) 并获取返回所有报文
*/
public void execute4(String command) throws IOException {
ChannelShell channel = null;
PrintWriter printWriter = null;
BufferedReader input = null;
Vector<String> stdout = new Vector<>();
try {
//建立交互式通道
channel = (ChannelShell) session.openChannel("shell");
channel.connect();
//获取输入
InputStreamReader inputStreamReader = new InputStreamReader(channel.getInputStream());
input = new BufferedReader(inputStreamReader);
//输出
printWriter = new PrintWriter(channel.getOutputStream());
printWriter.println(command);
printWriter.println("exit");
printWriter.flush();
// log.info("The remote command is: ");
System.out.println("The remote command is: ");
String line;
StringBuilder sb = new StringBuilder();
Integer times = 0;
Integer timeout=3600;
while ((line = input.readLine()) != null) {
if( times<timeout){
Thread.sleep(700);
times += 1;
webSocket.sendMessage(line);
}else{
webSocket.Onclose();
break;
}
}
System.out.println("连接结束了");
} catch (Exception e) {
log.error(e.getMessage(),e);
}finally {
printWriter.close();
input.close();
if (channel != null) {
//关闭通道
channel.disconnect();
}
}
}
前端建设
一、写websocket.js工具包
详细代码
/*
* @Date: 2023-03-01 11:52:00
* @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
* @FilePath: ./src/utils/websocket.js
*/
import { Message } from 'element-ui'
//import { getToken } from '@/utils/authToken' // 请求是否需要token
let websock = null
let messageCallback = null
let errorCallback = null
let wsUrl = ''
let tryTime = 0
// 接收ws后端返回的数据
export function websocketonmessage (e) {
// messageCallback(JSON.parse(e.data))
// console.log(messageCallback(JSON.parse(e.data)))
// console.log(e.data);
window.dispatchEvent(
new CustomEvent('onmessageWS', {
detail: {
data: e.data
}
})
);
return e.data;
}
/**
* 发起websocket连接
* @param {Object} agentData 需要向后台传递的参数数据
*/
function websocketSend (agentData) {
// 加延迟是为了尽量让ws连接状态变为OPEN
let timer = () => {
console.log(websock.readyState);
// 添加状态判断,当为OPEN时,发送消息
if (websock.readyState === websock.OPEN) { // websock.OPEN = 1
// 发给后端的数据需要字符串化
websock.send(JSON.stringify(agentData))
}
if (websock.readyState === websock.CLOSED) { // websock.CLOSED = 3
console.log('websock.readyState=3')
Message.error('ws连接异常,请稍候重试')
errorCallback()
}
}
setTimeout(() => {
timer()
}, 500)
}
// 关闭ws连接
function websocketclose (e) {
// e.code === 1000 表示正常关闭。 无论为何目的而创建, 该链接都已成功完成任务。
// e.code !== 1000 表示非正常关闭。
if (e && e.code !== 1000) {
// Message.error('ws连接异常,非正常关闭')
// errorCallback()
// // 如果需要设置异常重连则可替换为下面的代码,自行进行测试
// if (tryTime < 10) {
// setTimeout(function() {
// websock = null
// tryTime++
// initWebSocket()
// console.log(`第${tryTime}次重连`)
// }, 3 * 1000)
//} else {
// Message.error('重连失败!请稍后重试')
//}
}
}
// 建立ws连接
function websocketOpen (e) {
// console.log('ws连接成功')
}
// 初始化weosocket
function initWebSocket () {
if (typeof (WebSocket) === 'undefined') {
Message.error('您的浏览器不支持WebSocket,无法获取数据')
return false
}
const token = '';
// // ws请求完整地址
const requstWsUrl = wsUrl // + '?' + token
websock = new WebSocket(requstWsUrl)
// websock = new WebSocket();
websock.onmessage = function (e) {
websocketonmessage(e)
}
websock.onopen = function () {
websocketOpen()
}
websock.onerror = function () {
Message.error('ws连接异常,请稍候重试')
// errorCallback()
}
websock.onclose = function (e) {
websocketclose(e)
}
}
/**
* 发起websocket请求函数
* @param {string} url ws连接地址
* @param {Object} agentData 传给后台的参数
* @param {function} successCallback 接收到ws数据,对数据进行处理的回调函数
* @param {function} errCallback ws连接错误的回调函数
*/
export function sendWebsocket (url, agentData) {
let protocol = "ws://";
if (window.location.protocol === 'https:') {
protocol = "wss://";
}
wsUrl = protocol + "localhost:8090" + url;
initWebSocket()
websocketSend(agentData)
}
/**
* 关闭websocket函数
*/
export function closeWebsocket () {
if (websock) {
websock.close() // 关闭websocket
websock.onclose() // 关闭websocket
}
}
二、在main.js中注册websocket.js
三、在前端页面中调用websocket,我这个页面在查询方法getLogContent中调用
详细代码:
getLogContent() {
// 防止用户多次连续点击发起请求,所以要先关闭上次的ws请求。
this.$webSocket.closeWebsocket();
// 发起ws请求
// let url = 'ws://10.144.249.7:8099/monitor?logPath=/home/prep/logs/'+this.formatDate(Date.now(),'YMD')+'/PrepNormal.log';
// 跟后端协商,需要什么参数数据给后台
this.$message({
message: '查询中,请稍等',
type: 'success'
});
const params = {
threadName: this.threadName,
keyword: this.searchInput,
viewType: this.viewType
};
var textarea = '';
var statusLog = document.getElementById("log-container"); //log-container 即是页面需要展示内容的div
// let url = 'ws://localhost:8082/ws/getLogs/' // 本地调试
let url = '/ws/getLogs/' // 远程
console.log(url);
this.$webSocket.sendWebsocket(url, params);
let getSocketData = e => {
// console.log(e)
textarea = textarea + '\n' + e.detail.data
var ansi_up = new AnsiUp()
var html = ansi_up.ansi_to_html(textarea); //调用ansi_to_html()方法,txt就是从后端拿到的json数据
statusLog.innerHTML = html;
if (!this.mouseflag) {
this.scrollToBottom()
}
};
window.addEventListener('onmessageWS', getSocketData);
},
注意:AnsiUp在使用之前需要注册
(AnsiUp,经常和websocket结合使用)
1.安装
$ npm install ansi_up
2.引入
import {default as AnsiUp} from 'ansi_up';
3.使用
var ansi_up = new AnsiUp;
var html = ansi_up.ansi_to_html(txt); //调用ansi_to_html()方法,txt就是从后端拿到的json数据
var statusLog= document.getElementById("statusLog"); //statusLog 即是页面需要展示内容的div
statusLog.innerHTML = html;
参考:
websocket后端建设:https://www.cnblogs.com/xiaozhengtongxue/p/13448778.html
AnsiUp的使用步骤:
https://blog.youkuaiyun.com/weixin_50561602/article/details/116496609
JSch连接ssh参考:
https://blog.youkuaiyun.com/cxmfly11/article/details/129217663?spm=1001.2014.3001.5501