JAVA 操作 linux 实现 xshell 持续操作功能
工作中让我去做一个类 Xshell 在页面显示的功能 经过 一些日子的 搜索资料 大概是找到了
记录上 学习链接 https://blog.csdn.net/sinadrew/article/details/79992986
https://www.cnblogs.com/lgfeng/p/3255535.html
主要通过这两篇文章 一步步摸索着写了出来
通过 长链接 ssh2 持续的 操作linux 数据库 现在 放上 代码
可以执行 基本的 操作命令 有一些修改文件的 内容是没法执行 sh脚本 可以使用
// 将链接 公共化 可能会出现问题 自己琢磨的
public static ChannelShell channelShell;
@RequestMapping("/addWindow")
public Result goNewAddServer() {
// 开启一个session 链接 自定义的getSession 方法
Session session = ShellUtils.getSession("192.168.200.XXX", "root", "root", 22);
try{
// 链接session 设置session 长链接
channelShell = ShellUtils.ChannelShell(session);
return new Result(true,"");
}catch (Exception e){
return new Result(false,"");
}
}
@RequestMapping("/linux")
public ResultList getLinux(@RequestBody String cmd) throws UnsupportedEncodingException {
// 控制台 打印 模拟linux 黑窗口
System.out.println("\n-----------------Linux Shell-----------------\n");
System.out.println("执行命令: " + cmd);
String res="";
// 判断 输入的命令 如果是 这三个 展示命令 会将 渲染的颜色取消 否则 变成 字符串 会出现乱码
if(cmd.equals("ls") || cmd.equals("ll") ||cmd.equals("vi")){
res = ShellUtils.executeNewFlow(channelShell, cmd +" --color=never"+ " \n");
System.out.println(res);
}else {
// 否则就正常输出命令
res = ShellUtils.executeNewFlow(channelShell, cmd + " \n");
}
// 遍历执行结果 按照 \r\n 分隔
String[] str ={} ;
str = res.split("\r\n");
List<String>list = new ArrayList();
for (String st:str){
list.add(st);
}
// 将结果返回给前台页面
return new ResultList(true, list);
}
package com.icbc.gateway.util;
import com.jcraft.jsch.*;
import java.io.*;
public class ShellUtils {
/**
* 创建session
* @param host 主机名称/ip地址
* @param user 登陆用户名
* @param psw 密码
* @param port 端口
* @return
*/
public static Session getSession(String host,String user,String psw,int port){
JSch jsch=new JSch();
Session session=null;
try {
session = jsch.getSession(user, host, port);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setPassword(psw);
session.connect();
} catch (JSchException e) {
System.out.println("连接linux主机失败");
e.printStackTrace();
}
return session;
}
/**
* 得到可以执行命令的连接
* @param session 连接session
* @return 可以执行命令的ChannelExec
*/
public static ChannelExec getChanel(Session session){
ChannelExec openChannel=null;
try {
if(null !=session){
openChannel = (ChannelExec) session.openChannel("exec");
}
} catch (JSchException e) {
e.printStackTrace();
}
return openChannel;
}
/**
*
* @param openChannel
* @param command
* @return
*/
public static String getExcRes(ChannelExec openChannel,String command){
InputStream in =null;
BufferedReader reader=null;
StringBuffer result=new StringBuffer();
try {
try {
openChannel.setCommand(command);
int exitStatus = openChannel.getExitStatus();
System.out.println(exitStatus);
openChannel.connect();
in = openChannel.getInputStream();
reader = new BufferedReader(new InputStreamReader(in));
String buf = null;
while ((buf = reader.readLine()) != null) {
result.append(new String(buf.getBytes("gbk"),"UTF-8")+"<br>\r\n");
}
//reader.close();
} catch (JSchException e) {
result.append(e.getMessage());
e.printStackTrace();
}
} catch (IOException e) {
result.append(e.getMessage());
e.printStackTrace();
} /*finally {
//try {
//reader.close();
//} catch (IOException e) {
//e.printStackTrace();
//}
}*/
return result.toString();
}
public static ChannelShell ChannelShell(Session session) {
ChannelShell channel = null;
try {
if (null != session) {
channel = (ChannelShell) session.openChannel("shell");
channel.connect();
}
} catch (JSchException e) {
e.printStackTrace();
}
return channel;
}
public static String executeNewFlow(ChannelShell channel, String command) {
InputStream in =null;
OutputStream out=null;
String msg=null;
BufferedReader reader=null;
StringBuffer result=new StringBuffer();
try {
in = channel.getInputStream();
out = channel.getOutputStream();
out.write(command.getBytes());
out.flush();
// reader = new BufferedReader(new InputStreamReader(in));
// while ((msg =reader.readLine()) !=null ){
// System.out.println(msg);
// }
byte[] tmp=new byte[1024];
while (true){
int i=0;
//线程等待 200ms
Thread.currentThread().sleep(200);
while(in.available()>0){
i=in.read(tmp, 0, 1024);
if(i<0)break;
}
System.out.print(new String(tmp, 0, i));
return new String(tmp, 0, i);
// if(channel.isClosed()){
// if(in.available()>0) continue;
// System.out.println("exit-status: "+channel.getExitStatus());
// break;
// }
}
}catch (Exception e){
result.append(e.getMessage());
e.printStackTrace();
}
return null;
}
public static void disConnect(Session session,ChannelExec openChannel){
if(session!=null&&!openChannel.isClosed()){
openChannel.disconnect();
}
if(session!=null&&session.isConnected()){
session.disconnect();
}
}
// public static void main(String[] args) {
// Session session=getSession("192.168.230.129", "root", "123456", 22);
// ChannelExec chanel=getChanel(session);
// String res=getExcRes(chanel, "cd /home;ls;");
// System.out.println(res);
// ChannelExec chanel2=getChanel(session);
// String ss=getExcRes(chanel2, "ls;");
// System.out.println(ss);
// }
}
这是我借鉴来的 链接linux 方法 需要注意的 有两个
channel = (ChannelShell) session.openChannel(“shell”);
openChannel = (ChannelExec) session.openChannel(“exec”);
这两个地方开启的链接是不同的 一个是一次性链接 一个是 长链接 好像是 具体的有点忘记了
前台 使用的 是angular 还有 借鉴过来的 ajax 黑框口 使用的 layer.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" name="viewport">
<link rel="stylesheet" type="text/css" href="../plugins/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../plugins/adminLTE/css/AdminLTE.min.css">
<link rel="stylesheet" type="text/css" href="../plugins/adminLTE/css/skins/_all-skins.min.css">
<script src="../plugins/jQuery/jquery-2.2.3.min.js" ></script>
<script src="../plugins/bootstrap/js/bootstrap.min.js" ></script>
<script src="../plugins/layer/layer.js"></script>
<script src="../plugins/angularjs/angular.min.js"></script>
<script src="../plugins/angularjs/pagination.js" ></script>
<link rel="stylesheet" type="text/css" href="../plugins/angularjs/pagination.css" >
<script>
var app = angular.module('ICBC',[]);
app.controller('gthController',function ($scope,$http) {
$scope.addWindow = function () {
$http.post('../gth/addWindow').success(
function (response) {
if(response.flag){
layer.open({
type: 2,
title: 'Linux 黑窗口',
maxmin: true,
shadeClose: true, //点击遮罩关闭层
area: ['800px', '520px'],
content: 'box1.html'
})
}
}
)
}
});
</script>
</head>
<body ng-app="ICBC" ng-controller="gthController">
<!--<a id="parentIframe" class="layui-btn">运行上述例子</a>-->
<button id="parentIframe" ng-click="addWindow()" class="layui-btn">运行上述例子</button>
</body>
</html>
黑框口的设置 之前 可以随意修改 主体是一个input 框 每次 执行命令 将后台的结果 展示到append 到前台 展示
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>命令行窗口</title>
<script src="../plugins/jQuery/jquery-2.2.3.min.js" ></script>
<script src="../plugins/layer/layer.js"></script>
<script src="../plugins/angularjs/angular.min.js"></script>
<script src="../plugins/angularjs/pagination.js" ></script>
<link rel="stylesheet" type="text/css" href="../plugins/angularjs/pagination.css" >
<style type="text/css">
body{
background-color: #424242; /*背景颜色*/
font-size:14px;
}
.incmd {
background-color: #9FB6CD; /*输入行颜色*/
border: 0;
color: #FFFFFF; /*输入字体颜色*/
outline: none;
font-size:14px;
width: 99%;
}
.panel {/*暂时未用*/
background-color: #424242; /*背景颜色*/
border-top: #424242 outset 2px;/*上边框*/
width: 700px;
height: 500px;
overflow-y: scroll;
overflow-x:visible;
font-size:14px;
}
ul {
margin: 0px;
padding: 0px;
list-style: none;
color:#7CFC00; /*显示字体颜色*/
}
input {
background-color: #9FB6CD; /*输入行颜色*/
border: 0;
color: #FFFFFF; /*输入字体颜色*/
outline: none;
font-size:14px;
width: 99%;
}
</style>
<script type="text/javascript">
var app = angular.module('ICBC',[]);
app.controller('gthController',function ($scope,$http) {
$scope.linux = function($event){
if($event.keyCode == 13){
$http.post('../gth/linux',$scope.entity).success(
function (response) {
if(response.flag==true) {
$("ul").append("<li>" +"输入的命令为: "+ $scope.entity + "</li>"+"<br>"); //将输入的输出到界面
angular.forEach(response.message,function (data) {
$("ul").append("<li>" + data + "</li>"); //获取返回值并输出
})
$scope.entity=""; //清空输入框
$("#msg").scrollTop($("#msg").scrollTop() + 9999);//滚动条拉到最下面,显示出输入框
}
}
)
}
}
})
function CloseWebPage() {
if (navigator.userAgent.indexOf("MSIE") > 0) {
if (navigator.userAgent.indexOf("MSIE 6.0") > 0) {
window.opener = null;
window.close();
} else {
window.open('', '_top');
window.top.close();
}
} else if (navigator.userAgent.indexOf("Firefox") > 0) {
window.location.href = 'about:blank ';
} else {
window.opener = null;
window.open('', '_self', '');
window.close();
}
}
</script>
</head>
<body ng-app="ICBC" ng-controller="gthController">
<div id="msg">
<ul>
<li>----------------------命令Demo----------------------------</li>
<li>关闭进程方式1:</li>
<li> exit //退出 进程</li>
<li>----------------------开始操作----------------------------</li>
</ul>
<input type="text" ng-model="entity" value="$" ng-keypress="linux($event)" >
</div>
</body>
package com.icbc.gateway.pojo;
import java.io.Serializable;
public class Result implements Serializable {
private boolean flag;
private String message;
@Override
public String toString() {
return "Result{" +
"flag=" + flag +
", message='" + message + '\'' +
'}';
}
public Result(boolean flag, String message) {
super();
this.flag = flag;
this.message = message;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
就放全了吧 根据 要改的 linux 端口号 修改即可 jdk 1.8 ssh2 库
记录一下自己之前写的 不然隔几天就给忘记了