1

PrimefacesのターミナルコンポーネントとJSchを使用してリモートデスクトップにSSH接続しています。execチャネルでは、セッションとチャネルの両方が各コマンドで閉じるため、実行に時間がかかりすぎて、それを回避できませんでした。そこで、チャネルをシェルに変更し、標準の入力/出力スチームを「リダイレクト」しようとしています。これが私のコードがどのように見えるかです:

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

@ManagedBean
@SessionScoped
public class TerminalController implements Serializable{  

     public TerminalController(){
     jsch=new JSch();
     InputStream in=null;
     PrintStream out=System.out;
try{
                      session=jsch.getSession(user, ip, port);
                      session.setConfig("StrictHostKeyChecking", "no");
                        session.setPassword(passwd);
                        session.connect();
                       channel=session.openChannel("shell");    
                       channel.setInputStream(in);
                       channel.setOutputStream(out);
                       channel.connect();
}catch(Exception ee){
                      System.out.println(ee);
} }
    public String handleCommand(String command, String[] params) {  
     command=command+StringUtils.join(params," ");

                   in=IOUtils.toInputStream(command);
                  String result=out.toString();
                   out.flush();
                    return result;}

私はそれが混乱していることを知っています、私はまだJavaの初心者です。私が考えたもう1つの問題は、iostreamからstringへの変換で、Enterボタン機能が失われる可能性があることです。私はあなたの提案、解決策、アドバイスを待っています。

4

2 に答える 2

1
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

import org.apache.commons.lang.StringUtils;
import org.fusesource.jansi.AnsiConsole;
import org.fusesource.jansi.AnsiString;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

@ManagedBean
@SessionScoped
public class TerminalController {
    BufferedReader fromChannel;
    PrintWriter toChannel;
    Channel channel;
    Session session;
    JSch jsch;

    public TerminalController() {
        jsch = new JSch();
        try {
            session = jsch.getSession("leoks", "localhost", 22);
            session.setConfig("StrictHostKeyChecking", "no");
            session.setPassword("xxx");
            session.connect(Integer.MAX_VALUE); // 3 secs timeout
            channel = session.openChannel("shell");
            InputStream inStream = channel.getInputStream();
            fromChannel = new BufferedReader(new InputStreamReader(inStream,
                    "UTF-8"));
            OutputStream outStream = channel.getOutputStream();
            toChannel = new PrintWriter(new OutputStreamWriter(outStream,
                    "UTF-8"));
            channel.connect();

            StringBuilder result = new StringBuilder();
            boolean stop = false;
            while (!stop) {
                // prompt does not end with newline...
                char c = (char) fromChannel.read();
                result.append(c);
                System.out.print(c);
                if (result.toString().endsWith("$")) {
                    System.out.print("<<<");
                    stop = true;
                }
            }

        } catch (Exception ee) {
            ee.printStackTrace();
        }
    }

    public String handleCommand(String command, String[] params)
            throws IOException {
        command = command + " " + StringUtils.join(params, " ");
        toChannel.println(command);
        toChannel.flush();
        StringBuilder result = new StringBuilder();
        AnsiConsole.systemInstall();
        while (true) {
            char c = (char) fromChannel.read();
            result.append(c);
            if (c == '$') {
                AnsiString as = new AnsiString(result.toString());
                String s = as.getPlain().toString();
                s = s.replaceAll("\n", "<br>");
                AnsiConsole.systemUninstall();
                return s;
            }
        }
    }
}

JansiにはHTMLレンダリングクラスもあります。これは、ターミナルコンポーネントがHTMLをレンダリングし、制御コードでいっぱいの不正な形式の文字列をサイレントに無視するため、\nをBRに適切に置き換えるための作業が必要です。たとえば、次のようなCSSを使用して、端末のCSS定義を固定幅フォントに置き換えることもできます。

.ui-widget
{
    font-family: "Courier New", Courier, monospace;
    font-size: 0.8em;
}

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui">
<h:head>
    <title>Terminal POC</title>
</h:head>
<h:body>
    <h:outputStylesheet library="css" name="styles.css" />
    <h:form>
        <p:terminal 
            commandHandler="#{terminalController.handleCommand}"
            height="300px" 
            welcomeMessage="Welcome..." 
            prompt="&gt;" />
    </h:form>
</h:body>
</html>
于 2013-05-28T17:09:45.423 に答える
0

変数を設定しinてもチャネルには影響せず、呼び出しout.toString()ても結果は得られません。

コマンド(およびそのパラメーター)をチャネルに書き込み、そこから出力を読み取る必要があります。setInputStreamまた、 orメソッドは使用しないでくださいsetOutputStream(読み取りまたは書き込みの既存のストリームがある場合は、これらのメソッドは適切ですが、使用しません)。

public class TerminalController implements Serializable{  

    BufferedReader fromChannel;
    PrintWriter toChannel;
    Channel channel;
    Session session;

     public TerminalController(){
        jsch=new JSch();
        try {
            session=jsch.getSession(user, ip, port);
            session.setConfig("StrictHostKeyChecking", "no");
            session.setPassword(passwd);
            session.connect();
            channel = session.openChannel("shell");    
            InputStream inStream = channel.getInputStream();
            fromChannel = new BufferedReader(new InputStreamReader(inStream, "UTF-8"));
            OutputStream outStream = channel.getOutputStream();
            toChannel = new PrintWriter(new OutputStreamWriter(outStream, "UTF-8"));
            channel.connect();
        } catch(Exception ee) {
            ee.printStackTrace();
        }
    }

    public String handleCommand(String command, String[] params) {  
         command = command + StringUtils.join(params," ");
         toChannel.println(command);
         StringBuilder result = new StringBuilder();
         while(true) {
            String line = fromChannel.readLine();
            result.append(line);
            if(looksLikePrompt(line))
               return result.toString();
            result.append("\n");
         }
    }
}

難しいのは、リモートコマンドからの出力がいつ終了するかを実際に知ることであり、戻る必要があります(これは、looksLikePrompt私が書き方を知らない方法にあります)。

Primefaceの端末コンポーネントのCommandHandler原理が、コマンドがいつ終了したかを端末が知る必要がないインタラクティブな端末を作成するための正しい設計であるかどうかはわかりません。コマンドにさらに入力が必要な場合はどうなりますか?

于 2012-09-22T18:09:30.883 に答える