
后台Java代码
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import io.netty.channel.Channel;
import java.util.Map;
/**
* WebSocket接收到消息触发工具类
*/
public class WebSockedMsgUtils {
public static Gson son = new Gson();
public static void processMsg(Channel channel, String str){
//Tools.checkHasNullParam 是自己写的非空判断
if(Tools.checkHasNullParam(channel,str)){
WebBaseMsg base = son.fromJson(str, WebBaseMsg.class);
if(base != null){
//SSH 初始化连接
if("ssh-connection".equals(base.getType())) {
Map<String, Object> param = Tools.getGson().fromJson(base.getMsgText(), new TypeToken<Map<String, Object>>(){}.getType());
try {
new SSHThread(channel.hashCode() + "", param.get("host") + "", ((Long) param.get("port")).intValue(), param.get("username") + "", param.get("password") + "").start();
} catch (Exception e) {
e.printStackTrace();
}
}
//执行命令
else if("ssh-send-command".equals(base.getType())) {
SSHUtil.execCmd(channel.hashCode() + "", base.getMsgText());
}
//SSH 断开连接
else if("ssh-disconnection".equals(base.getType())) {
if(SSHUtil.sshMap.containsKey(channel.hashCode() + "")) {
SSHUtil.sshMap.get(channel.hashCode() + "").disconnect();
SSHUtil.sshMap.remove(channel.hashCode() + "");
}
}
}
}
}
}
//------------------------------------------------------------------------------------------
//给出部分的导入包路径
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Properties;
/**
* SSH工具类
* @since 1.0.0
*/
public class SSHThread extends Thread {
private String channelKey;
private String host;
private int port;
private String username;
private String password;
public SSHThread(String channelKey, String host, int port, String username, String password) {
this.channelKey = channelKey;
this.host = host;
this.port = port;
this.username = username;
this.password = password;
}
@Override
public void run() {
try {
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
//获取jsch的会话
JSch jSch = new JSch();
Session session = jSch.getSession(username, host, port);
session.setConfig(config);
//设置密码
session.setPassword(password);
//连接 超时时间30s
session.connect(10000);
//开启shell通道
Channel channel = session.openChannel("shell");
//通道连接 超时时间3s
channel.connect(3000);
//设置channel
SSHUtil.sshMap.put(channelKey, channel);
//读取终端返回的信息流
InputStream inputStream = channel.getInputStream();
try {
WebBaseMsg msg = new WebBaseMsg();
msg.setType("ssh-receive");
//发送已建立连接
msg.setMsgText("Connection established.\r\n");
ChannelMap.sendChannel(channelKey, Tools.gson.toJson(msg));
//循环读取
byte[] buffer = new byte[1024];
int i = 0;
//如果没有数据来,线程会一直阻塞在这个地方等待数据。
while ((i = inputStream.read(buffer)) != -1) {
msg.setMsgText(new String(Arrays.copyOfRange(buffer, 0, i)));
ChannelMap.sendChannel(channelKey, Tools.gson.toJson(msg));
}
} finally {
Log.info("断开 " + host + ":" + port + " SSH连接");
//断开连接后关闭会话
session.disconnect();
channel.disconnect();
if (inputStream != null) {
inputStream.close();
}
}
} catch (Exception e) {
e.printStackTrace();
WebBaseMsg msg = new WebBaseMsg();
msg.setType("equip-ssh-receive");
msg.setMsgText(e.toString());
ChannelMap.sendChannel(channelKey, Tools.gson.toJson(msg));
}
}
}
//------------------------------------------------------------------------------------------
import com.jcraft.jsch.Channel;
import java.io.OutputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* SSH工具类
* @since 1.0.0
*/
public class SSHUtil {
/**
* SSH连接集合,Map<Socket Channel HashCode, SSH连接通道>
*/
public static Map<String, Channel> sshMap = new ConcurrentHashMap<>();
/**
* 执行SSH命令
* @param channelKey
* @param cmd
*/
public static void execCmd(String channelKey, String cmd) {
try {
if (sshMap.containsKey(channelKey)) {
OutputStream outputStream = sshMap.get(channelKey).getOutputStream();
outputStream.write(cmd.getBytes());
outputStream.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//------------------------------------------------------------------------------------------
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ChannelMap {
/**
* Map<ChannelHandlerContext HashCode, Channel>
*/
private static Map<String, Channel> map = new ConcurrentHashMap<>();
/**
* 登录账号和通信道关联关系Map集合
* Map<ChannelHandlerContext HashCode, 登录账号ID>
*/
public static Map<String, Integer> userChannelLinkMap = new ConcurrentHashMap<>();
public static void addChannel(String key, Channel c) {
map.put(key, c);
}
/**
* Socket断开连接时触发
* @param key
*/
public static void removeChannel(String key) {
//断开CPE的ssh连接
if(SSHUtil.sshMap.containsKey(key)) {
SSHUtil.sshMap.get(key).disconnect();
SSHUtil.sshMap.remove(key);
}
}
/**
* websocket推送消息
* @param msg
*/
public static void sendChannel(String channelKey, String msg) {
Channel c = map.get(channelKey);
if(c != null) {
c.writeAndFlush(new TextWebSocketFrame(msg));
}
else{
Log.info("web soket通道未连接成功,无法发送消息");
}
}
}
//------------------------------------------------------------------------------------------
/**
* 基础消息类
*/
public class WebBaseMsg {
private String type;//type类型可以从 WebBaseType里取
//消息ID,必须唯一,用来获取返回值唯一标准
private String msgId;
private String msgText;
/**日志类型的ID*/
private String typeId;
//初始化客户端id
public WebBaseMsg() {
}
public WebBaseMsg(String type, String msgText) {
super();
this.type = type;
this.msgText = msgText;
}
public String getTypeId() {
return typeId;
}
public void setTypeId(String typeId) {
this.typeId = typeId;
}
public String getMsgText() {
return msgText;
}
public void setMsgText(String msgText) {
this.msgText = msgText;
}
public String getMsgId() {
return msgId;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
//前端javascript代码
**使用 xterm.js 插件。**
var sshTerminal = null;
/**
* 打开控制台
*/
function openSSHConsoleModal() {
//清理结果集
$("#sshConsoleParentDiv").html("");
//---------------------------------------------
//显示控制台,这个是自己封装的bootstrap弹出框方法,可以直接使用$("#id").modal("show");
commons.setModalSize("sshConsoleModal", commons.getWindowWidth() * 0.8, 510);
commons.showModal("sshConsoleModal", function () {
sshTerminal = new Terminal({
cols: 250,
rows: 25,
cursorBlink: true, // 光标闪烁
cursorStyle: "block", // 光标样式 null | 'block' | 'underline' | 'bar'
scrollback: 800, //回滚
tabStopWidth: 8, //制表宽度
screenKeys: true
});
sshTerminal.open(document.getElementById('sshConsoleParentDiv'));
//在页面上显示连接中...
sshTerminal.write("Connecting \r\n");
//初始化SSH连接
//这个是发送socket消息,需要自己去实现websocket连接后台的代码
socketSend(commons.objectToJsonString({
type : "ssh-connection",
msgText: commons.objectToJsonString({
host : "192.168.1.1",
port : 22,
username: "root",
password: "admin"
})
}));
sshTerminal.on('data', function (data) {
socketSend(commons.objectToJsonString({
type : "ssh-send-command",
msgText: data
}));
});
},
//这个是自己封装的方法,关闭bootstrap modal时触发的。
function () {
//设置终端对象为空
sshTerminal = null;
//这个是自己封装的loading
commons.loadingShow();
//这个是发送socket消息
socketSend(commons.objectToJsonString({
type: "ssh-disconnection"
}));
//这个是自己封装的loading
commons.loadingHide();
});
}
/**
* 重写Socket返回数据的回调方法
* @param msg
*/
function socketCallback(msg) {
var obj = JSON.parse(msg.data);
if(obj.type = "ssh-receive") {
if(sshTerminal != null) {
console.log(obj.msgText);
sshTerminal.write(obj.msgText);
}
}
}
<%--页面代码--%>
<%--SSH控制台--%>
<div class="modal fade common_model" id="sshConsoleModal" tabindex="-1" role="basic" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content" style="margin-top: 50px;">
<div class="modal-header" style="background-color: #242424; margin-bottom: 0; border-bottom: 1px solid #504f4f; padding: 10px; border-top-left-radius: 0; border-top-right-radius: 0;">
<button type="button" class="close" data-dismiss="modal"></button>
<button type="button" style="float: right; margin-right: 20px; margin-top: -2px;" class="btn btn-xs grey-mint" onclick="openCpeSSHModal()">账号信息</button>
<h4 class="modal-title" id="sshConsoleModalTitle" style="font-size: 14px;">SSH控制台</h4>
</div>
<div class="modal-body" style="background-color: #242424; color: #9a9a9a; padding: 5px;" id="sshConsoleCmdList">
<div style="width: 100%;" id="sshConsoleParentDiv"></div>
</div>
</div>
</div>
</div>