關(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 | 恢復(fù)模式,如果文件已經(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í)行復(fù)雜shell命令
* @param cmds 多條命令
* @return 執(zhí)行結(jié)果
* @throws Exception 連接異常
*/
public String execCmdByShell(String... cmds)throws Exception{
return execCmdByShell(Arrays.asList(cmds));
}
/**
* 執(zhí)行復(fù)雜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í)行復(fù)雜shell命令
*
* @param cmds 多條命令
* @return 執(zhí)行結(jié)果
* @throws Exception 連接異常
*/
public String execCmdByShell(String... cmds) throws Exception {
return execCmdByShell(Arrays.asList(cmds));
}
/**
* 執(zhí)行復(fù)雜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)文章
給JavaBean賦默認值并且轉(zhuǎn)Json字符串的實例
這篇文章主要介紹了給JavaBean賦默認值并且轉(zhuǎn)Json字符串的實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringBoot+WebSocket實現(xiàn)消息推送功能
WebSocket協(xié)議是基于TCP的一種新的網(wǎng)絡(luò)協(xié)議。本文將通過SpringBoot集成WebSocket實現(xiàn)消息推送功能,感興趣的可以了解一下2022-08-08
源碼分析Spring?中?@Qualifier?注解基本用法
這篇文章主要介紹了源碼分析Spring?中?@Qualifier?注解基本用法,在源碼分析的過程中,也?GET?到?Spring?許多新的玩法,感興趣的小伙伴趕緊去試試吧2023-08-08
SpringBoot @ModelAttribute使用場景分析
這篇文章主要介紹了SpringBoot @ModelAttribute使用場景分析,文中通過實例代碼圖文相結(jié)合給大家介紹的非常詳細,需要的朋友可以參考下2021-08-08
Eclipse中創(chuàng)建Web項目最新方法(2023年)
在Java開發(fā)人員中,最常用的開發(fā)工具應(yīng)該就是Eclipse,下面這篇文章主要給大家介紹了關(guān)于Eclipse中創(chuàng)建Web項目2023年最新的方法,需要的朋友可以參考下2023-09-09
Spring動態(tài)加載bean后調(diào)用實現(xiàn)方法解析
這篇文章主要介紹了Spring動態(tài)加載bean后調(diào)用實現(xiàn)方法解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-08-08

