工作需求记录:创建一个用于上传文件到服务器的SFTP工具类(使用JSch实现)
中午发来一个需求,创建一个Sftp传输文件到服务器的工具类。
首先需要解决的问题是,什么是Sftp?在使用Shell连接远程服务器的时候,诸如XShell或者我使用的Tabby Terminal都使用了SSH连接。
Sftp可以理解为SSH连接的一部分,作为Sftp连接的服务器只允许进行文件的上传和下载的一系列操作,但如果不写额外的方法,就没法知道到底上传是否成功。
在JAVA里要实现Sftp传输文件,最简单的是引入一个叫JSch的包,这里提供了丰富的方法来使用。除此之外,我们熟悉的Hutool也带有Sftp的基础实现,但单靠Hutool传输,
需要创建一个临时文件,再把它删除掉,因为Hutool的upload方法不支持IO流的直接使用,而是接收File类型,这里就涉及了多一步转换,比较麻烦。
所以我们直接在Maven Repository里找到并在pom里引入JSch的包:
<!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
如果是SSH连接的话自然可以在三方软件里用带有GUI的界面轻松上传下载,但我们现在需要自己构建这个流程,所以第一步就是解决创建连接的问题,在创建Session的时候,需要配置服务器的username,host,post和password,这些可以去yml里配置,如果是微服务则需要去Nacos之类的集成中心修改配置并发布。
/**
* 创建SFTP会话
*/
private Session createSession() throws JSchException {
JSch jsch = new JSch();
Session session = jsch.getSession(username, host, port);
session.setPassword(password);
session.setTimeout(timeout);
session.connect();
return session;
}
这里我们new出一个JSch来调用他的getSession方法传入配置来建立连接,并配置对应的属性,比如我在这里配置了sftp连接的超时时间timeout,3000为30秒。
想要像三方软件那样直接操作Linux,还需要创建一个Sftp通道ChannelSftp,这个类也是JSch包里自带的,只需要new出来,调用connect方法即可。
关于这里为什么要强转,这其实是一个父转子,Sftp的具体方法在ChannelSftp类中,但是Session只能提供父类Channel,里面没有ChannelSftp的方法
/**
* 创建SFTP通道
*/
private ChannelSftp createChannelSftp(Session session) throws JSchException {
ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
return channelSftp;
}
至此我们已经建立了连接,也获得了操作权,下一步就是操作了。
构建我们真正的upload方法,并用上之前的两个辅助方法:
public String uploadFile(MultipartFile file, String subFolder, String fileName) {
Session session = null;
ChannelSftp channelSftp = null;
try {
// 创建SFTP连接
session = createSession();
channelSftp = createChannelSftp(session);
// 构建上传路径
String remotePath = buildRemotePath(subFolder);
// 检查远程目录是否存在
createRemoteDirectoryIfNotExists(channelSftp, remotePath);
// 使用传入的文件名
if (StrUtil.isBlank(fileName)) {
throw new RuntimeException("文件名不能为空");
}
String fullRemotePath = remotePath + "/" + fileName;
// 使用InputStream上传
InputStream inputStream = file.getInputStream();
channelSftp.put(inputStream, fullRemotePath);
inputStream.close();
return fullRemotePath;
} catch (Exception e) {
log.error("SFTP文件上传失败: {}", e.getMessage(), e);
throw new RuntimeException("文件上传失败: " + e.getMessage());
} finally {
// 关闭连接
closeConnection(channelSftp, session);
}
我这里多了一步检查服务器是否存在上传路径的步骤,如果确定是有的话,就不需要再多做判断了。
至此,用于上传的SftpUtil就构建完成了,可以构建接口调用,或者用于前置后置必须业务都可以,这种业务场景一般都是需要前置,也就是必须上传文件后才能继续流程,在自己的方法里调用并判断一下,就可以了。除了上传以外,SftpUtil还支持下载等很多其他功能,可以自己查看一下JSch包里封装的方法探索和实现。

浙公网安备 33010602011771号