SFTP 出站通道介面卡
SFTP 出站通道介面卡是一個特殊的 MessageHandler
,它連線到遠端目錄,併為接收到的每條以檔案作為負載(payload)的入站 Message
啟動檔案傳輸。它還支援檔案的多種表示形式,因此您不僅限於 File
物件。與 FTP 出站介面卡類似,SFTP 出站通道介面卡支援以下負載型別:
-
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 中的許多其他元件一樣,您可以在配置 SFTP 出站通道介面卡時使用 Spring Expression Language (SpEL),方法是指定兩個屬性:remote-directory-expression
和 remote-filename-generator-expression
(前面已描述)。表示式評估上下文將訊息作為其根物件,這使您能夠使用基於訊息中的資料(來自 '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();
}
}