linux Web控制台

前段时间做一个hadoop+Spark的性能监控页面时,需要一个web控制台远程登陆到master节点上去,后来发现这方面资料太少,于是自己参照着零散的东西修修改改,终于做出了一个简单的web shell,记录一下以免时间长了忘记。大概像这个样子的:


这样就可以在网页上直接访问linux服务器了,初衷是用来远程关闭正在运行的spark任务的,做发现出来之后一般的linux命令都能执行。

首先讲一下后台实现:

1.建立ssh连接,并定义一些流用于收发命令。

2.其次定义是一个接收命令和返回结果的方法,因为linux每次返回一行,所以我这里存入List<String>返回给前台处理。

代码都如下:
package com.java.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;


public class SSHLinux
{
	private String hostname = "11.11.11.15";
	private int port = 22;
	private String username = "root";
	private String password = "123456";
	
	private  Connection conn;
	private  Session sess;
	private  BufferedReader stdout;
	private BufferedReader stderr;
	private PrintWriter pw;
	
	public SSHLinux()
	{
		//使用默认值		
		long t1 = System.currentTimeMillis();
		initSession();
		long t2 = System.currentTimeMillis();
		System.out.println("远程登陆linux,连接耗时:"+(t2-t1)/1000.0+"s");
	}
	
	public SSHLinux(String hostname, int port, String username, String password) 
	{		
		this.hostname = hostname;
		this.port = port;
		this.username = username;
		this.password = password;
	
		long t1 = System.currentTimeMillis();
		initSession();
		long t2 = System.currentTimeMillis();
		System.out.println("远程登陆linux,连接耗时:"+(t2-t1)/1000.0+"s");
	}
	
	//初始化连接并建立虚拟终端
	public void initSession()
	{
		try
		{			
			conn = new Connection(hostname,port);
			conn.connect();
			boolean isAuthenticated = conn.authenticateWithPassword(username, password);
			if (isAuthenticated == false)
				throw new IOException("Authentication failed.");
			
			sess = conn.openSession();
			sess.requestDumbPTY();//建立虚拟终端
			sess.startShell();//打开一个Shell	
			
			stdout = new BufferedReader(new InputStreamReader(new StreamGobbler(sess.getStdout()), StandardCharsets.UTF_8));
			stderr = new BufferedReader(new InputStreamReader(new StreamGobbler(sess.getStderr()), StandardCharsets.UTF_8));
			pw = new PrintWriter(sess.getStdin(),true);// 准备输入命令
			
		}
		catch (IOException e)
		{
			System.out.println("------建立ssh linux连接错误------");
		}
	}
	
	
	public void close()
	{
		try
		{
			stdout.close();
			stderr.close();
			pw.close();
			sess.close();
			conn.close();
		}
		catch (Exception e) 
		{
			System.out.println("------关闭ssh连接错误------");
		}
	
	}

	public List<String> execute(String strcmd)
	{			
		System.out.println("在execute()中接收到命令:"+ strcmd );
		List<String> rstList = new ArrayList<String>();
		try
		{		
			if(strcmd.equals("exit"))
			{
				pw.println(strcmd);// 输入待执行命令	
				close();
				rstList.add("用户退出,关闭连接!!!");
				return rstList;
			}
			
			pw.println(strcmd);// 输入待执行命令					
			
			while (true)
			{
				String line = stdout.readLine();
				if (line == null || line.trim().endsWith("#"))
					break;
				
				System.out.println(line);
				rstList.add(line);
			}
						
		}
		catch (IOException e)
		{
			System.out.println("------连接已经关闭或命令出错------");
		}		
			
		return rstList;		
	}

	
	public static void main(String[] args)
	{
		SSHLinux ssh = new SSHLinux("192.168.0.160",22,"root","123456");
		List<String> list = ssh.execute("pwd");
		System.out.println("list----: "+list);
		//ssh.execute("exit");
	}
}


3.页面后台调用前面初始化方法和执行命令的方法,这个方法叫getLinux(),主要是和前台页面交互。我在这个方法命名为linux,即@RequestMapping("/linux"),前台就可以通过linux.do识别了。

首先创建弹出框并初始化:

        /*
	 * 创建按钮弹出框
	 */
	@RequestMapping("/addWindow")
	public ModelAndView goNewAddServer(HttpServletRequest req)
	{ 
		//ssh连接linux---------从xml配置文件中读取参数
		ApplicationContext ct = new ClassPathXmlApplicationContext("applicationContext.xml");
		Permission per = (Permission) ct.getBean("linux");		
		String hostname = per.getIp();
		int port  = per.getPort();
		String username = per.getUsername();
		String password = per.getPassword();
		System.out.println("ssh连接linux---------Permission="+per.toString());
		
		try {
			ssh = new SSHLinux(hostname,port,username,password);
                        //或者将账号写死
			//ssh = new SSHLinux("192.168.1.12",22,"root","123456");
		} catch (Exception e) {			
			e.printStackTrace();
		}		
		return new ModelAndView("/admin/cloudcompute/box");///对应web console页面
	}
其次执行命令,主要是和前台页面交互
        /*
	 * 在linux web shell中执行命令
	 */
	@RequestMapping("/linux")
	@ResponseBody
	private void getLinux(HttpServletRequest request, HttpServletResponse response)throws Exception{
		System.out.println("\n-----------------Linux Shell-----------------\n");		
		String cmd = request.getParameter("code");
		System.out.println("执行命令: "+cmd);
		
		if(ssh!=null)
		{
			List<String> list = new ArrayList<String>();
			if(cmd.length()==0)
			{
				System.out.println("输入为空");
				//list.add("输入为空");
			}
			else if(cmd!="" || cmd.length()!=0 || cmd!=null)
			{
				list = ssh.execute(cmd);	
			}
			
			System.out.println("返回结果list----: "+list);
			
			String result = ""; //{'data:','
			for(String str : list)
			{
				result += str.trim()+"<br/>";
			}
			//result +="'}";				
			ResponseUtil.write(response, result);
			//JsonBinder buildNormalBinder = JsonBinder.buildNormalBinder();
			//return buildNormalBinder.toJson(result);
		}
		else
		{
			System.out.println("没有连接,不执行命令");
			//return "";
		}
						
	}//


4.接下来看页面,页面很简单:主要是定义<ul>列表来接收命令,因为发送的命令占一行,回来的结果为一行或多行,所以<ul>列表很合适。

<!-- 按钮触发模态框 -->
<span class="annnys">
	<a id="linuxWindow" class="pve-tabletack active-tabletack" href="javascript:establishDialog()" style="cursor:pointer;">控制台</a>											
</span>
<!-- 模态框(Modal) -->
<div class="modal fade" id="myModal"
	 tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
	<div class="modal-dialog"  style="width:703px;height:410px;">
		<div class="modal-content">
			<div class="modal-header">
				<button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
				<p class="modal-title" id="myModalLabel">Linux 控制台</p>
			</div>
			<div class="modal-body" style="padding:0px;">
				<!-- <iframe id="box" src="box.jsp" style="width:600px;height:400px;"></iframe> -->
				
				<div class="wingb" id="msg">
					<ul class="myul">
					<li>----------------------命令Demo----------------------------</li>
					<li>关闭进程方式1:</li>	
					<li>ps -aux | grep test.jar		//根据提交的jar包名字来查找进程,再kill -9 [pid]杀掉进程</li>
					<li>关闭进程方式2:</li>	
					<li>ps -aux | grep test.jar | kill -9 `awk '{print $2}'`	//查找进程id并立即杀掉</li>
					<li>关闭进程方式3:</li>
					<li>kill -9 $(cat my.pid)	//前提:提交任务时获取进程号: spark-submit --class demo.WordCount test.jar & echo $!>my.pid</li>
					<li>----------------------开始操作----------------------------</li>
					</ul>								
					<!-- <div class="incmd"  contentEditable="true"  id='in'>$</div> -->
					<input class="incmd" type="text" value="$" id='in'>
				</div>
				
			</div><!-- modal-body -->
		</div><!-- /.modal-content -->
	</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<script>				
$("#in").keyup(function(event) {					
	if (event.keyCode == 13) {	//回车			
		$.ajax({
			async: false,
			type : "POST",
			url : "${pageContext.request.contextPath}/admin/cloudcompute/linux.do",
			data : "code=" + $("#in").val().substring(1),
			success : function(data) {
				$("ul").append("<li>" + $("#in").val() + "</li>");  //将输入的输出到界面
				$("ul").append("<li>" + data + "</li>"); //获取返回值并输出
				$("#in").val("$"); //清空输入框
				$("#msg").scrollTop($("#msg").scrollTop() + 9999);//滚动条拉到最下面,显示出输入框
			}
		});
	}
	else  if(event.ctrlKey && event.which == 81){ //ctrl+Q 中断
		alert("ctrl+Q 中断");
		 CloseWebPage();
	}
});

$("#in")[0].focus();

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();
	}
}

//创建按钮 弹出框
function establishDialog(){
	xajax.iframeLAYER('${pageContext.request.contextPath}/admin/cloudcompute/addWindow.do',
			"linux控制台", 
			'620px', 
			'430px',
			function(){	
	});
		
}

</script>

这是原来的页面中增加的一个模态框,通过按钮触发。当然也可以新建一个页面专门来做控制台,代码都一样,如图:

<%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>命令行窗口</title>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/public-js/jquery-1.8.0.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/layer/layer.js"></script>

<style type="text/css">
body{
	background-color: #424242;  /*背景颜色*/
	font-size:14px;
	font: "微软雅黑";
}


.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>
$(function(){
	$("#in").keyup(function(event) {		
	
		if (event.keyCode == 13) {	//回车			
			$.ajax({
				async: false,
				type : "POST",
				url : "${pageContext.request.contextPath}/admin/cloudcompute/linux.do",
				data : "code=" + $("#in").val().substring(1),
				success : function(data) {
					$("ul").append("<li>" + $("#in").val() + "</li>");  //将输入的输出到界面
					$("ul").append("<li>" + data + "</li>"); //获取返回值并输出
					$("#in").val("$"); //清空输入框
					$("#msg").scrollTop($("#msg").scrollTop() + 32);//滚动条拉到最下面,显示出输入框
				}
			});
		}
		/* else  if(event.ctrlKey && event.which == 81){ //ctrl+Q 中断
        	alert("ctrl+Q 中断");
        }
		else  if(event.which == 27){ //ESC 退出			
        	alert("ESC终端");
        	CloseWebPage();
        }
			 */
	});

	$("#in")[0].focus();	
	
});
	
	

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>
<div id="msg">
	<ul>
	<li>----------------------命令Demo----------------------------</li>
	<li>关闭进程方式1:</li>	
	<li>ps -aux | grep test.jar		//根据提交的jar包名字来查找进程,再kill -9 [pid]杀掉进程</li>
	<li>关闭进程方式2:</li>	
	<li>ps -aux | grep test.jar | kill -9 `awk '{print $2}'`	//查找进程id并立即杀掉</li>
	<li>关闭进程方式3:</li>
	<li>kill -9 $(cat my.pid)	//前提:提交任务时获取进程号: spark-submit --class demo.WordCount test.jar & echo $!>my.pid</li>
	<li>----------------------开始操作----------------------------</li>
	</ul>

	<!-- <div class="incmd"  contentEditable="true"  id='in'>$</div> -->
	<input type="text" value="$" id='in'>
</div>

</body>
</html>

5.页面调用后台代码的部分都是一样的,linux.do就会调转到前面提到的getLinux()方法。

ok, 本文主要从后台到前台的顺序讲了如何实现一个简单web shell。

完。

我准备写一个公众号技术博客,回顾我学大数据以来的个人经验,希望和大家一起每天进步一点点!刚刚开始写,请大家多多支持,如有不足之处多多包含,最后多多关注哈哈哈。


  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值