Изменил импорт файлов по SFTP в dbf-importer.
This commit is contained in:
psemenkov 2024-04-15 17:09:58 +03:00
parent eb79ccf8d0
commit 4da055edad
7 changed files with 125 additions and 60 deletions

View file

@ -87,11 +87,11 @@
</dependency> </dependency>
<!-- TEST --> <!-- TEST -->
<!-- <dependency>--> <dependency>
<!-- <groupId>org.springframework</groupId>--> <groupId>org.springframework.boot</groupId>
<!-- <artifactId>spring-test</artifactId>--> <artifactId>spring-boot-starter-test</artifactId>
<!-- <scope>test</scope>--> <scope>test</scope>
<!-- </dependency>--> </dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId> <artifactId>junit-jupiter</artifactId>

View file

@ -4,29 +4,27 @@ import com.jcraft.jsch.ChannelSftp;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.InboundChannelAdapter; import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.annotation.ServiceActivator; import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.core.MessageSource; import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.file.filters.AcceptAllFileListFilter; import org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway;
import org.springframework.integration.file.remote.session.CachingSessionFactory; import org.springframework.integration.file.remote.session.CachingSessionFactory;
import org.springframework.integration.file.remote.session.SessionFactory; import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.scheduling.PollerMetadata; import org.springframework.integration.sftp.gateway.SftpOutboundGateway;
import org.springframework.integration.sftp.inbound.SftpInboundFileSynchronizer;
import org.springframework.integration.sftp.inbound.SftpInboundFileSynchronizingMessageSource;
import org.springframework.integration.sftp.session.DefaultSftpSessionFactory; import org.springframework.integration.sftp.session.DefaultSftpSessionFactory;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessageHandler;
import org.springframework.scheduling.support.PeriodicTrigger;
import ru.spcex.clearing.dbf.importer.config.settings.ImportDBFServiceSettings; import ru.spcex.clearing.dbf.importer.config.settings.ImportDBFServiceSettings;
import java.io.File; import java.io.File;
import java.util.Comparator; import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.Command.MGET;
@Configuration @Configuration
@ConditionalOnProperty(value="import-dbf-service.store.sftp-in.sftp-src-dir")
public class SFTPConfig { public class SFTPConfig {
private final Logger log = LoggerFactory.getLogger(getClass()); private final Logger log = LoggerFactory.getLogger(getClass());
private final ImportDBFServiceSettings settings; private final ImportDBFServiceSettings settings;
@ -47,40 +45,26 @@ public class SFTPConfig {
return new CachingSessionFactory<>(factory); return new CachingSessionFactory<>(factory);
} }
@Bean(name = PollerMetadata.DEFAULT_POLLER) @MessagingGateway
public PollerMetadata defaultPoller() { public interface DbfGateway {
PollerMetadata pollerMetadata = new PollerMetadata(); @Gateway(requestChannel = "listSftpChannel")
pollerMetadata.setTrigger(new PeriodicTrigger(5, TimeUnit.SECONDS)); List<File> listFiles(String dir);
return pollerMetadata;
} }
@Bean @Bean
SftpInboundFileSynchronizer sftpInboundFileSynchronizer() { public MessageChannel listSftpChannel(SessionFactory<ChannelSftp.LsEntry> sessionFactory, ImportDBFServiceSettings settings) {
SftpInboundFileSynchronizer fileSync = new SftpInboundFileSynchronizer(sftpSessionFactory()); DirectChannel dc = new DirectChannel();
fileSync.setDeleteRemoteFiles(true); dc.subscribe(handlerList(sessionFactory, settings));
fileSync.setTemporaryFileSuffix(".tmp"); return dc;
fileSync.setRemoteDirectory(settings.getStore().getSftpIn().getSftpSrcDir());
fileSync.setFilter(new AcceptAllFileListFilter<>());
fileSync.setPreserveTimestamp(true);
fileSync.setComparator(Comparator.comparingInt(f -> f.getAttrs().getMTime()));
return fileSync;
} }
@Bean @Bean
@InboundChannelAdapter("sftpChannel") @ServiceActivator(inputChannel = "listSftpChannel")
public MessageSource<File> sftpMessageSource() { public MessageHandler handlerList(SessionFactory<ChannelSftp.LsEntry> sessionFactory, ImportDBFServiceSettings settings) {
SftpInboundFileSynchronizingMessageSource source = new SftpInboundFileSynchronizingMessageSource(sftpInboundFileSynchronizer()); SftpOutboundGateway sftpOutboundGateway = new SftpOutboundGateway(sessionFactory, MGET.getCommand(), null);
source.setLocalDirectory(new File(settings.getStore().getSrcDir())); sftpOutboundGateway.setLocalDirectory(new File(settings.getStore().getSrcDir()));
source.setAutoCreateLocalDirectory(true); sftpOutboundGateway.setAutoCreateLocalDirectory(true);
return source; sftpOutboundGateway.setOption(AbstractRemoteFileOutboundGateway.Option.DELETE);
} return sftpOutboundGateway;
@Bean
@ServiceActivator(inputChannel="sftpChannel")
MessageHandler messageHandler() {
return arg0 -> {
File f = (File) arg0.getPayload();
log.info("copy file '{}' from sftp event", f.getName());
};
} }
} }

View file

@ -48,6 +48,7 @@ public class DBFImporterService {
} else { } else {
log.info("adding import task {}", specificTable); log.info("adding import task {}", specificTable);
} }
fileChecker.checkAndLoadSFTP();
executorService.execute(() -> { executorService.execute(() -> {
Map<ETable, List<File>> newFiles = null; Map<ETable, List<File>> newFiles = null;
try { try {

View file

@ -1,24 +1,34 @@
package ru.spcex.clearing.dbf.importer.services; package ru.spcex.clearing.dbf.importer.services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.spcex.clearing.dbf.importer.config.SFTPConfig;
import ru.spcex.clearing.dbf.importer.config.settings.ImportDBFServiceSettings; import ru.spcex.clearing.dbf.importer.config.settings.ImportDBFServiceSettings;
import ru.spcex.clearing.dbf.importer.logic.data.enums.ETable; import ru.spcex.clearing.dbf.importer.logic.data.enums.ETable;
import ru.spcex.platform.utils.log.ExceptionUtils;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Service("fileChecker") @Service("fileChecker")
public class FileChecker { public class FileChecker {
private final ImportDBFServiceSettings settings; private final ImportDBFServiceSettings settings;
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final SFTPConfig.DbfGateway gateway;
public FileChecker(ImportDBFServiceSettings settings) { public FileChecker(SFTPConfig.DbfGateway gateway,
ImportDBFServiceSettings settings) {
this.gateway = gateway;
this.settings = settings; this.settings = settings;
} }
public Map<ETable, List<File>> checkNewFiles() {
return checkNewFiles(null);
}
public Map<ETable, List<File>> checkNewFiles(ETable specificTable) { public Map<ETable, List<File>> checkNewFiles(ETable specificTable) {
Map<ETable, List<File>> newFiles = new EnumMap<>(ETable.class); Map<ETable, List<File>> newFiles = new EnumMap<>(ETable.class);
@ -39,19 +49,30 @@ public class FileChecker {
} }
private List<File> lsDBF(String dbfDirPath) { private List<File> lsDBF(String dbfDirPath) {
File dbfDir = new File(dbfDirPath);
File[] dbfFiles = dbfDir.listFiles((dir, name) -> {
int formatPosition = name.lastIndexOf(".");
if (formatPosition == -1 || formatPosition == name.length() - 1) return false;
return "dbf".equalsIgnoreCase(name.substring(formatPosition + 1));
});
List<File> resultFiles = new LinkedList<>(); List<File> resultFiles = new LinkedList<>();
if (dbfFiles != null && dbfFiles.length >= 1) { try (Stream<Path> stream = Files.walk(Paths.get(dbfDirPath))) {
Arrays.sort(dbfFiles, Comparator.comparingLong(File::lastModified)); resultFiles = stream
resultFiles.addAll(Arrays.asList(dbfFiles)); .filter(file -> !Files.isDirectory(file))
.map(Path::toFile)
.filter(file -> file.getName().toLowerCase(Locale.ROOT).endsWith(".dbf"))
.sorted(Comparator.comparingLong(File::lastModified))
.collect(Collectors.toList());
} catch (IOException e) {
log.error("Error reading 'service.store.src-dir' : {}", ExceptionUtils.getStackTrace(e));
} }
return resultFiles; return resultFiles;
} }
public void checkAndLoadSFTP() {
if (settings.getStore().getSftpIn().getSftpSrcPayValDir() == null || settings.getStore().getSftpIn().getSftpSrcPayValDir().size() == 0) {
log.error("No SFTP scanning directories, need will be adding setting like 'import-dbf-service.store.sftp-in.sftp-src-pay-val-dir.VAL=/VAL' and restart app");
return;
}
List<File> files = new ArrayList<>();
for (String path : settings.getStore().getSftpIn().getSftpSrcPayValDir().values()) {
files.addAll(gateway.listFiles(path));
}
if (files.size() > 0) log.info("Loaded from SFTP files count={}", files.size());
}
} }

View file

@ -14,6 +14,8 @@ import-dbf-service.common.insert-batch-size=100
import-dbf-service.common.threads-count=10 import-dbf-service.common.threads-count=10
#sftpSrcDir #sftpSrcDir
import-dbf-service.store.sftp-in.sftp-src-pay-val-dir.rub=clearing_importer_sftp/rub/
import-dbf-service.store.sftp-in.sftp-src-pay-val-dir.eur=clearing_importer_sftp/eur/
import-dbf-service.store.sftp-in.sftp-src-dir=clearing_importer_sftp import-dbf-service.store.sftp-in.sftp-src-dir=clearing_importer_sftp
import-dbf-service.store.sftp-in.user=user import-dbf-service.store.sftp-in.user=user
import-dbf-service.store.sftp-in.password=********* import-dbf-service.store.sftp-in.password=*********

View file

@ -0,0 +1,46 @@
package ru.spcex.clearing.dbf.importer.logic.data.tables;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.spcex.clearing.dbf.importer.config.settings.ImportDBFServiceSettings;
import ru.spcex.clearing.dbf.importer.logic.data.enums.ETable;
import ru.spcex.clearing.dbf.importer.logic.stages.ChangeDirOfFileStage;
import ru.spcex.clearing.dbf.importer.services.FileChecker;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
@ContextConfiguration(classes = {FileChecker.class, ChangeDirOfFileStage.class})
@EnableConfigurationProperties(value = ImportDBFServiceSettings.class)
@ExtendWith(SpringExtension.class)
class FileWorkTest {
@Autowired
FileChecker fileChecker;
@Autowired
ChangeDirOfFileStage changeDirOfFileStage;
@BeforeAll
static void setProperty() {
Path path = Paths.get("src", "main", "resources");
String currentPath = path.toAbsolutePath().toString();
System.setProperty("spring.config.location", currentPath);
}
@Disabled
@Test
void checkNewFiles() {
Map<ETable, List<File>> newFiles = fileChecker.checkNewFiles(null);
newFiles.size();
}
}

View file

@ -1,11 +1,14 @@
package ru.spcex.platform.utils.config; package ru.spcex.platform.utils.config;
import java.util.Map;
public class SftpInboundFolderSetting { public class SftpInboundFolderSetting {
private String sftpSrcDir; private String sftpSrcDir;
private String user; private String user;
private String password; private String password;
private String serverIp; private String serverIp;
private int serverPort; private int serverPort;
private Map<String, String> sftpSrcPayValDir;
public String getSftpSrcDir() { public String getSftpSrcDir() {
return sftpSrcDir; return sftpSrcDir;
@ -46,4 +49,12 @@ public class SftpInboundFolderSetting {
public void setServerPort(int serverPort) { public void setServerPort(int serverPort) {
this.serverPort = serverPort; this.serverPort = serverPort;
} }
public Map<String, String> getSftpSrcPayValDir() {
return sftpSrcPayValDir;
}
public void setSftpSrcPayValDir(Map<String, String> sftpSrcPayValDir) {
this.sftpSrcPayValDir = sftpSrcPayValDir;
}
} }