手把手教你SpringBoot集成SFTP客户端实现文件上传下载(上)

简介: 手把手教你SpringBoot集成SFTP客户端实现文件上传下载

背景

在项目开发中,一般文件存储很少再使用SFTP服务,但是也不排除合作伙伴使用SFTP来存储项目中的文件或者通过SFTP来实现文件数据的交互。我遇到的项目中,就有银行和保险公司等合作伙伴通过SFTP服务来实现与我们项目的文件数据的交互。

为了能够顺利地完成与友商的SFTP服务的连通,我们需要在自己的项目中实现一套SFTP客户端工具。一般我们会采用Jsch来实现SFTP客户端。

依赖

<!--执行远程操作-->
<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>
     <!--链接池-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.11.1</version>
</dependency>
复制代码

首先我们一定要引入jsch依赖,这个是我们实现SFTP客户端的基石;其次我们引入了链接池工具,为了避免每次执行SFTP命令都要重新创建链接,我们使用池化的方式优化了比较消耗资源的创建操作。

创建工具类

为了更好的使用SFTP工具,我们把jsch中关于SFTP的相关功能提炼出来,做了一次简单的封装,做成了我们可以直接使用的工具类。

里面只有两类方法:

1.创建Session与开启Session;

session创建好后,还不能创建channel,需要开启session后才能创建channel;

2.创建channel与开启channel;

channel也是一样,创建好的channel需要开启后才能真正地执行命令;

public class JschUtil {
  /**
   * 创建session
   *
   * @param userName       用户名
   * @param password       密码
   * @param host           域名
   * @param port           端口
   * @param privateKeyFile 密钥文件
   * @param passphrase     口令
   * @return
   * @throws AwesomeException
   */
  public static Session createSession(String userName, String password, String host, int port, String privateKeyFile, String passphrase) throws AwesomeException {
    return createSession(new JSch(), userName, password, host, port, privateKeyFile, passphrase);
  }
  /**
   * 创建session
   *
   * @param jSch
   * @param userName       用户名
   * @param password       密码
   * @param host           域名
   * @param port           端口
   * @param privateKeyFile 密钥
   * @param passphrase     口令
   * @return
   * @throws AwesomeException
   */
  public static Session createSession(JSch jSch, String userName, String password, String host, int port, String privateKeyFile, String passphrase) throws AwesomeException {
    try {
      if (!StringUtils.isEmpty(privateKeyFile)) {
        // 使用密钥验证方式,密钥可以是有口令的密钥,也可以是没有口令的密钥
        if (!StringUtils.isEmpty(passphrase)) {
          jSch.addIdentity(privateKeyFile, passphrase);
        } else {
          jSch.addIdentity(privateKeyFile);
        }
      }
      // 获取session
      Session session = jSch.getSession(userName, host, port);
      if (!StringUtils.isEmpty(password)) {
        session.setPassword(password);
      }
      // 不校验域名
      session.setConfig("StrictHostKeyChecking", "no");
      return session;
    } catch (Exception e) {
      throw new AwesomeException(500, "create session fail");
    }
  }
  /**
   * 创建session
   *
   * @param jSch
   * @param userName 用户名
   * @param password 密码
   * @param host     域名
   * @param port     端口
   * @return
   * @throws AwesomeException
   */
  public static Session createSession(JSch jSch, String userName, String password, String host, int port) throws AwesomeException {
    return createSession(jSch, userName, password, host, port, StringUtils.EMPTY, StringUtils.EMPTY);
  }
  /**
   * 创建session
   *
   * @param jSch
   * @param userName 用户名
   * @param host     域名
   * @param port     端口
   * @return
   * @throws AwesomeException
   */
  private Session createSession(JSch jSch, String userName, String host, int port) throws AwesomeException {
    return createSession(jSch, userName, StringUtils.EMPTY, host, port, StringUtils.EMPTY, StringUtils.EMPTY);
  }
  /**
   * 开启session链接
   *
   * @param jSch
   * @param userName       用户名
   * @param password       密码
   * @param host           域名
   * @param port           端口
   * @param privateKeyFile 密钥
   * @param passphrase     口令
   * @param timeout        链接超时时间
   * @return
   * @throws AwesomeException
   */
  public static Session openSession(JSch jSch, String userName, String password, String host, int port, String privateKeyFile, String passphrase, int timeout) throws AwesomeException {
    Session session = createSession(jSch, userName, password, host, port, privateKeyFile, passphrase);
    try {
      if (timeout >= 0) {
        session.connect(timeout);
      } else {
        session.connect();
      }
      return session;
    } catch (Exception e) {
      throw new AwesomeException(500, "session connect fail");
    }
  }
  /**
   * 开启session链接
   *
   * @param userName       用户名
   * @param password       密码
   * @param host           域名
   * @param port           端口
   * @param privateKeyFile 密钥
   * @param passphrase     口令
   * @param timeout        链接超时时间
   * @return
   * @throws AwesomeException
   */
  public static Session openSession(String userName, String password, String host, int port, String privateKeyFile, String passphrase, int timeout) throws AwesomeException {
    Session session = createSession(userName, password, host, port, privateKeyFile, passphrase);
    try {
      if (timeout >= 0) {
        session.connect(timeout);
      } else {
        session.connect();
      }
      return session;
    } catch (Exception e) {
      throw new AwesomeException(500, "session connect fail");
    }
  }
  /**
   * 开启session链接
   *
   * @param jSch
   * @param userName 用户名
   * @param password 密码
   * @param host     域名
   * @param port     端口
   * @param timeout  链接超时时间
   * @return
   * @throws AwesomeException
   */
  public static Session openSession(JSch jSch, String userName, String password, String host, int port, int timeout) throws AwesomeException {
    return openSession(jSch, userName, password, host, port, StringUtils.EMPTY, StringUtils.EMPTY, timeout);
  }
  /**
   * 开启session链接
   *
   * @param userName 用户名
   * @param password 密码
   * @param host     域名
   * @param port     端口
   * @param timeout  链接超时时间
   * @return
   * @throws AwesomeException
   */
  public static Session openSession(String userName, String password, String host, int port, int timeout) throws AwesomeException {
    return openSession(userName, password, host, port, StringUtils.EMPTY, StringUtils.EMPTY, timeout);
  }
  /**
   * 开启session链接
   *
   * @param jSch
   * @param userName 用户名
   * @param host     域名
   * @param port     端口
   * @param timeout  链接超时时间
   * @return
   * @throws AwesomeException
   */
  public static Session openSession(JSch jSch, String userName, String host, int port, int timeout) throws AwesomeException {
    return openSession(jSch, userName, StringUtils.EMPTY, host, port, StringUtils.EMPTY, StringUtils.EMPTY, timeout);
  }
  /**
   * 开启session链接
   *
   * @param userName 用户名
   * @param host     域名
   * @param port     端口
   * @param timeout  链接超时时间
   * @return
   * @throws AwesomeException
   */
  public static Session openSession(String userName, String host, int port, int timeout) throws AwesomeException {
    return openSession(userName, StringUtils.EMPTY, host, port, StringUtils.EMPTY, StringUtils.EMPTY, timeout);
  }
  /**
   * 创建指定通道
   *
   * @param session
   * @param channelType
   * @return
   * @throws AwesomeException
   */
  public static Channel createChannel(Session session, ChannelType channelType) throws AwesomeException {
    try {
      if (!session.isConnected()) {
        session.connect();
      }
      return session.openChannel(channelType.getValue());
    } catch (Exception e) {
      throw new AwesomeException(500, "open channel fail");
    }
  }
  /**
   * 创建sftp通道
   *
   * @param session
   * @return
   * @throws AwesomeException
   */
  public static ChannelSftp createSftp(Session session) throws AwesomeException {
    return (ChannelSftp) createChannel(session, ChannelType.SFTP);
  }
  /**
   * 创建shell通道
   *
   * @param session
   * @return
   * @throws AwesomeException
   */
  public static ChannelShell createShell(Session session) throws AwesomeException {
    return (ChannelShell) createChannel(session, ChannelType.SHELL);
  }
  /**
   * 开启通道
   *
   * @param session
   * @param channelType
   * @param timeout
   * @return
   * @throws AwesomeException
   */
  public static Channel openChannel(Session session, ChannelType channelType, int timeout) throws AwesomeException {
    Channel channel = createChannel(session, channelType);
    try {
      if (timeout >= 0) {
        channel.connect(timeout);
      } else {
        channel.connect();
      }
      return channel;
    } catch (Exception e) {
      throw new AwesomeException(500, "connect channel fail");
    }
  }
  /**
   * 开启sftp通道
   *
   * @param session
   * @param timeout
   * @return
   * @throws AwesomeException
   */
  public static ChannelSftp openSftpChannel(Session session, int timeout) throws AwesomeException {
    return (ChannelSftp) openChannel(session, ChannelType.SFTP, timeout);
  }
  /**
   * 开启shell通道
   *
   * @param session
   * @param timeout
   * @return
   * @throws AwesomeException
   */
  public static ChannelShell openShellChannel(Session session, int timeout) throws AwesomeException {
    return (ChannelShell) openChannel(session, ChannelType.SHELL, timeout);
  }
  enum ChannelType {
    SESSION("session"),
    SHELL("shell"),
    EXEC("exec"),
    X11("x11"),
    AGENT_FORWARDING("auth-agent@openssh.com"),
    DIRECT_TCPIP("direct-tcpip"),
    FORWARDED_TCPIP("forwarded-tcpip"),
    SFTP("sftp"),
    SUBSYSTEM("subsystem");
    private final String value;
    ChannelType(String value) {
      this.value = value;
    }
    public String getValue() {
      return this.value;
    }
  }
}
复制代码

SFTP链接池化

我们通过实现BasePooledObjectFactory类来池化通道ChannelSftp。这并不是真正池化的代码,下面的代码只是告知池化管理器如何创建对象和销毁对象。

static class SftpFactory extends BasePooledObjectFactory<ChannelSftp> implements AutoCloseable {
    private Session session;
    private SftpProperties properties;
    // 初始化SftpFactory
    // 里面主要是创建目标session,后续可用通过这个session不断地创建ChannelSftp。
    SftpFactory(SftpProperties properties) throws AwesomeException {
      this.properties = properties;
      String username = properties.getUsername();
      String password = properties.getPassword();
      String host = properties.getHost();
      int port = properties.getPort();
      String privateKeyFile = properties.getPrivateKeyFile();
      String passphrase = properties.getPassphrase();
      session = JschUtil.createSession(username, password, host, port, privateKeyFile, passphrase);
    }
    // 销毁对象,主要是销毁ChannelSftp
    @Override
    public void destroyObject(PooledObject<ChannelSftp> p) throws Exception {
      p.getObject().disconnect();
    }
    // 创建对象ChannelSftp
    @Override
    public ChannelSftp create() throws Exception {
      int timeout = properties.getTimeout();
      return JschUtil.openSftpChannel(this.session, timeout);
    }
    // 包装创建出来的对象
    @Override
    public PooledObject<ChannelSftp> wrap(ChannelSftp channelSftp) {
      return new DefaultPooledObject<>(channelSftp);
    }
    // 验证对象是否可用
    @Override
    public boolean validateObject(PooledObject<ChannelSftp> p) {
      return p.getObject().isConnected();
    }
    // 销毁资源,关闭session
    @Override
    public void close() throws Exception {
      if (Objects.nonNull(session)) {
        if (session.isConnected()) {
          session.disconnect();
        }
        session = null;
      }
    }
  }
复制代码


相关文章
|
2月前
|
网络协议 Java
SpringBoot快速搭建TCP服务端和客户端
由于工作需要,研究了SpringBoot搭建TCP通信的过程,对于工程需要的小伙伴,只是想快速搭建一个可用的服务.其他的教程看了许多,感觉讲得太复杂,很容易弄乱,这里我只讲效率,展示快速搭建过程。
148 58
|
5天前
|
Java 关系型数据库 MySQL
springboot项目集成dolphinscheduler调度器 实现datax数据同步任务
springboot项目集成dolphinscheduler调度器 实现datax数据同步任务
46 2
|
5天前
|
分布式计算 Java 大数据
springboot项目集成dolphinscheduler调度器 可拖拽spark任务管理
springboot项目集成dolphinscheduler调度器 可拖拽spark任务管理
27 2
|
8天前
|
物联网 Linux 开发者
快速部署自己私有MQTT-Broker-下载安装到运行不到一分钟,快速简单且易于集成到自己项目中
本文给物联网开发的朋友推荐的是GMQT,让物联网开发者快速拥有合适自己的MQTT-Broker,本文从下载程序到安装部署手把手教大家安装用上私有化MQTT服务器。
138 5
|
1月前
|
前端开发
SpringBoot2.3.1集成Knife4j接口文档
SpringBoot2.3.1集成Knife4j接口文档
164 44
|
3天前
|
存储 人工智能 Java
Springboot集成AI Springboot3 集成阿里云百炼大模型CosyVoice2 实现Ai克隆语音(未持久化存储)
本项目基于Spring Boot 3.5.3与Java 17,集成阿里云百炼大模型CosyVoice2实现音色克隆与语音合成。内容涵盖项目搭建、音色创建、音频合成、音色管理等功能,适用于希望快速掌握Spring Boot集成语音AI技术的开发者。需提前注册阿里云并获取API Key。
|
1月前
|
缓存 安全 Java
Shiro简介及SpringBoot集成Shiro(狂神说视频简易版)
Shiro简介及SpringBoot集成Shiro(狂神说视频简易版)
104 6
|
2月前
|
缓存 Java 数据库
SpringBoot集成Ehcache缓存使用指南
以上是SpringBoot集成Ehcache缓存的基本操作指南,帮助你在实际项目中轻松实现缓存功能。当然,Ehcache还有诸多高级特性,通过学习和实践,你可以更好地发挥它的威力。
133 20
|
2月前
|
Java
SpringBoot快速搭建WebSocket服务端和客户端
由于工作需要,研究了SpringBoot搭建WebSocket双向通信的过程,其他的教程看了许多,感觉讲得太复杂,很容易弄乱,这里我只展示快速搭建过程。
215 1
|
9月前
|
Java Maven Docker
gitlab-ci 集成 k3s 部署spring boot 应用
gitlab-ci 集成 k3s 部署spring boot 应用

热门文章

最新文章