当前位置 : 主页 > 编程语言 > java >

关于Springboot中JSCH的使用及说明

来源:互联网 收集:自由互联 发布时间:2023-01-30
目录 1. JSCH简介 2. JSCH依赖 3. 使用方法 3.1 连接远程主机 3.2 ChannelExec使用说明 3.3 ChannelSftp使用说明 3.4 ChannelShell使用说明 3.5 完整工具类代码 4. 使用连接池 1. JSCH简介 JSch 是SSH2的一个纯
目录
  • 1. JSCH简介
  • 2. JSCH依赖
  • 3. 使用方法
    • 3.1 连接远程主机
    • 3.2 ChannelExec使用说明
    • 3.3 ChannelSftp使用说明
    • 3.4 ChannelShell使用说明
    • 3.5 完整工具类代码
  • 4. 使用连接池

    1. JSCH简介

    JSch 是SSH2的一个纯Java实现。它允许你连接到一个sshd 服务器,使用端口转发,X11转发,文件传输等等。

    你可以将它的功能集成到你自己的 程序中。同时该项目也提供一个J2ME版本用来在手机上直连SSHD服务器。

    2. JSCH依赖

            <dependency>
                <groupId>com.jcraft</groupId>
                <artifactId>jsch</artifactId>
                <version>0.1.55</version>
            </dependency>

    3. 使用方法

    3.1 连接远程主机

    /**
         * 初始化
         *
         * @param ip       远程主机IP地址
         * @param port     远程主机端口
         * @param username 远程主机登陆用户名
         * @param password 远程主机登陆密码
         * @throws JSchException JSch异常
         */
        public void init(String ip, Integer port, String username, String password) throws JSchException {
            JSch jsch = new JSch();
            session = jsch.getSession(username, ip, port);
            session.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", strictHostKeyChecking);
            session.setConfig(sshConfig);
            session.connect(timeout);
            log.info("Session connected!");
        }
        public void init(String ip, String username, String password) throws JSchException {
            init(ip,22,username,password);
        }
    

    3.2 ChannelExec使用说明

    /**
         * 连接多次执行命令,执行命令完毕后需要执行close()方法
         *
         * @param command 需要执行的指令
         * @return 执行结果
         * @throws Exception 没有执行初始化
         */
        public String execCmd(String command) throws Exception {
            // 打开执行shell指令的通道
            channel = session.openChannel("exec");
            channelExec = (ChannelExec) channel;
            if (session == null || channel == null || channelExec == null) {
                log.error("请先执行init()");
                throw new Exception("请先执行init()");
            }
            log.info("execCmd command - > {}", command);
            channelExec.setCommand(command);
            channel.setInputStream(null);
            channelExec.setErrStream(System.err);
            channel.connect();
            StringBuilder sb = new StringBuilder(16);
            try (InputStream in = channelExec.getInputStream();
                 InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);
                 BufferedReader reader = new BufferedReader(isr)) {
                String buffer;
                while ((buffer = reader.readLine()) != null) {
                    sb.append("\n").append(buffer);
                }
                log.info("execCmd result - > {}", sb);
                return sb.toString();
            }
        }
        /**
         * 执行命令关闭连接
         * @param command 需要执行的指令
         * @return 执行结果
         * @throws Exception 没有执行初始化
         */
        public String execCmdAndClose(String command) throws Exception {
            String result = execCmd(command);
            close();
            return result;
        }
        
         /**
         * 释放资源
         */
        public void close() {
            if (channelExec != null && channelExec.isConnected()) {
                channelExec.disconnect();
            }
            if (channel != null && channel.isConnected()) {
                channel.disconnect();
            }
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }
    

    3.3 ChannelSftp使用说明

    3.3.1 ChannelSftp简介

    ChannelSftp类是JSch实现SFTP核心类,它包含了所有SFTP的方法,如:

    • put(): 文件上传
    • get(): 文件下载
    • cd(): 进入指定目录
    • ls(): 得到指定目录下的文件列表
    • rename(): 重命名指定文件或目录
    • rm(): 删除指定文件
    • mkdir(): 创建目录
    • rmdir(): 删除目录

    3.3.2 JSch支持三种文件传输模式:

    模式描述OVERWRITE完全覆盖模式,这是JSch的默认文件传输模式,即如果目标文件已经存在,传输的文件将完全覆盖目标文件,产生新的文件。RESUME恢复模式,如果文件已经传输一部分,这时由于网络或其他任何原因导致文件传输中断,如果下一次传输相同的文件,则会从上一次中断的地方续传。APPEND追加模式,如果目标文件已存在,传输的文件将在目标文件后追加。

    3.3.3 文件上传

    实现文件上传可以调用ChannelSftp对象的put方法。ChannelSftp中有12个put方法的重载方法:

    方法描述public void put(String src, String dst)将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。采用默认的传输模式:OVERWRITEpublic void put(String src, String dst, int mode)将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。指定文件传输模式为mode(mode可选值为:ChannelSftp.OVERWRITE,ChannelSftp.RESUME,ChannelSftp.APPEND)public void put(String src, String dst, SftpProgressMonitor monitor)将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。采用默认的传输模式:OVERWRITE,并使用实现了SftpProgressMonitor接口的monitor对象来监控文件传输的进度。public void put(String src, String dst,SftpProgressMonitor monitor, int mode)将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同。指定传输模式为mode,并使用实现了SftpProgressMonitor接口的monitor对象来监控文件传输的进度。public void put(InputStream src, String dst)将本地的input stream对象src上传到目标服务器,目标文件名为dst,dst不能为目录。采用默认的传输模式:OVERWRITEpublic void put(InputStream src, String dst, int mode)将本地的input stream对象src上传到目标服务器,目标文件名为dst,dst不能为目录。指定文件传输模式为modepublic void put(InputStream src, String dst, SftpProgressMonitor monitor)将本地的input stream对象src上传到目标服务器,目标文件名为dst,dst不能为目录。采用默认的传输模式:OVERWRITE,并使用实现了SftpProgressMonitor接口的monitor对象来监控传输的进度。public void put(InputStream src, String dst,SftpProgressMonitor monitor, int mode)将本地的input stream对象src上传到目标服务器,目标文件名为dst,dst不能为目录。指定文件传输模式为mode,并使用实现了SftpProgressMonitor接口的monitor对象来监控传输的进度。public OutputStream put(String dst)该方法返回一个输出流,可以向该输出流中写入数据,最终将数据传输到目标服务器,目标文件名为dst,dst不能为目录。采用默认的传输模式:OVERWRITEpublic OutputStream put(String dst, final int mode)该方法返回一个输出流,可以向该输出流中写入数据,最终将数据传输到目标服务器,目标文件名为dst,dst不能为目录。指定文件传输模式为modepublic OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode)该方法返回一个输出流,可以向该输出流中写入数据,最终将数据传输到目标服务器,目标文件名为dst,dst不能为目录。指定文件传输模式为mode,并使用实现了SftpProgressMonitor接口的monitor对象来监控传输的进度。public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode, long offset)该方法返回一个输出流,可以向该输出流中写入数据,最终将数据传输到目标服务器,目标文件名为dst,dst不能为目录。指定文件传输模式为mode,并使用实现了SftpProgressMonitor接口的monitor对象来监控传输的进度。offset指定了一个偏移量,从输出流偏移offset开始写入数据。
        /**
         * SFTP文件上传
         *
         * @param src 源地址
         * @param dst 目的地址
         * @throws Exception 上传文件失败
         */
        public void putAndClose(String src, String dst) throws Exception {
            putAndClose(src, dst, ChannelSftp.OVERWRITE);
        }
        /**
         * SFTP文件上传
         *
         * @param src  源地址
         * @param dst  目的地址
         * @param mode 上传模式 默认为ChannelSftp.OVERWRITE
         * @throws Exception 上传文件失败
         */
        public void putAndClose(String src, String dst, int mode) throws Exception {
            initChannelSftp();
            log.info("Upload File {} -> {}", src, dst);
            channelSftp.put(src, dst, mode);
            log.info("Upload File Success!");
            close();
        }
        /**
         * SFTP文件上传并监控上传进度
         *
         * @param src 源地址
         * @param dst 目的地址
         * @throws Exception 上传文件失败
         */
        public void putMonitorAndClose(String src, String dst) throws Exception {
            putMonitorAndClose(src, dst, ChannelSftp.OVERWRITE);
        }
        /**
         * SFTP文件上传并监控上传进度
         *
         * @param src  源地址
         * @param dst  目的地址
         * @param mode 上传模式 默认为ChannelSftp.OVERWRITE
         * @throws Exception 上传文件失败
         */
        public void putMonitorAndClose(String src, String dst, int mode) throws Exception {
            initChannelSftp();
            UploadMonitor monitor = new UploadMonitor(new File(src).length());
            log.info("Upload File {} -> {}", src, dst);
            channelSftp.put(src, dst, monitor, mode);
            log.info("Upload File Success!");
            close();
        }
        /**
         * 释放资源
         */
        public void close() {
            if (channelSftp != null && channelSftp.isConnected()) {
                channelSftp.disconnect();
            }
            if (channel != null && channel.isConnected()) {
                channel.disconnect();
            }
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }
        private void initChannelSftp() throws Exception {
            channel = session.openChannel("sftp");
            channel.connect(); // 建立SFTP通道的连接
            channelSftp = (ChannelSftp) channel;
            if (session == null || channel == null || channelSftp == null) {
                log.error("请先执行init()");
                throw new Exception("请先执行init()");
            }
        }
    }
    

    3.3.4 文件下载

    JSch文件下载是通过调用ChannelSftp对象的get方法来实现的。ChannelSftp中有9个get方法的重载方法:

    方法描述publicvoid get(String src, String dst)将目标服务器上文件名为src的文件下载到本地,本地文件名为dst。若dst为目录,则下载到本地的文件名将与src文件名相同。(注:src必须是文件,不能为目录),采用默认的传输模式:OVERWRITEpublicvoid get(String src, String dst, SftpProgressMonitor monitor)将目标服务器上文件名为src的文件下载到本地,本地文件名为dst。若dst为目录,则下载到本地的文件名将与src文件名相同。(注:src必须是文件,不能为目录),采用默认的传输模式:OVERWRITEpublicvoid get(String src, String dst,SftpProgressMonitor monitor, int mode)将目标服务器上文件名为src的文件下载到本地,本地文件名为dst。若dst为目录,则下载到本地的文件名将与src文件名相同。(注:src必须是文件,不能为目录)指定文件传输模式为mode(mode可选值为:ChannelSftp.OVERWRITE,ChannelSftp.RESUME,ChannelSftp.APPEND),并使用实现了SftpProgressMonitor接口的monitor对象来监控文件的传输进度。publicvoid get(String src, OutputStream dst)将目标服务器上文件名为src的文件下载到本地,下载的数据写入到输出流对象dst(如:文件输出流)。采用默认的传输模式:OVERWRITEpublicvoid get(String src, OutputStream dst, SftpProgressMonitor monitor)将目标服务器上文件名为src的文件下载到本地,下载的数据写入到输出流对象dst(如:文件输出流)。采用默认的传输模式:OVERWRITE,并使用实现了SftpProgressMonitor接口的monitor对象来监控文件的传输进度。publicvoid get(String src, OutputStream dst, SftpProgressMonitor monitor, int mode, long skip)将目标服务器上文件名为src的文件下载到本地,下载的数据写入到输出流对象dst(如:文件输出流)。指定文件传输模式为mode并使用实现了SftpProgressMonitor接口的monitor对象来监控文件的传输进度。skip指定了一个跳读量,即下载时从src文件跳过skip字节的数据。(一般不推荐使用该参数,默认设为0)public InputStream get(String src)该方法返回一个输入流,该输入流含有目标服务器上文件名为src的文件数据。可以从该输入流中读取数据,最终将数据传输到本地(如:读取数据后将数据写入到本地的文件中)(注:该方法不支持多种文件传输模式,如何读取与保存数据由应用程序自己确定)public InputStream get(String src, SftpProgressMonitor monitor)该方法返回一个输入流,该输入流含有目标服务器上文件名为src的文件数据。可以从该输入流中读取数据,最终将数据传输到本地(如:读取数据后将数据写入到本地的文件中)并使用实现了SftpProgressMonitor接口的monitor对象来监控文件的传输进度。(注:该方法不支持多种文件传输模式,如何读取与保存数据由应用程序自己确定)public InputStream get(String src, final SftpProgressMonitor monitor, finallong skip)该方法返回一个输入流,该输入流含有目标服务器上文件名为src的文件数据。可以从该输入流中读取数据,最终将数据传输到本地(如:读取数据后将数据写入到本地的文件中)并使用实现了SftpProgressMonitor接口的monitor对象来监控文件的传输进度。(注:该方法不支持多种文件传输模式,如何读取与保存数据由应用程序自己确定)skip指定了一个跳读量,即下载时从src文件跳过skip字节的数据。(一般不推荐使用该参数,默认设为0)
    /**
         * SFTP文件下载
         *
         * @param src 源文件地址
         * @param dst 目的地址
         * @throws Exception 下载文件失败
         */
        public void getAndClose(String src, String dst) throws Exception {
            initChannelSftp();
            log.info("Download File {} -> {}", src, dst);
            channelSftp.get(src, dst);
            log.info("Download File Success!");
            close();
        }
        public void getMonitorAndClose(String src, String dst) throws Exception {
            initChannelSftp();
            FileProgressMonitor monitor = new FileProgressMonitor(new File(src).length());
            log.info("Download File {} -> {}", src, dst);
            channelSftp.get(src, dst, monitor);
            log.info("Download File Success!");
            close();
        }
    

    3.4 ChannelShell使用说明

    3.4.1 shell代码

    /**
         * 执行复杂shell命令
         * @param cmds 多条命令
         * @return 执行结果
         * @throws Exception 连接异常
         */
        public String execCmdByShell(String... cmds)throws Exception{
            return execCmdByShell(Arrays.asList(cmds));
        }
     /**
         * 执行复杂shell命令
         * @param cmds 多条命令
         * @return 执行结果
         * @throws Exception 连接异常
         */
        public String execCmdByShell(List<String> cmds) throws Exception {
            String result = "";
            initChannelShell();
            InputStream inputStream = channelShell.getInputStream();
            channelShell.setPty(true);
            channelShell.connect();
            OutputStream outputStream = channelShell.getOutputStream();
            PrintWriter printWriter = new PrintWriter(outputStream);
            for (String cmd : cmds) {
                printWriter.println(cmd);
            }
            printWriter.flush();
            byte[] tmp = new byte[1024];
            while (true) {
                while (inputStream.available() > 0) {
                    int i = inputStream.read(tmp, 0, 1024);
                    if (i < 0) {
                        break;
                    }
                    String s = new String(tmp, 0, i);
                    if (s.contains("--More--")) {
                        outputStream.write((" ").getBytes());
                        outputStream.flush();
                    }
                    System.out.println(s);
                }
                if (channelShell.isClosed()) {
                    System.out.println("exit-status:" + channelShell.getExitStatus());
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            outputStream.close();
            inputStream.close();
            return result;
        }
    private void initChannelShell() throws Exception {
            // 打开执行shell指令的通道
            channel = session.openChannel("shell");
            channelShell = (ChannelShell) channel;
            if (session == null || channel == null || channelShell == null) {
                log.error("请先执行init()");
                throw new Exception("请先执行init()");
            }
        }
    

    3.5 完整工具类代码

    ShellUtil.java

    @Slf4j
    @Component
    @Slf4j
    @Component
    @Scope(value = "prototype")
    public class ShellUtil {
        @Value("${ssh.strictHostKeyChecking:no}")
        private String strictHostKeyChecking;
        @Value("${ssh.timeout:30000}")
        private Integer timeout;
        private Session session;
        private Channel channel;
        private ChannelExec channelExec;
        private ChannelSftp channelSftp;
        private ChannelShell channelShell;
        /**
         * 初始化
         *
         * @param ip       远程主机IP地址
         * @param port     远程主机端口
         * @param username 远程主机登陆用户名
         * @param password 远程主机登陆密码
         * @throws JSchException JSch异常
         */
        public void init(String ip, Integer port, String username, String password) throws JSchException {
            JSch jsch = new JSch();
            session = jsch.getSession(username, ip, port);
            session.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", strictHostKeyChecking);
            session.setConfig(sshConfig);
            session.connect(timeout);
            log.info("Session connected!");
        }
        public void init(String ip, String username, String password) throws JSchException {
            init(ip, 22, username, password);
        }
        /**
         * 连接多次执行命令,执行命令完毕后需要执行close()方法
         *
         * @param command 需要执行的指令
         * @return 执行结果
         * @throws Exception 没有执行初始化
         */
        public String execCmd(String command) throws Exception {
            initChannelExec();
            log.info("execCmd command - > {}", command);
            channelExec.setCommand(command);
            channel.setInputStream(null);
            channelExec.setErrStream(System.err);
            channel.connect();
            StringBuilder sb = new StringBuilder(16);
            try (InputStream in = channelExec.getInputStream();
                 InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);
                 BufferedReader reader = new BufferedReader(isr)) {
                String buffer;
                while ((buffer = reader.readLine()) != null) {
                    sb.append("\n").append(buffer);
                }
                log.info("execCmd result - > {}", sb);
                return sb.toString();
            }
        }
        /**
         * 执行命令关闭连接
         *
         * @param command 需要执行的指令
         * @return 执行结果
         * @throws Exception 没有执行初始化
         */
        public String execCmdAndClose(String command) throws Exception {
            String result = execCmd(command);
            close();
            return result;
        }
        /**
         * 执行复杂shell命令
         *
         * @param cmds 多条命令
         * @return 执行结果
         * @throws Exception 连接异常
         */
        public String execCmdByShell(String... cmds) throws Exception {
            return execCmdByShell(Arrays.asList(cmds));
        }
        /**
         * 执行复杂shell命令
         *
         * @param cmds 多条命令
         * @return 执行结果
         * @throws Exception 连接异常
         */
        public String execCmdByShell(List<String> cmds) throws Exception {
            String result = "";
            initChannelShell();
            InputStream inputStream = channelShell.getInputStream();
            channelShell.setPty(true);
            channelShell.connect();
            OutputStream outputStream = channelShell.getOutputStream();
            PrintWriter printWriter = new PrintWriter(outputStream);
            for (String cmd : cmds) {
                printWriter.println(cmd);
            }
            printWriter.flush();
            byte[] tmp = new byte[1024];
            while (true) {
                while (inputStream.available() > 0) {
                    int i = inputStream.read(tmp, 0, 1024);
                    if (i < 0) {
                        break;
                    }
                    String s = new String(tmp, 0, i);
                    if (s.contains("--More--")) {
                        outputStream.write((" ").getBytes());
                        outputStream.flush();
                    }
                    System.out.println(s);
                }
                if (channelShell.isClosed()) {
                    System.out.println("exit-status:" + channelShell.getExitStatus());
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            outputStream.close();
            inputStream.close();
            return result;
        }
        /**
         * SFTP文件上传
         *
         * @param src 源地址
         * @param dst 目的地址
         * @throws Exception 上传文件失败
         */
        public void putAndClose(String src, String dst) throws Exception {
            putAndClose(src, dst, ChannelSftp.OVERWRITE);
        }
        /**
         * SFTP文件上传
         *
         * @param src  源地址
         * @param dst  目的地址
         * @param mode 上传模式 默认为ChannelSftp.OVERWRITE
         * @throws Exception 上传文件失败
         */
        public void putAndClose(String src, String dst, int mode) throws Exception {
            put(src, dst, mode);
            close();
        }
        public void put(String src, String dst) throws Exception {
            put(src, dst, ChannelSftp.OVERWRITE);
        }
        public void put(String src, String dst, int mode) throws Exception {
            initChannelSftp();
            log.info("Upload File {} -> {}", src, dst);
            channelSftp.put(src, dst, mode);
            log.info("Upload File Success!");
        }
        /**
         * SFTP文件上传并监控上传进度
         *
         * @param src 源地址
         * @param dst 目的地址
         * @throws Exception 上传文件失败
         */
        public void putMonitorAndClose(String src, String dst) throws Exception {
            putMonitorAndClose(src, dst, ChannelSftp.OVERWRITE);
        }
        /**
         * SFTP文件上传并监控上传进度
         *
         * @param src  源地址
         * @param dst  目的地址
         * @param mode 上传模式 默认为ChannelSftp.OVERWRITE
         * @throws Exception 上传文件失败
         */
        public void putMonitorAndClose(String src, String dst, int mode) throws Exception {
            initChannelSftp();
            FileProgressMonitor monitor = new FileProgressMonitor(new File(src).length());
            log.info("Upload File {} -> {}", src, dst);
            channelSftp.put(src, dst, monitor, mode);
            log.info("Upload File Success!");
            close();
        }
        /**
         * SFTP文件下载
         *
         * @param src 源文件地址
         * @param dst 目的地址
         * @throws Exception 下载文件失败
         */
        public void getAndClose(String src, String dst) throws Exception {
            get(src,dst);
            close();
        }
        public void get(String src, String dst) throws Exception {
            initChannelSftp();
            log.info("Download File {} -> {}", src, dst);
            channelSftp.get(src, dst);
            log.info("Download File Success!");
        }
        /**
         * SFTP文件下载并监控下载进度
         *
         * @param src 源文件地址
         * @param dst 目的地址
         * @throws Exception 下载文件失败
         */
        public void getMonitorAndClose(String src, String dst) throws Exception {
            initChannelSftp();
            FileProgressMonitor monitor = new FileProgressMonitor(new File(src).length());
            log.info("Download File {} -> {}", src, dst);
            channelSftp.get(src, dst, monitor);
            log.info("Download File Success!");
            close();
        }
        /**
         * 删除指定目录文件
         *
         * @param path 删除路径
         * @throws Exception 远程主机连接异常
         */
        public void deleteFile(String path) throws Exception {
            initChannelSftp();
            channelSftp.rm(path);
            log.info("Delete File {}", path);
        }
        /**
         * 删除指定目录
         *
         * @param path 删除路径
         * @throws Exception 远程主机连接异常
         */
        public void deleteDir(String path) throws Exception {
            initChannelSftp();
            channelSftp.rmdir(path);
            log.info("Delete Dir {} ", path);
        }
        /**
         * 释放资源
         */
        public void close() {
            if (channelSftp != null && channelSftp.isConnected()) {
                channelSftp.disconnect();
            }
            if (channelExec != null && channelExec.isConnected()) {
                channelExec.disconnect();
            }
            if (channel != null && channel.isConnected()) {
                channel.disconnect();
            }
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }
        private void initChannelSftp() throws Exception {
            channel = session.openChannel("sftp");
            channel.connect(); // 建立SFTP通道的连接
            channelSftp = (ChannelSftp) channel;
            if (session == null || channel == null || channelSftp == null) {
                log.error("请先执行init()");
                throw new Exception("请先执行init()");
            }
        }
        private void initChannelExec() throws Exception {
            // 打开执行shell指令的通道
            channel = session.openChannel("exec");
            channelExec = (ChannelExec) channel;
            if (session == null || channel == null || channelExec == null) {
                log.error("请先执行init()");
                throw new Exception("请先执行init()");
            }
        }
        private void initChannelShell() throws Exception {
            // 打开执行shell指令的通道
            channel = session.openChannel("shell");
            channelShell = (ChannelShell) channel;
            if (session == null || channel == null || channelShell == null) {
                log.error("请先执行init()");
                throw new Exception("请先执行init()");
            }
        }
    }
    

    FileProgressMonitor.java

    @Slf4j
    public class FileProgressMonitor extends TimerTask implements SftpProgressMonitor {
        private boolean isEnd = false;
        private long transfered;
        private long fileSize;
        private ScheduledExecutorService executorService;
        private boolean isScheduled = false;
        long startTime = 0L;
        public FileProgressMonitor(long fileSize) {
            this.fileSize = fileSize;
        }
        @Override
        public void run() {
            if (!isEnd()) {
                log.info("Transfering is in progress.");
                long transfered = getTransfered();
                // 判断当前已传输数据大小是否等于文件总大小
                if (transfered != fileSize) {
                    log.info("Current transfered: {} bytes", transfered);
                    sendProgressMessage(transfered);
                } else {
                    // 如果当前已传输数据大小等于文件总大小,说明已完成,设置end
                    log.info("File transfering is done.");
                    setEnd(true);
                }
            } else {
                log.info("Transfering done. Cancel timer.");
                // 如果传输结束,停止timer记时器
                stop();
                return;
            }
        }
        /**
         * 实现了SftpProgressMonitor接口的count方法
         */
        @Override
        public boolean count(long count) {
            if (isEnd()) {
                return false;
            }
            if (!isScheduled) {
                start();
            }
            add(count);
            return true;
        }
        /**
         * 实现了SftpProgressMonitor接口的end方法
         */
        @Override
        public void end() {
            setEnd(true);
            log.info("transfering end. time ->{} s", (System.currentTimeMillis() - startTime) / 1000);
        }
        @Override
        public void init(int op, String src, String dest, long max) {
            startTime = System.currentTimeMillis();
        }
        public void stop() {
            log.info("Try to stop progress monitor.");
            boolean isShutdown = executorService.isShutdown();
            if (!isShutdown) {
                executorService.shutdown();
            }
            log.info("Progress monitor stoped.");
        }
        public void start() {
            log.info("Try to start progress monitor.");
            executorService = new ScheduledThreadPoolExecutor(1);
            //1秒钟后开始执行,每2杪钟执行一次
            executorService.scheduleWithFixedDelay(this, 1, 1, TimeUnit.SECONDS);
            isScheduled = true;
            log.info("Progress monitor started.");
        }
        /**
         * 打印progress信息
         *
         * @param transfered
         */
        private void sendProgressMessage(long transfered) {
            if (fileSize != 0) {
                double d = ((double) transfered * 100) / (double) fileSize;
                DecimalFormat df = new DecimalFormat("#.##");
                log.info("Sending progress message: {} %", df.format(d));
            } else {
                log.info("Sending progress message: {}", transfered);
            }
        }
        private synchronized void add(long count) {
            transfered = transfered + count;
        }
        private synchronized long getTransfered() {
            return transfered;
        }
        public synchronized void setTransfered(long transfered) {
            this.transfered = transfered;
        }
        private synchronized void setEnd(boolean isEnd) {
            this.isEnd = isEnd;
        }
        private synchronized boolean isEnd() {
            return isEnd;
        }
    }
    

    4. 使用连接池

    jsch连接池

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持自由互联。

    上一篇:JPA原生SQL实现增删改查的示例详解
    下一篇:没有了
    网友评论