美文网首页SpringbootSocketjava
SpringBoot+WebSocket+ganymed实现We

SpringBoot+WebSocket+ganymed实现We

作者: 蓝雄威 | 来源:发表于2018-12-31 13:26 被阅读472次

    一、背景

    实现Web版的SSH工具是某个同学公司的需求,刚听到这个需求的时候觉得挺扯蛋的,因为通过XShell或者SecureCRT直接连接过去不是更加方便吗?后面想想他们公司可的确有这方面的需求,他们公司是做金融相关的项目,操作的电脑都是不允许插U盘的,安装这些SSH工具比较难,所以需要有个Web版的SSH工具,方便在任何地方都可以直接操作服务器.对于这样的需求,有开源的GateOne可以实现WebSSH.不过我们也可以通过SpringBoot+WebSocket来简单实现这个需求,主要是了解一下WebSocket怎么使用以及Java如何通过SSH协议操作远程服务器.

    二、分析

    要实现Web的SSH工具,需要在前台页面不断的输出服务器响应的信息。所以选择WebSocket来和服务器连接,实时把数据输出到前台中.关于WebSocket的通俗解释:点击这里.
    怎么通过java操作远程服务器呢?有开源的项目ganymed可以通过java代码操作服务器并把结果返回.

    三、实现步骤

    步骤一:

    创建SpringBoot项目,然后导入websocket和ganymed相关依赖.

    <dependency>
         <groupId>org.springframework.boot</groupId>            
         <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    <dependency>
        <groupId>ch.ethz.ganymed</groupId>
        <artifactId>ganymed-ssh2</artifactId>
        <version>build210</version>
    </dependency>
    <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <version>1.16.10</version>
         <scope>provided</scope>
    </dependency>
    
    步骤二:

    添加连接远程服务器的工具类:

    package com.example.demo;
    
    import ch.ethz.ssh2.Connection;
    import ch.ethz.ssh2.Session;
    import ch.ethz.ssh2.StreamGobbler;
    import org.apache.tomcat.util.http.fileupload.IOUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.nio.charset.StandardCharsets;
    import java.util.Scanner;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    /**
     * Created by wolfcode-lanxw
     */
    
    public final class SSHAgent {
        private Connection connection;
        private Session session;
        private BufferedReader stdout;
        public PrintWriter printWriter;
        private BufferedReader stderr;
        private ExecutorService service = Executors.newFixedThreadPool(3);
    
        public void initSession(String hostName, String userName, String passwd) throws IOException {
            //根据主机名先获取一个远程连接
            connection = new Connection(hostName);
            //发起连接
            connection.connect();
            //认证账号密码
            boolean authenticateWithPassword = connection.authenticateWithPassword(userName, passwd);
            //如果账号密码有误抛出异常
            if (!authenticateWithPassword) {
                throw new RuntimeException("Authentication failed. Please check hostName, userName and passwd");
            }
            //开启一个会话
            session = connection.openSession();
            session.requestDumbPTY();
            session.startShell();
            //获取标准输出
            stdout = new BufferedReader(new InputStreamReader(new StreamGobbler(session.getStdout()), StandardCharsets.UTF_8));
            //获取标准错误输出
            stderr = new BufferedReader(new InputStreamReader(new StreamGobbler(session.getStderr()), StandardCharsets.UTF_8));
            //获取标准输入
            printWriter = new PrintWriter(session.getStdin());
        }
    
        public void execCommand(final WebSocketServer webSocketServer) throws IOException {
            //执行命令方法,使用线程池来执行
            service.submit(new Runnable() {
                @Override
                public void run() {
                    String line;
                    try {
                        //持续获取服务器标准输出
                        while ((line = stdout.readLine()) != null) {
                            //通过对应的webSocket服务端将内容输出到前台
                            webSocketServer.sendMessage(line);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        //关闭资源方法
        public void close() {
            IOUtils.closeQuietly(stdout);
            IOUtils.closeQuietly(stderr);
            IOUtils.closeQuietly(printWriter);
            session.close();
            connection.close();
        }
    }
    
    步骤三:

    添加WebSocket相关的配置.

    package com.example.demo;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.socket.server.standard.ServerEndpointExporter;
    /**
     * Created by wolfcode-lanxw
     */
    @Configuration
    public class WebSocketConfig {
        @Bean
        public ServerEndpointExporter serverEndpointExporter() {
            return new ServerEndpointExporter();
        }
    }
    

    这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint

    步骤四:

    添加WebSocket服务端的配置

    package com.example.demo;
    
    import java.io.IOException;
    
    import javax.websocket.OnClose;
    import javax.websocket.OnError;
    import javax.websocket.OnMessage;
    import javax.websocket.OnOpen;
    import javax.websocket.Session;
    import javax.websocket.server.ServerEndpoint;
    
    import lombok.extern.slf4j.Slf4j;
    
    import org.springframework.stereotype.Component;
    @Slf4j
    @ServerEndpoint(value = "/websocket")
    @Component
    public class WebSocketServer {
        //与某个客户端的连接会话,需要通过它来给客户端发送数据
        private Session session;
        //操作SSH的工具类
        private SSHAgent sshAgent;
        /**
         * 连接建立成功调用的方法*/
        @OnOpen
        public void onOpen(Session session) {
            log.info("客户端连接!");
            this.session = session;
            try {
                //在客户端通过webSocket连接时,创建一个SSH的会话
                this.sshAgent = new SSHAgent();
                //这里写上你的远程服务器ip,账号密码。当然你可以抽取成配置文件
                this.sshAgent.initSession("192.168.142.138", "root", "111111");
                //准备执行命令。
                sshAgent.execCommand(this);
            } catch (IOException e) {
                log.error("websocket IO异常");
            }
        }
        /**
         * 连接关闭调用的方法
         */
        @OnClose
        public void onClose() {
            this.sshAgent.close();
            log.info("有一连接关闭!");
        }
    
        /**
         * 收到客户端消息后调用的方法
         *
         * @param message 客户端发送过来的消息*/
        @OnMessage
        public void onMessage(String message, Session session) {
            log.info("来自客户端的消息:" + message);
            //群发消息
            try {
                //通过工具类的标准输入网远程服务器中写内容
                this.sshAgent.printWriter.write( message+ "\r\n");
                this.sshAgent.printWriter.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         *
         * @param session
         * @param error
         */
        @OnError
        public void onError(Session session, Throwable error) {
            log.error("发生错误");
            error.printStackTrace();
        }
    }
    
    步骤五:

    添加WebSocket客户端的配置,先添加query-2.1.3.min.js,然后再添加index.html,内容如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="jquery-2.1.3.min.js" type="text/javascript"></script>
        <script type="text/javascript">
    
            var socket;
            if(typeof(WebSocket) == "undefined") {
                console.log("您的浏览器不支持WebSocket");
            }else{
                console.log("您的浏览器支持WebSocket");
                //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接
                //socket = new WebSocket("ws://localhost:9094/starManager/websocket/张三")
                socket = new WebSocket("ws://localhost:8080/websocket");
                //打开事件
                socket.onopen = function() {
                    console.log("Socket 已打开");
                    //socket.send("这是来自客户端的消息" + location.href + new Date());
                };
                //获得消息事件
                socket.onmessage = function(msg) {
                    console.log(msg.data);
                    //发现消息进入    调后台获取
                };
                //关闭事件
                socket.onclose = function() {
                    console.log("Socket已关闭");
                };
                //发生了错误事件
                socket.onerror = function() {
                    alert("Socket发生了错误");
                }
                $(window).unload(function(){
                    socket.close();
                });
            }
    
            $(function(){
                $("#message").bind("keypress",function(){
                    if(event.keyCode == "13"){
                        socket.send($("#message").val());
                        $("#message").val("");
                    }
                });
                $(document).keydown(function(e) {
                    if (event.ctrlKey && event.keyCode === 67){
                        socket.send("quit;exit;");
                    }
                });
            });
        </script>
    </head>
    <body>
        <div id="content"></div>
        请输入命令(按回车结束):<input type="text" id="message">
    </body>
    </html>
    

    在页面中输入命令后,远程服务器的内容就会在控制台打印.

    相关文章

      网友评论

        本文标题:SpringBoot+WebSocket+ganymed实现We

        本文链接:https://www.haomeiwen.com/subject/xdsilqtx.html