SFTP 出站通道介面卡
SFTP出站通道介面卡是一個特殊的 MessageHandler,它連線到遠端目錄併為收到的每個作為傳入 Message 的 payload 的檔案啟動檔案傳輸。它還支援檔案的多種表示形式,因此您不限於 File 物件。與FTP出站介面卡類似,SFTP出站通道介面卡支援以下payload:
-
java.io.File:實際的檔案物件 -
byte[]:表示檔案內容的位元組陣列 -
java.lang.String:表示檔案內容的文字 -
java.io.InputStream:要傳輸到遠端檔案的資料流 -
org.springframework.core.io.Resource:要傳輸到遠端檔案的資料資源
以下示例展示瞭如何配置SFTP出站通道介面卡:
<int-sftp:outbound-channel-adapter id="sftpOutboundAdapter"
session-factory="sftpSessionFactory"
channel="inputChannel"
charset="UTF-8"
remote-file-separator="/"
remote-directory="foo/bar"
remote-filename-generator-expression="payload.getName() + '-mysuffix'"
filename-generator="fileNameGenerator"
use-temporary-filename="true"
chmod="600"
mode="REPLACE"/>
有關這些屬性的更多詳細資訊,請參閱schema。
SpEL和SFTP出站介面卡
與Spring Integration中的許多其他元件一樣,您可以透過指定兩個屬性:remote-directory-expression 和 remote-filename-generator-expression(前面描述過)來配置SFTP出站通道介面卡時使用Spring表示式語言(SpEL)。表示式評估上下文將訊息作為其根物件,這使您可以使用可以根據訊息中的資料(來自“payload”或“headers”)動態計算檔名或現有目錄路徑的表示式。在前面的示例中,我們定義了 remote-filename-generator-expression 屬性,其表示式值根據原始名稱計算檔名,同時附加字尾:'-mysuffix'。
從版本4.1開始,您可以在傳輸檔案時指定 mode。預設情況下,現有檔案會被覆蓋。這些模式由 FileExistsMode 列舉定義,其中包括以下值:
-
REPLACE(預設) -
REPLACE_IF_MODIFIED -
APPEND -
APPEND_NO_FLUSH -
IGNORE -
FAIL
使用 IGNORE 和 FAIL 時,檔案不會被傳輸。FAIL 會導致丟擲異常,而 IGNORE 會靜默忽略傳輸(儘管會生成 DEBUG 日誌條目)。
版本4.3引入了 chmod 屬性,您可以使用它在上傳後更改遠端檔案許可權。您可以使用傳統的Unix八進位制格式(例如,600只允許檔案所有者讀寫)。使用Java配置介面卡時,您可以使用 setChmodOctal("600") 或 setChmod(0600)。
避免部分寫入的檔案
處理檔案傳輸時常見的問題之一是處理部分檔案的可能性。檔案可能在檔案系統中出現,但其傳輸實際上尚未完成。
為了解決這個問題,Spring Integration SFTP介面卡使用一種通用演算法,即檔案在臨時名稱下傳輸,並在完全傳輸後重命名。
預設情況下,每個正在傳輸的檔案都會在檔案系統中顯示一個附加字尾,預設情況下為 .writing。您可以透過設定 temporary-file-suffix 屬性來更改它。
但是,在某些情況下,您可能不希望使用此技術(例如,如果伺服器不允許重新命名檔案)。對於這種情況,您可以透過將 use-temporary-file-name 設定為 false 來停用此功能(預設值為 true)。當此屬性為 false 時,檔案會以其最終名稱寫入,並且消費應用程式需要其他機制來檢測檔案完全上傳後才能訪問它。
使用 Java 配置
以下Spring Boot應用程式展示瞭如何使用Java配置出站介面卡的示例:
@SpringBootApplication
@IntegrationComponentScan
public class SftpJavaApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context =
new SpringApplicationBuilder(SftpJavaApplication.class)
.web(false)
.run(args);
MyGateway gateway = context.getBean(MyGateway.class);
gateway.sendToSftp(new File("/foo/bar.txt"));
}
@Bean
public SessionFactory<SftpClient.DirEntry> sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost("localhost");
factory.setPort(port);
factory.setUser("foo");
factory.setPassword("foo");
factory.setAllowUnknownKeys(true);
factory.setTestSession(true);
return new CachingSessionFactory<SftpClient.DirEntry>(factory);
}
@Bean
@ServiceActivator(inputChannel = "toSftpChannel")
public MessageHandler handler() {
SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
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 = "toSftpChannel")
void sendToSftp(File file);
}
}
使用 Java DSL 進行配置
以下 Spring Boot 應用程式演示瞭如何使用 Java DSL 配置出站介面卡
@SpringBootApplication
public class SftpJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(SftpJavaApplication.class)
.web(false)
.run(args);
}
@Bean
public IntegrationFlow sftpOutboundFlow() {
return IntegrationFlow.from("toSftpChannel")
.handle(Sftp.outboundAdapter(this.sftpSessionFactory, FileExistsMode.FAIL)
.useTemporaryFileName(false)
.remoteDirectory("/foo")
).get();
}
}