關(guān)于Springboot中JSCH的使用及說明
1. JSCH簡介
JSch 是SSH2的一個純Java實現(xiàn)。它允許你連接到一個sshd 服務(wù)器,使用端口轉(zhuǎn)發(fā),X11轉(zhuǎn)發(fā),文件傳輸?shù)鹊取?/p>
你可以將它的功能集成到你自己的 程序中。同時該項目也提供一個J2ME版本用來在手機上直連SSHD服務(wù)器。
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使用說明
/** * 連接多次執(zhí)行命令,執(zhí)行命令完畢后需要執(zhí)行close()方法 * * @param command 需要執(zhí)行的指令 * @return 執(zhí)行結(jié)果 * @throws Exception 沒有執(zhí)行初始化 */ public String execCmd(String command) throws Exception { // 打開執(zhí)行shell指令的通道 channel = session.openChannel("exec"); channelExec = (ChannelExec) channel; if (session == null || channel == null || channelExec == null) { log.error("請先執(zhí)行init()"); throw new Exception("請先執(zhí)行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(); } } /** * 執(zhí)行命令關(guān)閉連接 * @param command 需要執(zhí)行的指令 * @return 執(zhí)行結(jié)果 * @throws Exception 沒有執(zhí)行初始化 */ 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實現(xiàn)SFTP核心類,它包含了所有SFTP的方法,如:
put()
: 文件上傳get()
: 文件下載cd()
: 進入指定目錄ls()
: 得到指定目錄下的文件列表rename()
: 重命名指定文件或目錄rm()
: 刪除指定文件mkdir()
: 創(chuàng)建目錄rmdir()
: 刪除目錄
3.3.2 JSch支持三種文件傳輸模式:
模式 | 描述 |
---|---|
OVERWRITE | 完全覆蓋模式,這是JSch的默認文件傳輸模式,即如果目標文件已經(jīng)存在,傳輸?shù)奈募⑼耆采w目標文件,產(chǎn)生新的文件。 |
RESUME | 恢復模式,如果文件已經(jīng)傳輸一部分,這時由于網(wǎng)絡(luò)或其他任何原因?qū)е挛募鬏斨袛?,如果下一次傳輸相同的文件,則會從上一次中斷的地方續(xù)傳。 |
APPEND | 追加模式,如果目標文件已存在,傳輸?shù)奈募⒃谀繕宋募笞芳印?/td> |
3.3.3 文件上傳
實現(xiàn)文件上傳可以調(diào)用ChannelSftp對象的put方法。ChannelSftp中有12個put方法的重載方法:
方法 | 描述 |
---|---|
public void put(String src, String dst) | 將本地文件名為src的文件上傳到目標服務(wù)器,目標文件名為dst,若dst為目錄,則目標文件名將與src文件名相同。采用默認的傳輸模式:OVERWRITE |
public void put(String src, String dst, int mode) | 將本地文件名為src的文件上傳到目標服務(wù)器,目標文件名為dst,若dst為目錄,則目標文件名將與src文件名相同。指定文件傳輸模式為mode(mode可選值為:ChannelSftp.OVERWRITE,ChannelSftp.RESUME,ChannelSftp.APPEND) |
public void put(String src, String dst, SftpProgressMonitor monitor) | 將本地文件名為src的文件上傳到目標服務(wù)器,目標文件名為dst,若dst為目錄,則目標文件名將與src文件名相同。采用默認的傳輸模式:OVERWRITE,并使用實現(xiàn)了SftpProgressMonitor接口的monitor對象來監(jiān)控文件傳輸?shù)倪M度。 |
public void put(String src, String dst,SftpProgressMonitor monitor, int mode) | 將本地文件名為src的文件上傳到目標服務(wù)器,目標文件名為dst,若dst為目錄,則目標文件名將與src文件名相同。指定傳輸模式為mode,并使用實現(xiàn)了SftpProgressMonitor接口的monitor對象來監(jiān)控文件傳輸?shù)倪M度。 |
public void put(InputStream src, String dst) | 將本地的input stream對象src上傳到目標服務(wù)器,目標文件名為dst,dst不能為目錄。采用默認的傳輸模式:OVERWRITE |
public void put(InputStream src, String dst, int mode) | 將本地的input stream對象src上傳到目標服務(wù)器,目標文件名為dst,dst不能為目錄。指定文件傳輸模式為mode |
public void put(InputStream src, String dst, SftpProgressMonitor monitor) | 將本地的input stream對象src上傳到目標服務(wù)器,目標文件名為dst,dst不能為目錄。采用默認的傳輸模式:OVERWRITE,并使用實現(xiàn)了SftpProgressMonitor接口的monitor對象來監(jiān)控傳輸?shù)倪M度。 |
public void put(InputStream src, String dst,SftpProgressMonitor monitor, int mode) | 將本地的input stream對象src上傳到目標服務(wù)器,目標文件名為dst,dst不能為目錄。指定文件傳輸模式為mode,并使用實現(xiàn)了SftpProgressMonitor接口的monitor對象來監(jiān)控傳輸?shù)倪M度。 |
public OutputStream put(String dst) | 該方法返回一個輸出流,可以向該輸出流中寫入數(shù)據(jù),最終將數(shù)據(jù)傳輸?shù)侥繕朔?wù)器,目標文件名為dst,dst不能為目錄。采用默認的傳輸模式:OVERWRITE |
public OutputStream put(String dst, final int mode) | 該方法返回一個輸出流,可以向該輸出流中寫入數(shù)據(jù),最終將數(shù)據(jù)傳輸?shù)侥繕朔?wù)器,目標文件名為dst,dst不能為目錄。指定文件傳輸模式為mode |
public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode) | 該方法返回一個輸出流,可以向該輸出流中寫入數(shù)據(jù),最終將數(shù)據(jù)傳輸?shù)侥繕朔?wù)器,目標文件名為dst,dst不能為目錄。指定文件傳輸模式為mode,并使用實現(xiàn)了SftpProgressMonitor接口的monitor對象來監(jiān)控傳輸?shù)倪M度。 |
public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode, long offset) | 該方法返回一個輸出流,可以向該輸出流中寫入數(shù)據(jù),最終將數(shù)據(jù)傳輸?shù)侥繕朔?wù)器,目標文件名為dst,dst不能為目錄。指定文件傳輸模式為mode,并使用實現(xiàn)了SftpProgressMonitor接口的monitor對象來監(jiān)控傳輸?shù)倪M度。offset指定了一個偏移量,從輸出流偏移offset開始寫入數(shù)據(jù)。 |
/** * 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文件上傳并監(jiān)控上傳進度 * * @param src 源地址 * @param dst 目的地址 * @throws Exception 上傳文件失敗 */ public void putMonitorAndClose(String src, String dst) throws Exception { putMonitorAndClose(src, dst, ChannelSftp.OVERWRITE); } /** * SFTP文件上傳并監(jiān)控上傳進度 * * @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("請先執(zhí)行init()"); throw new Exception("請先執(zhí)行init()"); } } }
3.3.4 文件下載
JSch文件下載是通過調(diào)用ChannelSftp對象的get方法來實現(xiàn)的。ChannelSftp中有9個get方法的重載方法:
方法 | 描述 |
---|---|
publicvoid get(String src, String dst) | 將目標服務(wù)器上文件名為src的文件下載到本地,本地文件名為dst。若dst為目錄,則下載到本地的文件名將與src文件名相同。(注:src必須是文件,不能為目錄),采用默認的傳輸模式:OVERWRITE |
publicvoid get(String src, String dst, SftpProgressMonitor monitor) | 將目標服務(wù)器上文件名為src的文件下載到本地,本地文件名為dst。若dst為目錄,則下載到本地的文件名將與src文件名相同。(注:src必須是文件,不能為目錄),采用默認的傳輸模式:OVERWRITE |
publicvoid get(String src, String dst,SftpProgressMonitor monitor, int mode) | 將目標服務(wù)器上文件名為src的文件下載到本地,本地文件名為dst。若dst為目錄,則下載到本地的文件名將與src文件名相同。(注:src必須是文件,不能為目錄)指定文件傳輸模式為mode(mode可選值為:ChannelSftp.OVERWRITE,ChannelSftp.RESUME,ChannelSftp.APPEND),并使用實現(xiàn)了SftpProgressMonitor接口的monitor對象來監(jiān)控文件的傳輸進度。 |
publicvoid get(String src, OutputStream dst) | 將目標服務(wù)器上文件名為src的文件下載到本地,下載的數(shù)據(jù)寫入到輸出流對象dst(如:文件輸出流)。采用默認的傳輸模式:OVERWRITE |
publicvoid get(String src, OutputStream dst, SftpProgressMonitor monitor) | 將目標服務(wù)器上文件名為src的文件下載到本地,下載的數(shù)據(jù)寫入到輸出流對象dst(如:文件輸出流)。采用默認的傳輸模式:OVERWRITE,并使用實現(xiàn)了SftpProgressMonitor接口的monitor對象來監(jiān)控文件的傳輸進度。 |
publicvoid get(String src, OutputStream dst, SftpProgressMonitor monitor, int mode, long skip) | 將目標服務(wù)器上文件名為src的文件下載到本地,下載的數(shù)據(jù)寫入到輸出流對象dst(如:文件輸出流)。指定文件傳輸模式為mode并使用實現(xiàn)了SftpProgressMonitor接口的monitor對象來監(jiān)控文件的傳輸進度。skip指定了一個跳讀量,即下載時從src文件跳過skip字節(jié)的數(shù)據(jù)。(一般不推薦使用該參數(shù),默認設(shè)為0) |
public InputStream get(String src) | 該方法返回一個輸入流,該輸入流含有目標服務(wù)器上文件名為src的文件數(shù)據(jù)??梢詮脑撦斎肓髦凶x取數(shù)據(jù),最終將數(shù)據(jù)傳輸?shù)奖镜兀ㄈ纾鹤x取數(shù)據(jù)后將數(shù)據(jù)寫入到本地的文件中)(注:該方法不支持多種文件傳輸模式,如何讀取與保存數(shù)據(jù)由應(yīng)用程序自己確定) |
public InputStream get(String src, SftpProgressMonitor monitor) | 該方法返回一個輸入流,該輸入流含有目標服務(wù)器上文件名為src的文件數(shù)據(jù)??梢詮脑撦斎肓髦凶x取數(shù)據(jù),最終將數(shù)據(jù)傳輸?shù)奖镜兀ㄈ纾鹤x取數(shù)據(jù)后將數(shù)據(jù)寫入到本地的文件中)并使用實現(xiàn)了SftpProgressMonitor接口的monitor對象來監(jiān)控文件的傳輸進度。(注:該方法不支持多種文件傳輸模式,如何讀取與保存數(shù)據(jù)由應(yīng)用程序自己確定) |
public InputStream get(String src, final SftpProgressMonitor monitor, finallong skip) | 該方法返回一個輸入流,該輸入流含有目標服務(wù)器上文件名為src的文件數(shù)據(jù)??梢詮脑撦斎肓髦凶x取數(shù)據(jù),最終將數(shù)據(jù)傳輸?shù)奖镜兀ㄈ纾鹤x取數(shù)據(jù)后將數(shù)據(jù)寫入到本地的文件中)并使用實現(xiàn)了SftpProgressMonitor接口的monitor對象來監(jiān)控文件的傳輸進度。(注:該方法不支持多種文件傳輸模式,如何讀取與保存數(shù)據(jù)由應(yīng)用程序自己確定)skip指定了一個跳讀量,即下載時從src文件跳過skip字節(jié)的數(shù)據(jù)。(一般不推薦使用該參數(shù),默認設(shè)為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代碼
/** * 執(zhí)行復雜shell命令 * @param cmds 多條命令 * @return 執(zhí)行結(jié)果 * @throws Exception 連接異常 */ public String execCmdByShell(String... cmds)throws Exception{ return execCmdByShell(Arrays.asList(cmds)); } /** * 執(zhí)行復雜shell命令 * @param cmds 多條命令 * @return 執(zhí)行結(jié)果 * @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 { // 打開執(zhí)行shell指令的通道 channel = session.openChannel("shell"); channelShell = (ChannelShell) channel; if (session == null || channel == null || channelShell == null) { log.error("請先執(zhí)行init()"); throw new Exception("請先執(zhí)行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); } /** * 連接多次執(zhí)行命令,執(zhí)行命令完畢后需要執(zhí)行close()方法 * * @param command 需要執(zhí)行的指令 * @return 執(zhí)行結(jié)果 * @throws Exception 沒有執(zhí)行初始化 */ 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(); } } /** * 執(zhí)行命令關(guān)閉連接 * * @param command 需要執(zhí)行的指令 * @return 執(zhí)行結(jié)果 * @throws Exception 沒有執(zhí)行初始化 */ public String execCmdAndClose(String command) throws Exception { String result = execCmd(command); close(); return result; } /** * 執(zhí)行復雜shell命令 * * @param cmds 多條命令 * @return 執(zhí)行結(jié)果 * @throws Exception 連接異常 */ public String execCmdByShell(String... cmds) throws Exception { return execCmdByShell(Arrays.asList(cmds)); } /** * 執(zhí)行復雜shell命令 * * @param cmds 多條命令 * @return 執(zhí)行結(jié)果 * @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文件上傳并監(jiān)控上傳進度 * * @param src 源地址 * @param dst 目的地址 * @throws Exception 上傳文件失敗 */ public void putMonitorAndClose(String src, String dst) throws Exception { putMonitorAndClose(src, dst, ChannelSftp.OVERWRITE); } /** * SFTP文件上傳并監(jiān)控上傳進度 * * @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文件下載并監(jiān)控下載進度 * * @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("請先執(zhí)行init()"); throw new Exception("請先執(zhí)行init()"); } } private void initChannelExec() throws Exception { // 打開執(zhí)行shell指令的通道 channel = session.openChannel("exec"); channelExec = (ChannelExec) channel; if (session == null || channel == null || channelExec == null) { log.error("請先執(zhí)行init()"); throw new Exception("請先執(zhí)行init()"); } } private void initChannelShell() throws Exception { // 打開執(zhí)行shell指令的通道 channel = session.openChannel("shell"); channelShell = (ChannelShell) channel; if (session == null || channel == null || channelShell == null) { log.error("請先執(zhí)行init()"); throw new Exception("請先執(zhí)行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(); // 判斷當前已傳輸數(shù)據(jù)大小是否等于文件總大小 if (transfered != fileSize) { log.info("Current transfered: {} bytes", transfered); sendProgressMessage(transfered); } else { // 如果當前已傳輸數(shù)據(jù)大小等于文件總大小,說明已完成,設(shè)置end log.info("File transfering is done."); setEnd(true); } } else { log.info("Transfering done. Cancel timer."); // 如果傳輸結(jié)束,停止timer記時器 stop(); return; } } /** * 實現(xiàn)了SftpProgressMonitor接口的count方法 */ @Override public boolean count(long count) { if (isEnd()) { return false; } if (!isScheduled) { start(); } add(count); return true; } /** * 實現(xiàn)了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秒鐘后開始執(zhí)行,每2杪鐘執(zhí)行一次 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. 使用連接池
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Java中String,StringBuffer和StringBuilder的使用
這篇文章主要為大家詳細介紹了Java中String,StringBuffer和StringBuilder三者的區(qū)別以及使用,文中的少了講解詳細,感興趣的可以了解一下2022-07-07Spring系列中的beanFactory與ApplicationContext
這篇文章主要介紹了Spring系列中的beanFactory與ApplicationContext,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-09-09SpringBoot集成Zipkin實現(xiàn)分布式全鏈路監(jiān)控
這篇文章主要介紹了SpringBoot集成Zipkin實現(xiàn)分布式全鏈路監(jiān)控的方法啊,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09java枚舉類的屬性、方法和構(gòu)造方法應(yīng)用實戰(zhàn)
這篇文章主要介紹了java枚舉類的屬性、方法和構(gòu)造方法應(yīng)用,結(jié)合實例形式分析了java枚舉類的定義、構(gòu)造及相關(guān)應(yīng)用操作技巧,需要的朋友可以參考下2019-08-08SpringBoot使用Prometheus采集自定義指標數(shù)據(jù)的方法詳解
隨著微服務(wù)在生產(chǎn)環(huán)境大規(guī)模部署和應(yīng)用,隨之而來也帶來了新的問題,其中比較關(guān)鍵的就是關(guān)于微服務(wù)的運維和監(jiān)控,本文將結(jié)合微服務(wù)運維監(jiān)控中的指標監(jiān)控進行詳細的說明,需要的朋友可以參考下2024-07-07