当前位置:   article > 正文

Spring Boot集成JSch快速入门demo

Spring Boot集成JSch快速入门demo

1.JSch介绍

JSch是SSH2的纯Java实现。JSch允许您连接到sshd服务器并使用端口转发,X11转发,文件传输等,并且可以将其功能集成到您自己的Java程序中。

2.实现原理

  • 根据远程主机的IP地址,用户名和端口,建立会话(Session)

  • 设置用户信息(包括密码和Userinfo),然后连接session,getSession()只是创建一个session,需要设置必要的认证信息之后,调用connect()才能建立连接。

  • 设置channel上需要远程执行的Shell脚本,连接channel,就可以远程执行该Shell脚本,调用openChannel(String type) 可以在session上打开指定类型的channel。该channel只是被初始化,使用前需要先调用connect()进行连接。

  • 可以读取远程执行Shell脚本的输出,然后依次断开channel和session的连接

3.代码工程

实验目标:实现文件上传到服务,服务器下载文件以及执行服务器命令 

pom.xml

 
 
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>springboot-demo</artifactId>
  7. <groupId>com.et</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>JSch</artifactId>
  12. <properties>
  13. <maven.compiler.source>8</maven.compiler.source>
  14. <maven.compiler.target>8</maven.compiler.target>
  15. </properties>
  16. <dependencies>
  17. <dependency>
  18. <groupId>org.springframework.boot</groupId>
  19. <artifactId>spring-boot-starter-web</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>org.springframework.boot</groupId>
  23. <artifactId>spring-boot-autoconfigure</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter-test</artifactId>
  28. <scope>test</scope>
  29. </dependency>
  30. <!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
  31. <dependency>
  32. <groupId>com.jcraft</groupId>
  33. <artifactId>jsch</artifactId>
  34. <version>0.1.55</version>
  35. </dependency>
  36. <dependency>
  37. <groupId>org.projectlombok</groupId>
  38. <artifactId>lombok</artifactId>
  39. </dependency>
  40. <dependency>
  41. <groupId>com.alibaba</groupId>
  42. <artifactId>fastjson</artifactId>
  43. <version>1.2.78</version>
  44. </dependency>
  45. </dependencies>
  46. </project>

remote.java

 
 
  1. package com.et.jsch.model;
  2. import lombok.Data;
  3. @Data
  4. public class Remote {
  5. private String host;
  6. private final int port = 22;
  7. private String user;
  8. private String password;
  9. private final String identity = "~/.ssh/id_rsa";
  10. private String passphrase;
  11. }

JSchUtil.java

 
 
  1. package com.et.jsch.util;
  2. import com.et.jsch.model.Remote;
  3. import com.jcraft.jsch.*;
  4. import lombok.extern.slf4j.Slf4j;
  5. import java.io.*;
  6. import java.nio.file.Files;
  7. import java.nio.file.Paths;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10. import java.util.function.Function;
  11. /**
  12. * ssh tools
  13. */
  14. @Slf4j
  15. public class JSchUtil {
  16. public static final int SESSION_TIMEOUT = 30000;
  17. public static final int CONNECT_TIMEOUT = 3000;
  18. /**
  19. * get session
  20. *
  21. * @param remote ssh server info
  22. * @return session
  23. * @throws JSchException /
  24. */
  25. public static Session getSession(Remote remote) throws JSchException {
  26. JSch jSch = new JSch();
  27. if (Files.exists(Paths.get(remote.getIdentity()))) {
  28. jSch.addIdentity(remote.getIdentity(), remote.getPassphrase());
  29. }
  30. Session session = jSch.getSession(remote.getUser(), remote.getHost(), remote.getPort());
  31. session.setPassword(remote.getPassword());
  32. session.setConfig("StrictHostKeyChecking", "no");
  33. return session;
  34. }
  35. /**
  36. * excute remote command
  37. *
  38. * @param session session
  39. * @param command command
  40. * @return /
  41. * @throws JSchException /
  42. */
  43. public static List<String> remoteExecute(Session session, String command) throws JSchException {
  44. log.debug(">> {}", command);
  45. List<String> resultLines = new ArrayList<>();
  46. ChannelExec channel = null;
  47. try {
  48. channel = openExecChannel(session);
  49. channel.setCommand(command);
  50. InputStream input = channel.getInputStream();
  51. channel.connect(CONNECT_TIMEOUT);
  52. try {
  53. BufferedReader inputReader = new BufferedReader(new InputStreamReader(input));
  54. String inputLine;
  55. while ((inputLine = inputReader.readLine()) != null) {
  56. log.debug(" {}", inputLine);
  57. resultLines.add(inputLine);
  58. }
  59. } finally {
  60. if (input != null) {
  61. try {
  62. input.close();
  63. } catch (Exception e) {
  64. log.error("JSch inputStream close error:", e);
  65. }
  66. }
  67. }
  68. } catch (IOException e) {
  69. log.error("IOException:", e);
  70. } finally {
  71. disconnect(channel);
  72. }
  73. return resultLines;
  74. }
  75. /**
  76. * scp file to remote server
  77. *
  78. * @param session session
  79. * @param source local file
  80. * @param destination remote target file
  81. * @return file size
  82. */
  83. public static long scpTo(Session session, String source, String destination) {
  84. FileInputStream fileInputStream = null;
  85. ChannelExec channel = null;
  86. try {
  87. channel = openExecChannel(session);
  88. OutputStream out = channel.getOutputStream();
  89. InputStream in = channel.getInputStream();
  90. boolean ptimestamp = false;
  91. String command = "scp";
  92. if (ptimestamp) {
  93. command += " -p";
  94. }
  95. command += " -t " + destination;
  96. channel.setCommand(command);
  97. channel.connect(CONNECT_TIMEOUT);
  98. if (checkAck(in) != 0) {
  99. return -1;
  100. }
  101. File _lfile = new File(source);
  102. if (ptimestamp) {
  103. command = "T " + (_lfile.lastModified() / 1000) + " 0";
  104. // The access time should be sent here,
  105. // but it is not accessible with JavaAPI ;-<
  106. command += (" " + (_lfile.lastModified() / 1000) + " 0\n");
  107. out.write(command.getBytes());
  108. out.flush();
  109. if (checkAck(in) != 0) {
  110. return -1;
  111. }
  112. }
  113. //send "C0644 filesize filename", where filename should not include '/'
  114. long fileSize = _lfile.length();
  115. command = "C0644 " + fileSize + " ";
  116. if (source.lastIndexOf('/') > 0) {
  117. command += source.substring(source.lastIndexOf('/') + 1);
  118. } else {
  119. command += source;
  120. }
  121. command += "\n";
  122. out.write(command.getBytes());
  123. out.flush();
  124. if (checkAck(in) != 0) {
  125. return -1;
  126. }
  127. //send content of file
  128. fileInputStream = new FileInputStream(source);
  129. byte[] buf = new byte[1024];
  130. long sum = 0;
  131. while (true) {
  132. int len = fileInputStream.read(buf, 0, buf.length);
  133. if (len <= 0) {
  134. break;
  135. }
  136. out.write(buf, 0, len);
  137. sum += len;
  138. }
  139. //send '\0'
  140. buf[0] = 0;
  141. out.write(buf, 0, 1);
  142. out.flush();
  143. if (checkAck(in) != 0) {
  144. return -1;
  145. }
  146. return sum;
  147. } catch (JSchException e) {
  148. log.error("scp to caught jsch exception, ", e);
  149. } catch (IOException e) {
  150. log.error("scp to caught io exception, ", e);
  151. } catch (Exception e) {
  152. log.error("scp to error, ", e);
  153. } finally {
  154. closeInputStream(fileInputStream);
  155. disconnect(channel);
  156. }
  157. return -1;
  158. }
  159. /**
  160. * scp remote file to local
  161. *
  162. * @param session session
  163. * @param source remote file
  164. * @param destination local file
  165. * @return file size
  166. */
  167. public static long scpFrom(Session session, String source, String destination) {
  168. FileOutputStream fileOutputStream = null;
  169. ChannelExec channel = null;
  170. try {
  171. channel = openExecChannel(session);
  172. channel.setCommand("scp -f " + source);
  173. OutputStream out = channel.getOutputStream();
  174. InputStream in = channel.getInputStream();
  175. channel.connect();
  176. byte[] buf = new byte[1024];
  177. //send '\0'
  178. buf[0] = 0;
  179. out.write(buf, 0, 1);
  180. out.flush();
  181. while (true) {
  182. if (checkAck(in) != 'C') {
  183. break;
  184. }
  185. }
  186. //read '644 '
  187. in.read(buf, 0, 4);
  188. long fileSize = 0;
  189. while (true) {
  190. if (in.read(buf, 0, 1) < 0) {
  191. break;
  192. }
  193. if (buf[0] == ' ') {
  194. break;
  195. }
  196. fileSize = fileSize * 10L + (long) (buf[0] - '0');
  197. }
  198. String file = null;
  199. for (int i = 0; ; i++) {
  200. in.read(buf, i, 1);
  201. if (buf[i] == (byte) 0x0a) {
  202. file = new String(buf, 0, i);
  203. break;
  204. }
  205. }
  206. // send '\0'
  207. buf[0] = 0;
  208. out.write(buf, 0, 1);
  209. out.flush();
  210. // read a content of lfile
  211. if (Files.isDirectory(Paths.get(destination))) {
  212. fileOutputStream = new FileOutputStream(destination + File.separator + file);
  213. } else {
  214. fileOutputStream = new FileOutputStream(destination);
  215. }
  216. long sum = 0;
  217. while (true) {
  218. int len = in.read(buf, 0, buf.length);
  219. if (len <= 0) {
  220. break;
  221. }
  222. sum += len;
  223. if (len >= fileSize) {
  224. fileOutputStream.write(buf, 0, (int) fileSize);
  225. break;
  226. }
  227. fileOutputStream.write(buf, 0, len);
  228. fileSize -= len;
  229. }
  230. return sum;
  231. } catch (JSchException e) {
  232. log.error("scp to caught jsch exception, ", e);
  233. } catch (IOException e) {
  234. log.error("scp to caught io exception, ", e);
  235. } catch (Exception e) {
  236. log.error("scp to error, ", e);
  237. } finally {
  238. closeOutputStream(fileOutputStream);
  239. disconnect(channel);
  240. }
  241. return -1;
  242. }
  243. /**
  244. * remote edit
  245. *
  246. * @param session session
  247. * @param source target file
  248. * @param process edit command collect
  249. * @return isSuccess
  250. */
  251. private static boolean remoteEdit(Session session, String source, Function<List<String>, List<String>> process) {
  252. InputStream in = null;
  253. OutputStream out = null;
  254. try {
  255. String fileName = source;
  256. int index = source.lastIndexOf('/');
  257. if (index >= 0) {
  258. fileName = source.substring(index + 1);
  259. }
  260. //backup source
  261. remoteExecute(session, String.format("cp %s %s", source, source + ".bak." + System.currentTimeMillis()));
  262. //scp from remote
  263. String tmpSource = System.getProperty("java.io.tmpdir") + session.getHost() + "-" + fileName;
  264. scpFrom(session, source, tmpSource);
  265. in = new FileInputStream(tmpSource);
  266. //edit file according function process
  267. String tmpDestination = tmpSource + ".des";
  268. out = new FileOutputStream(tmpDestination);
  269. List<String> inputLines = new ArrayList<>();
  270. BufferedReader reader = new BufferedReader(new InputStreamReader(in));
  271. String inputLine = null;
  272. while ((inputLine = reader.readLine()) != null) {
  273. inputLines.add(inputLine);
  274. }
  275. List<String> outputLines = process.apply(inputLines);
  276. for (String outputLine : outputLines) {
  277. out.write((outputLine + "\n").getBytes());
  278. out.flush();
  279. }
  280. //scp to remote
  281. scpTo(session, tmpDestination, source);
  282. return true;
  283. } catch (Exception e) {
  284. log.error("remote edit error, ", e);
  285. return false;
  286. } finally {
  287. closeInputStream(in);
  288. closeOutputStream(out);
  289. }
  290. }
  291. /**
  292. * update file
  293. *
  294. * @param session session
  295. * @param in file stream
  296. * @param directory local dir
  297. * @param fileName FTP server file name:xxx.txt ||xxx.txt.zip
  298. */
  299. public static boolean uploadFile(Session session, InputStream in, String directory, String fileName) {
  300. log.info(">>>>>>>>uploadFile--ftp start>>>>>>>>>>>>>");
  301. ChannelSftp channel = null;
  302. try {
  303. channel = openSftpChannel(session);
  304. channel.connect(CONNECT_TIMEOUT);
  305. String[] folders = directory.split("/");
  306. try {
  307. for (int i = 0; i < folders.length; i++) {
  308. if (i == 0 && folders[i].length() == 0) {
  309. channel.cd("/");
  310. } else if (folders[i].length() > 0) {
  311. try {
  312. channel.cd(folders[i]);
  313. } catch (SftpException e) {
  314. channel.mkdir(folders[i]);
  315. channel.cd(folders[i]);
  316. }
  317. }
  318. }
  319. } catch (SftpException e) {
  320. log.error("ftp create file fail" + directory, e);
  321. return false;
  322. }
  323. try {
  324. channel.put(in, fileName);
  325. } catch (SftpException e) {
  326. log.error("sftp error-->" + e.getMessage(), e);
  327. return false;
  328. }
  329. log.info(">>>>>>>>uploadFile--ftp upload end>>>>>>>>>>>>>");
  330. log.info(">>>>>>>>ftp upload dir:{},filename:{}>>>>>>>>>>>>>", directory, fileName);
  331. return true;
  332. } catch (JSchException e) {
  333. log.error("JSch error-->" + e.getMessage(), e);
  334. return false;
  335. } finally {
  336. closeInputStream(in);
  337. disconnect(channel);
  338. }
  339. }
  340. /**
  341. *
  342. *
  343. * @param channel sftp connect
  344. * @param directory
  345. * @param fileName
  346. * @return
  347. */
  348. public static InputStream stream(ChannelSftp channel, String directory, String fileName) {
  349. try {
  350. channel.connect(CONNECT_TIMEOUT);
  351. InputStream inputStream = channel.get(directory + "/" + fileName);
  352. log.info(">>>>>>>>ftp file directory:{},filename:{}>>>>>>>>>>>>>", directory, fileName);
  353. return inputStream;
  354. } catch (SftpException e) {
  355. log.error("sftp error-->" + e.getMessage());
  356. return null;
  357. } catch (JSchException e) {
  358. log.error("JSch error-->" + e.getMessage());
  359. return null;
  360. }
  361. }
  362. /**
  363. * ftp delete remote file
  364. *
  365. * @param session session
  366. * @param directory directory
  367. * @param fileName filename
  368. * @return is Success
  369. */
  370. public static boolean deleteFile(Session session, String directory, String fileName) {
  371. log.info(">>>>>>>>deleteFile--ftp delete file end>>>>>>>>>>>>>");
  372. ChannelSftp channel = null;
  373. try {
  374. channel = openSftpChannel(session);
  375. channel.connect(CONNECT_TIMEOUT);
  376. channel.rm(directory + "/" + fileName);
  377. log.info(">>>>>>>>deleteFile--deletefile end>>>>>>>>>>>>>");
  378. log.info(">>>>>>>>ftp delete file directory:{},filename:{}>>>>>>>>>>>>>", directory, fileName);
  379. } catch (SftpException e) {
  380. log.error("ftp create directory fail" + directory);
  381. return false;
  382. } catch (JSchException e) {
  383. log.error("JSch error-->" + e.getMessage());
  384. return false;
  385. } finally {
  386. disconnect(channel);
  387. }
  388. return true;
  389. }
  390. public static Channel openChannel(Session session, String type) throws JSchException {
  391. if (!session.isConnected()) {
  392. session.connect(SESSION_TIMEOUT);
  393. }
  394. return session.openChannel(type);
  395. }
  396. public static ChannelSftp openSftpChannel(Session session) throws JSchException {
  397. return (ChannelSftp) openChannel(session, "sftp");
  398. }
  399. public static ChannelExec openExecChannel(Session session) throws JSchException {
  400. return (ChannelExec) openChannel(session, "exec");
  401. }
  402. /**
  403. * disconnect
  404. *
  405. * @param session
  406. */
  407. public static void disconnect(Session session) {
  408. if (session != null) {
  409. if (session.isConnected()) {
  410. try {
  411. session.disconnect();
  412. log.info("session disconnect successfully");
  413. } catch (Exception e) {
  414. log.error("JSch session disconnect error:", e);
  415. }
  416. }
  417. }
  418. }
  419. /**
  420. * close connection
  421. *
  422. * @param channel channel connection
  423. */
  424. public static void disconnect(Channel channel) {
  425. if (channel != null) {
  426. if (channel.isConnected()) {
  427. try {
  428. channel.disconnect();
  429. log.info("channel is closed already");
  430. } catch (Exception e) {
  431. log.error("JSch channel disconnect error:", e);
  432. }
  433. }
  434. }
  435. }
  436. public static int checkAck(InputStream in) throws IOException {
  437. int b = in.read();
  438. // b may be 0 for success,
  439. // 1 for error,
  440. // 2 for fatal error,
  441. // -1
  442. if (b == 0) {
  443. return b;
  444. }
  445. if (b == -1) {
  446. return b;
  447. }
  448. if (b == 1 || b == 2) {
  449. StringBuilder sb = new StringBuilder();
  450. int c;
  451. do {
  452. c = in.read();
  453. sb.append((char) c);
  454. }
  455. while (c != '\n');
  456. if (b == 1) { // error
  457. log.debug(sb.toString());
  458. }
  459. if (b == 2) { // fatal error
  460. log.debug(sb.toString());
  461. }
  462. }
  463. return b;
  464. }
  465. public static void closeInputStream(InputStream in) {
  466. if (in != null) {
  467. try {
  468. in.close();
  469. } catch (IOException e) {
  470. log.error("Close input stream error." + e.getMessage());
  471. }
  472. }
  473. }
  474. public static void closeOutputStream(OutputStream out) {
  475. if (out != null) {
  476. try {
  477. out.close();
  478. } catch (IOException e) {
  479. log.error("Close output stream error." + e.getMessage());
  480. }
  481. }
  482. }
  483. }

DemoApplication.java

 
 
  1. package com.et.jsch;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class DemoApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run(DemoApplication.class, args);
  8. }
  9. }

代码仓库

  • https://github.com/Harries/springboot-demo

4.测试

  1. import com.alibaba.fastjson.JSONObject;
  2. import com.et.jsch.DemoApplication;
  3. import com.et.jsch.model.Remote;
  4. import com.et.jsch.util.JSchUtil;
  5. import com.jcraft.jsch.JSchException;
  6. import com.jcraft.jsch.Session;
  7. import org.junit.After;
  8. import org.junit.Before;
  9. import org.junit.Test;
  10. import org.junit.runner.RunWith;
  11. import org.slf4j.Logger;
  12. import org.slf4j.LoggerFactory;
  13. import org.springframework.boot.test.context.SpringBootTest;
  14. import org.springframework.test.context.junit4.SpringRunner;
  15. import java.io.File;
  16. import java.io.FileInputStream;
  17. import java.io.FileNotFoundException;
  18. import java.io.InputStream;
  19. import java.util.List;
  20. @RunWith(SpringRunner.class)
  21. @SpringBootTest(classes = DemoApplication.class)
  22. public class JSchUtilTests {
  23. private Logger log = LoggerFactory.getLogger(getClass());
  24. Session session;
  25. @Before
  26. public void before() throws JSchException {
  27. Remote remote= new Remote();
  28. remote.setHost("xxx.xxx.xxx.xxx");
  29. remote.setUser("root");
  30. remote.setPassword("xxxx");
  31. session= JSchUtil.getSession(remote);
  32. }
  33. @After
  34. public void after(){
  35. JSchUtil.disconnect(session);
  36. }
  37. @Test
  38. public void remoteExecute() throws JSchException {
  39. List<String> list= JSchUtil.remoteExecute(session,"ls");
  40. System.out.println(JSONObject.toJSON(list));
  41. }
  42. @Test
  43. public void uploadFile() throws JSchException, FileNotFoundException {
  44. String filestr ="D:\\tmp\\test\\file_utils\\file1.txt";
  45. File file = new File(filestr);
  46. InputStream in = new FileInputStream(file);
  47. String directory="/root/test";
  48. String fileName="test.txt";
  49. boolean flag= JSchUtil.uploadFile(session,in,directory,fileName);
  50. System.out.println(flag);
  51. }
  52. @Test
  53. public void deleteFile() throws JSchException, FileNotFoundException {
  54. String directory="/root/test";
  55. String fileName="test.txt";
  56. boolean flag= JSchUtil.deleteFile(session,directory,fileName);
  57. System.out.println(flag);
  58. }
  59. @Test
  60. public void scpFrom() throws JSchException, FileNotFoundException {
  61. String source="/root/test/file1.txt";
  62. String destination ="D:\\tmp\\scfFrom.txt";
  63. long filesize= JSchUtil.scpFrom(session,source,destination);
  64. System.out.println(filesize);
  65. }
  66. @Test
  67. public void scpTo() throws JSchException, FileNotFoundException {
  68. String filestr ="D:\\tmp\\test\\file_utils\\file1.txt";
  69. String destination="/root/test/file1.txt";
  70. long filesize= JSchUtil.scpTo(session,filestr,destination);
  71. System.out.println(filesize);
  72. }
  73. }

自己尝试一下吧,非常好的一个工具,更多功能可以去官网看例子

5.引用

  • http://www.jcraft.com/jsch/examples/

  • http://www.liuhaihua.cn/archives/710346.html

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/341293
推荐阅读
相关标签
  

闽ICP备14008679号