Skip to content

🌟 Spring Integration SFTP 适配器详解

本文面向 Spring 初学者,通过 Kotlin 代码+场景化示例讲解 SFTP 文件传输的核心用法,采用现代 Spring 最佳实践(注解配置优先)。


🧠 一、SFTP 基础概念

1.1 什么是 SFTP?

  • 核心特性
    • 基于 SSH 的安全文件传输协议
    • 全程加密防止数据泄露
    • 需要用户名/密码或密钥认证

IMPORTANT

协议要求:SFTP 会话必须全程保持客户端身份可见性,断开连接后需重新认证!

1.2 Spring Integration 支持

提供三种客户端端点:

端点类型方向功能
InboundAdapter接收监控远程目录→拉取文件到本地
OutboundAdapter发送推送本地文件→到远程目录
OutboundGateway双向执行 LS/GET/PUT/RM 等命令

⚙️ 二、环境配置

2.1 添加依赖 (Gradle Kotlin DSL)

kotlin
dependencies {
    implementation("org.springframework.integration:spring-integration-sftp:6.5.1")
    // [!code highlight] // 关键依赖项
}

2.2 配置会话工厂

kotlin
@Configuration
class SftpConfig {

    @Bean
    fun sftpSessionFactory(): DefaultSftpSessionFactory {
        return DefaultSftpSessionFactory().apply {
            host = "sftp.example.com"
            port = 22
            user = "admin"
            password = "securePass123!"
            // [!code warning] // 生产环境应使用密钥替代密码
            allowUnknownKeys = true  // 允许未知主机密钥
        }
    }
}

CAUTION

版本迁移注意:Spring Integration 6.0+ 使用 Apache MINA SSHD 替代 JCraft JSch,DefaultSftpSessionFactory 现在基于 org.apache.sshd.client.SshClient


🔄 三、实战:文件传输组件

3.1 入站适配器 (拉取远程文件)

kotlin
@Bean
fun sftpInboundAdapter(factory: SftpSessionFactory): IntegrationFlow {
    return IntegrationFlow.from(
        Sftp.inboundAdapter(factory)
            .remoteDirectory("/uploads")
            .regexFilter(".*\\.txt$") // 只处理txt文件
            .localDirectory(File("local-dir"))
    ) { e -> e.poller(Pollers.fixedRate(5000)) } // 每5秒轮询
}

工作流程
远程目录监控 → 文件过滤 → 下载到 local-dir → 触发后续处理

3.2 出站适配器 (推送本地文件)

kotlin
@Bean
fun uploadFlow(factory: SftpSessionFactory) = IntegrationFlow
    .from("fileUploadChannel")
    .handle(Sftp.outboundAdapter(factory).apply {
        remoteDirectory("/remote-dir")
        fileNameGenerator { it.headers["filename"] as String } // 动态文件名
    }
    .get()

使用示例

kotlin
val file = File("report.pdf")
messageChannel.send(
    MessageBuilder.withPayload(file)
        .setHeader("filename", "2024_report.pdf")
        .build()
)

3.3 出站网关 (高级操作)

kotlin
@Bean
fun listFilesGateway(factory: SftpSessionFactory) = IntegrationFlow
    .from("listCommandChannel")
    .handle(Sftp.outboundGateway(factory, "ls", "'/reports'")) 
    // [!code highlight] // 执行 ls /reports 命令
    .get()
kotlin
@Bean
fun downloadGateway(factory: SftpSessionFactory) = IntegrationFlow
    .from("downloadChannel")
    .handle(Sftp.outboundGateway(factory, "get", "payload.remotePath"))
    // [!code highlight] // payload 需包含 remotePath 属性
    .get()

⚠️ 四、关键注意事项

4.1 安全最佳实践

kotlin
@Bean
fun secureSessionFactory() = DefaultSftpSessionFactory().apply {
    // ...
    privateKey = FileResource(File("keys/user_rsa")) // 使用密钥
    privateKeyPassphrase = "keyPassword" 
    // [!code error] // 硬编码密码有风险!应使用环境变量
}

4.2 连接池配置

kotlin
factory.setSessionConfigurer { session: Session ->
    session.timeout = 30000 // 超时设置
    session.poolConfig.maxTotal = 10 // 最大连接数
    // [!code warning] // 根据业务负载调整
}

4.3 错误处理

kotlin
@Bean
fun errorHandler() = MessagePublishingErrorHandler().apply {
    setDefaultErrorChannelName("sftpErrorChannel")
}

// 全局异常捕获
@ServiceActivator(inputChannel = "sftpErrorChannel")
fun handleError(ex: MessagingException) {
    logger.error("SFTP操作失败: ${ex.failedMessage}", ex.cause)
}

❓ 五、常见问题解决

Q1: 连接超时如何排查?

诊断步骤

  1. 检查网络连通性 telnet sftp.example.com 22
  2. 验证防火墙规则
  3. 增加会话超时时间:
    kotlin
    factory.sessionConfig { it.timeout = 60000 }

Q2: 文件下载不完整?

解决方案

kotlin
Sftp.inboundAdapter(factory)
   .useTemporaryFileName(false) // [!code highlight] // 禁用临时文件名
   .localDirectory(File("local"))

Q3: 权限拒绝错误

根本原因

  • 服务器目录权限不足
  • 客户端密钥未授权

修复

bash
# 在SFTP服务器执行
chmod 755 /target-dir
cat client.pub >> ~/.ssh/authorized_keys

🚀 六、总结

核心要点

  1. 优先使用 Apache MINA SSHD 的现代实现
  2. 入站适配器适合 自动化拉取
  3. 出站网关适合 交互式操作 (LS/GET/PUT)
  4. 生产环境必须使用 SSH密钥认证

最佳实践建议

kotlin
// 组合使用:网关验证+适配器传输
fun secureFlow() = IntegrationFlow
    .from(gateway().verifyDirectory("/incoming"))
    .handle(outboundAdapter().autoCreateDirectory(true))

最终方案对比:

传统方式Spring Integration
手动管理 SSH 连接声明式自动连接池
自行解析文件列表内置正则过滤机制
编写重试逻辑@Retryable 注解支持