背景:

        项目中有需求要使用Java上传文件至服务器及执行某些shell脚本。通过查阅一些资料,反复测试了两套方案,各有优缺点,下面分别阐述一下。
        

实现方案一:SpringBoot + JSch + Linux

1、JSch介绍:

        最开始使用的是jsch开源包,这是一个很老的开源工具包,是SSH2的纯Java实现,JSch可以连接到sshd服务器并使用端口转发、X11转发、文件传输等。官网地址:JSch - Java Secure Channelicon-default.png?t=M4ADhttp://www.jcraft.com/jsch/

2、具体使用:

        具体的操作可参照这篇文章:

Java JSch 远程执行 Shell 命令_qhh0205的博客-CSDN博客_java jsch 执行命令背景项目需求,需要远程 ssh 登录到某个节点执行 shell 命令来完成任务。对于这种需求,如果不用 java 程序,直接 linux 的 ssh 命令就可以完成,但是在编码到程序中时需要相关的程序包来完成,本文主要介绍在 java 中如何使用 JSch 包实现 ssh 远程连接并执行命令。JSch 简介JSch 是Java Secure Channel的缩写。JSch是一个SSH2的纯Java实现。它允许你连接到一个SSH服务器,并且可以使用端口转发,X11转发,文件传输等,当然你也可以集成它的功https://blog.csdn.net/qianghaohao/article/details/115281105

3、存在的问题:

        我在使用过程中遇到了两个比较大的问题:

        1、需要上传的文件存放在项目的/resources/static/下,需要一起打包到项目jar包中,需要注意的,文件打包到jar包中之后将无法通过路径和file文件获取,只能通过读取流对象获取jar中的文件。jsch主要可以通过两种方式上传:路径和流对象

// 通过源文件路径上传
public void put(String src, String dst) throws SftpException {
    this.put((String)src, dst, (SftpProgressMonitor)null, 0);
}
// 通过源文件流对象上传
public void put(InputStream src, String dst) throws SftpException {
    this.put((InputStream)src, dst, (SftpProgressMonitor)null, 0);
}

所以这里我们要采用第二种,使用流的方式上传,获取流对象的方式如下:

ClassPathResource resource = new ClassPathResource("static/xxx/xxx.docx");
try {
    InputStream fis = resource.getInputStream();
} catch (Exception e) {
    e.printStackTrace();
}

这个文件路径的问题比较好解决,第二个是一个阻塞性的问题。

        2、JSch这个工具包已经很久没有更新了,JSch连接服务器时会和服务端进行协商,选出共同支持的算法进行传输,服务器SSH版本和JSch支持算法找不到相同的会导致报错:Algorithm negotiation fail(算法协商失败),我测试了ssh7.6版本连接没问题,ssh8.2会连接失败。目前还没找到合适的解决办法,希望有解决方案的网友在评论区评论!

实现方案二:SpringBoot + SSHJ + Linux

1、SSHJ介绍:

        在上个方案阻塞后找JSch替代品,SSHJ 是 hierynomus 在 Github 上开源的 Java SSH 库,项目位于 https://github.com/hierynomus/sshj,2022-04-22刚更新了0.33.0版本。相信是暂时不会出现算法协商失败的问题。
        SSHJ 功能齐全,支持从 known_hosts 文件读取验证公钥,支持公钥、密码和交互式的验证方式,支持命令、子系统和 Shell Channel,支持本地和远程端口转发,支持 SCP 安全拷贝协议,支持从版本 0 到 3 的完全的 SFTP 安全文件传输协议,支持广泛的加密、签名、压缩等的算法实现。

SSHJ - 功能齐全的Java SSH库-简易百科SSH(Secure Shell,安全外壳协议),是专为远程登录会话和其他网络服务提供安全性的应用层协议。在日常开发中,包括登录远程服务器、远程执行命令脚本、文件传输等,都使用了 SSH 协议icon-default.png?t=M4ADhttps://www.isolves.com/it/yj/zs/2020-07-19/24469.html

2、具体使用:

        关于SSHJ的文章我找了一下,感觉比较少,可以参照下面这篇,但是大部分还是要自己看源码。sshj 示例_weixin_30839881的博客-CSDN博客icon-default.png?t=M4ADhttps://blog.csdn.net/weixin_30839881/article/details/99955274?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165259697516781667898380%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165259697516781667898380&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-99955274-null-null.142^v9^pc_search_result_cache,157^v4^control&utm_term=sshj&spm=1018.2226.3001.4187

3、存在的问题:

        该工具包不支持流对象上传!(看了源码也没有,也许是我太菜了,有知道的网友评论区指点)

// 通过源文件路径上传
public void put(String source, String dest) throws IOException {
    this.xfer.upload(source, dest);
}
// 通过源文件file上传
public void put(LocalSourceFile source, String dest) throws IOException {
    this.xfer.upload(source, dest);
}

        SSHJ只支持 路径 和 file文件 上传,这和我上个方案遇到的jar包中的文件只能通过流读取正好对峙上了。

        最后通过两天的冥思苦想,终于得到一个解决方案:

        先通过流获取到文件,再将流对象复制到一个file文件中(在/tmp/下会生成一个同名的临时文件),最后将这个file对象传到对应的服务器。大致代码如下:

SSHClient sshClient = new SSHClient();
ClassPathResource resource = new ClassPathResource("static/xxx/xxx.docx");
try {
    InputStream fis = resource.getInputStream();
    File file = new File("/tmp/" + resource.getFilename());
    FileUtils.copyInputStreamToFile(fis, file);
    SFTPClient sftpClient = sshClient.newSFTPClient();
    LocalSourceFile localSourceFile = new FileSystemFile(file);
    sftpClient.put(localSourceFile, targetPath);
} catch (Exception e) {
    e.printStackTrace();
}

至此,大功告成!如何在Java中将InputStream转换为File_cyan20115的博客-CSDN博客以下是一些将InputStream转换为File Java示例 手动将InputStream复制到FileOutputStream Apache Commons IO – FileUtils.copyInputStreamToFile Java 1.7 NIO Files.copy 1. FileOutputStream 1.1我们必须将数据从InputStream手动复...https://blog.csdn.net/cyan20115/article/details/106554092?spm=1001.2101.3001.6650.5&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5-106554092-blog-89181410.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5-106554092-blog-89181410.pc_relevant_default&utm_relevant_index=8

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐