对于最新稳定版本,请使用 Spring Integration 7.0.0spring-doc.cadn.net.cn

FTP 出站通道适配器

FTP出站通道适配器依赖于消息处理器该实现连接到FTP服务器,并为收到的每个文件发起FTP传输。 它还支持多种文件表示方式,因此你并不局限于java.io.file-输入有效载荷。 FTP出站通道适配器支持以下有效载荷:spring-doc.cadn.net.cn

以下示例展示了如何配置出站通道适配器:spring-doc.cadn.net.cn

<int-ftp:outbound-channel-adapter id="ftpOutbound"
    channel="ftpChannel"
    session-factory="ftpSessionFactory"
    charset="UTF-8"
    remote-file-separator="/"
    auto-create-directory="true"
    remote-directory-expression="headers['remote_dir']"
    temporary-remote-directory-expression="headers['temp_remote_dir']"
    filename-generator="fileNameGenerator"
    use-temporary-filename="true"
    chmod="600"
    mode="REPLACE"/>

前面的配置展示了你可以通过使用出站通道适配器同时也提供各种属性的值,例如文件名生成器(一个实现o.s.i.file.FileNameGenerator策略界面),指的是会话工厂,以及其他属性。 你还可以看到一些示例*表达属性允许你使用 SpEL 来配置如下设置远程目录表达式,temporary-remote-directory-expression远程文件名生成器表达式(一个 SpEL 的替代方案文件名生成器,在前例中所示)。 与任何允许使用 SpEL 的组件一样,访问有效载荷和消息头部可以通过“payload”和“heads”变量实现。 请参阅结构图以了解可用属性的更多细节。spring-doc.cadn.net.cn

默认情况下,如果没有指定文件名生成器,Spring Integration 会使用o.s.i.file.DefaultFileNameGenerator.DefaultFileNameGenerator根据file_name消息头,或者,如果消息的有效载荷已经是java.io.file,它使用了该文件的原始名称。
定义某些值(例如:远程目录)可能是依赖平台或FTP服务器的。 例如,正如 forum.spring.io/showthread.php?p=333478&posted=1#post333478 报道的,在某些平台上,你必须在目录定义末尾加上斜杠(例如,remote-directory=“/thing1/thing2/”而不是remote-directory=“/thing1/thing2”).

从4.1版本开始,你可以指定模式在传输文件时。 默认情况下,已有文件会被覆盖。 这些模态由以下定义FileExistsMode枚举,包括以下数值:spring-doc.cadn.net.cn

忽视失败不要转移文件。失败导致抛出一个例外,而忽视默默无视转移(尽管调试日志条目会被生成)。spring-doc.cadn.net.cn

5.2 版本引入了CHMOD属性,你可以用它在上传后更改远程文件权限。 你可以使用传统的Unix八进制格式(例如,600仅允许文件所有者读写)。 用 Java 配置适配器时,你可以用setChmodOctal(“600”)setChmod(0600). 只有当你的FTP服务器支持以下条件时才适用网站CHMOD副指挥部。spring-doc.cadn.net.cn

避免部分写入的文件

处理文件传输时常见的问题之一是可能处理部分文件。 也就是说,文件可能在其传输完成之前就已出现在文件系统中。spring-doc.cadn.net.cn

为解决这个问题,Spring Integration FTP 适配器采用一种常见算法:文件先以临时名称传输,完全传输后再重命名。spring-doc.cadn.net.cn

默认情况下,所有正在传输的文件都会在文件系统中加上一个附加后缀,默认情况下为。写作. 你可以通过设置临时文件后缀属性。spring-doc.cadn.net.cn

不过,有些情况下你可能不想使用这种方法(例如服务器不允许重命名文件)。 遇到这种情况,你可以通过设置来禁用这个功能使用临时文件名false(默认为true). 当该属性为false文件以最终名称写入,消费应用程序需要其他机制来检测文件是否完全上传,然后才访问。spring-doc.cadn.net.cn

使用 Java 配置配置

以下 Spring Boot 应用程序展示了如何用 Java 配置配置出站适配器的示例:spring-doc.cadn.net.cn

@SpringBootApplication
@IntegrationComponentScan
public class FtpJavaApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =
                    new SpringApplicationBuilder(FtpJavaApplication.class)
                        .web(false)
                        .run(args);
        MyGateway gateway = context.getBean(MyGateway.class);
        gateway.sendToFtp(new File("/foo/bar.txt"));
    }

    @Bean
    public SessionFactory<FTPFile> ftpSessionFactory() {
        DefaultFtpSessionFactory sf = new DefaultFtpSessionFactory();
        sf.setHost("localhost");
        sf.setPort(port);
        sf.setUsername("foo");
        sf.setPassword("foo");
        sf.setTestSession(true);
        return new CachingSessionFactory<FTPFile>(sf);
    }

    @Bean
    @ServiceActivator(inputChannel = "ftpChannel")
    public MessageHandler handler() {
        FtpMessageHandler handler = new FtpMessageHandler(ftpSessionFactory());
        handler.setRemoteDirectoryExpressionString("headers['remote-target-dir']");
        handler.setFileNameGenerator(new FileNameGenerator() {

            @Override
            public String generateFileName(Message<?> message) {
                 return "handlerContent.test";
            }

        });
        return handler;
    }

    @MessagingGateway
    public interface MyGateway {

         @Gateway(requestChannel = "toFtpChannel")
         void sendToFtp(File file);

    }
}

使用 Java DSL 配置

以下 Spring Boot 应用程序展示了如何使用 Java DSL 配置出站适配器的示例:spring-doc.cadn.net.cn

@SpringBootApplication
@IntegrationComponentScan
public class FtpJavaApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =
            new SpringApplicationBuilder(FtpJavaApplication.class)
                .web(false)
                .run(args);
        MyGateway gateway = context.getBean(MyGateway.class);
        gateway.sendToFtp(new File("/foo/bar.txt"));
    }

    @Bean
    public SessionFactory<FTPFile> ftpSessionFactory() {
        DefaultFtpSessionFactory sf = new DefaultFtpSessionFactory();
        sf.setHost("localhost");
        sf.setPort(port);
        sf.setUsername("foo");
        sf.setPassword("foo");
        sf.setTestSession(true);
        return new CachingSessionFactory<FTPFile>(sf);
    }

    @Bean
    public IntegrationFlow ftpOutboundFlow() {
        return IntegrationFlow.from("toFtpChannel")
                .handle(Ftp.outboundAdapter(ftpSessionFactory(), FileExistsMode.FAIL)
                        .useTemporaryFileName(false)
                        .fileNameExpression("headers['" + FileHeaders.FILENAME + "']")
                        .remoteDirectory(this.ftpServer.getTargetFtpDirectory().getName())
                ).get();
    }

    @MessagingGateway
    public interface MyGateway {

         @Gateway(requestChannel = "toFtpChannel")
         void sendToFtp(File file);

    }

}