您当前的位置: 首页 >  spring

水的精神

暂无认证

  • 2浏览

    0关注

    711博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

springBoot 使用 SFTP

水的精神 发布时间:2019-10-14 21:38:49 ,浏览量:2

这篇文章转发别人的,挺不错的,过段时间把自己的分享出来。

Spring Boot实现SFTP文件上传下载 1.实现背景及现实意义 近期由于系统迁移到docker容器,采用Spring Boot 框架实现微服务治理,在此基础上晚间批量文件服务器也由ftp改成sftp,由于之前ftp的实现是采用公具类的形式,在此基础之上,未屏蔽开发细节和依赖Spring Boot自动装配的特性,进行组件的自动装配和改造,旨在实现简化开发,提高文件传输的安全性和数据交互的可靠性。

2.什么是sftp sftp是SSH File Transfer Protocol的缩写,安全文件传送协议。可以为传输文件提供一种安全的网络的加密方法。sftp 与 ftp 有着几乎一样的语法和功能。SFTP 为 SSH的其中一部分,是一种传输档案至 Blogger 伺服器的安全方式。其实在SSH软件包中,已经包含了一个叫作SFTP(Secure File Transfer Protocol)的安全文件信息传输子系统,SFTP本身没有单独的守护进程,它必须使用sshd守护进程(端口号默认是22)来完成相应的连接和答复操作,所以从某种意义上来说,SFTP并不像一个服务器程序,而更像是一个客户端程序。SFTP同样是使用加密传输认证信息和传输的数据,所以,使用SFTP是非常安全的。但是,由于这种传输方式使用了加密/解密技术,所以传输效率比普通的FTP要低得多。

3.sftp文件传输在java中的实现一 3.1Maven依赖     com.jcraft     jsch     0.1.54 3.2sftp相关config封装 /**  * @ClassName: SftpConfig  * @Description: sftp配置类  * @Author: 尚先生  * @CreateDate: 2019/1/7  * @Version: 1.0  */ public class SftpConfig {

    private String hostname;     private Integer port;     private String username;     private String password;     private Integer timeout;     private Resource privateKey;     private String remoteRootPath;     private String fileSuffix;

    public String getHostname() {         return hostname;     }

    public void setHostname(String hostname) {         this.hostname = hostname;     }

    public Integer getPort() {         return port;     }

    public void setPort(Integer port) {         this.port = port;     }

    public String getUsername() {         return username;     }

    public void setUsername(String username) {         this.username = username;     }

    public String getPassword() {         return password;     }

    public void setPassword(String password) {         this.password = password;     }

    public Integer getTimeout() {         return timeout;     }

    public void setTimeout(Integer timeout) {         this.timeout = timeout;     }

    public Resource getPrivateKey() {         return privateKey;     }

    public void setPrivateKey(Resource privateKey) {         this.privateKey = privateKey;     }

    public String getRemoteRootPath() {         return remoteRootPath;     }

    public void setRemoteRootPath(String remoteRootPath) {         this.remoteRootPath = remoteRootPath;     }

    public String getFileSuffix() {         return fileSuffix;     }

    public void setFileSuffix(String fileSuffix) {         this.fileSuffix = fileSuffix;     }

    public SftpConfig(String hostname, Integer port, String username, String password, Integer timeout, Resource privateKey, String remoteRootPath, String fileSuffix) {         this.hostname = hostname;         this.port = port;         this.username = username;         this.password = password;         this.timeout = timeout;         this.privateKey = privateKey;         this.remoteRootPath = remoteRootPath;         this.fileSuffix = fileSuffix;     }     public SftpConfig(String hostname, Integer port, String username, String password, Integer timeout, String remoteRootPath) {         this.hostname = hostname;         this.port = port;         this.username = username;         this.password = password;         this.timeout = timeout;         this.remoteRootPath = remoteRootPath;     }     public SftpConfig() {     } } 3.3sftp工具类实现 /**  * @ClassName: SFTP  * @Description: sftp上传通用类  * @Author: 尚先生  * @CreateDate: 2019/1/3  * @Version: 1.0  */ public class SFTP {

    private long count;     /**      * 已经连接次数      */     private long count1 = 0;

    private long sleepTime;

    private static final Logger logger = LoggerFactory.getLogger(SFTP.class);

    /**      * 连接sftp服务器      *      * @return      */     public ChannelSftp connect(SftpConfig sftpConfig) {         ChannelSftp sftp = null;         try {             JSch jsch = new JSch();             jsch.getSession(sftpConfig.getUsername(), sftpConfig.getHostname(), sftpConfig.getPort());             Session sshSession = jsch.getSession(sftpConfig.getUsername(), sftpConfig.getHostname(), sftpConfig.getPort());             logger.info("Session created ... UserName=" + sftpConfig.getUsername() + ";host=" + sftpConfig.getHostname() + ";port=" + sftpConfig.getPort());             sshSession.setPassword(sftpConfig.getPassword());             Properties sshConfig = new Properties();             sshConfig.put("StrictHostKeyChecking", "no");             sshSession.setConfig(sshConfig);             sshSession.connect();             logger.info("Session connected ...");             logger.info("Opening Channel ...");             Channel channel = sshSession.openChannel("sftp");             channel.connect();             sftp = (ChannelSftp) channel;             logger.info("登录成功");         } catch (Exception e) {             try {                 count1 += 1;                 if (count == count1) {                     throw new RuntimeException(e);                 }                 Thread.sleep(sleepTime);                 logger.info("重新连接....");                 connect(sftpConfig);             } catch (InterruptedException e1) {                 throw new RuntimeException(e1);             }         }         return sftp;     }

    /**      * 上传文件      *      * @param directory  上传的目录      * @param uploadFile 要上传的文件      * @param sftpConfig      */     public void upload(String directory, String uploadFile, SftpConfig sftpConfig) {         ChannelSftp sftp = connect(sftpConfig);         try {             sftp.cd(directory);         } catch (SftpException e) {             try {                 sftp.mkdir(directory);                 sftp.cd(directory);             } catch (SftpException e1) {                 throw new RuntimeException("ftp创建文件路径失败" + directory);             }         }         File file = new File(uploadFile);         InputStream inputStream=null;         try {             inputStream = new FileInputStream(file);             sftp.put(inputStream, file.getName());         } catch (Exception e) {             throw new RuntimeException("sftp异常" + e);         } finally {             disConnect(sftp);             closeStream(inputStream,null);         }     }

    /**      * 下载文件      *      * @param directory    下载目录      * @param downloadFile 下载的文件      * @param saveFile     存在本地的路径      * @param sftpConfig      */     public void download(String directory, String downloadFile, String saveFile, SftpConfig sftpConfig) {         OutputStream output = null;         try {             File localDirFile = new File(saveFile);             // 判断本地目录是否存在,不存在需要新建各级目录             if (!localDirFile.exists()) {                 localDirFile.mkdirs();             }             if (logger.isInfoEnabled()) {                 logger.info("开始获取远程文件:[{}]---->[{}]", new Object[]{directory, saveFile});             }             ChannelSftp sftp = connect(sftpConfig);             sftp.cd(directory);             if (logger.isInfoEnabled()) {                 logger.info("打开远程文件:[{}]", new Object[]{directory});             }             output = new FileOutputStream(new File(saveFile.concat(File.separator).concat(downloadFile)));             sftp.get(downloadFile, output);             if (logger.isInfoEnabled()) {                 logger.info("文件下载成功");             }             disConnect(sftp);         } catch (Exception e) {             if (logger.isInfoEnabled()) {                 logger.info("文件下载出现异常,[{}]", e);             }             throw new RuntimeException("文件下载出现异常,[{}]", e);         } finally {             closeStream(null,output);         }     }

    /**      * 下载远程文件夹下的所有文件      *      * @param remoteFilePath      * @param localDirPath      * @throws Exception      */     public void getFileDir(String remoteFilePath, String localDirPath, SftpConfig sftpConfig) throws Exception {         File localDirFile = new File(localDirPath);         // 判断本地目录是否存在,不存在需要新建各级目录         if (!localDirFile.exists()) {             localDirFile.mkdirs();         }         if (logger.isInfoEnabled()) {             logger.info("sftp文件服务器文件夹[{}],下载到本地目录[{}]", new Object[]{remoteFilePath, localDirFile});         }         ChannelSftp channelSftp = connect(sftpConfig);         Vector lsEntries = channelSftp.ls(remoteFilePath);         if (logger.isInfoEnabled()) {             logger.info("远程目录下的文件为[{}]", lsEntries);         }         for (LsEntry entry : lsEntries) {             String fileName = entry.getFilename();             if (checkFileName(fileName)) {                 continue;             }             String remoteFileName = getRemoteFilePath(remoteFilePath, fileName);             channelSftp.get(remoteFileName, localDirPath);         }         disConnect(channelSftp);     }

    /**      * 关闭流      * @param outputStream      */     private void closeStream(InputStream inputStream,OutputStream outputStream) {         if (outputStream != null) {             try {                 outputStream.close();             } catch (IOException e) {                 e.printStackTrace();             }         }         if(inputStream != null){             try {                 inputStream.close();             } catch (IOException e) {                 e.printStackTrace();             }         }     }

    private boolean checkFileName(String fileName) {         if (".".equals(fileName) || "..".equals(fileName)) {             return true;         }         return false;     }

    private String getRemoteFilePath(String remoteFilePath, String fileName) {         if (remoteFilePath.endsWith("/")) {             return remoteFilePath.concat(fileName);         } else {             return remoteFilePath.concat("/").concat(fileName);         }     }

    /**      * 删除文件      *      * @param directory  要删除文件所在目录      * @param deleteFile 要删除的文件      * @param sftp      */     public void delete(String directory, String deleteFile, ChannelSftp sftp) {         try {             sftp.cd(directory);             sftp.rm(deleteFile);         } catch (Exception e) {             throw new RuntimeException(e);         }     }

    /**      * 列出目录下的文件      *      * @param directory  要列出的目录      * @param sftpConfig      * @return      * @throws SftpException      */     public List listFiles(String directory, SftpConfig sftpConfig) throws SftpException {         ChannelSftp sftp = connect(sftpConfig);         List fileNameList = new ArrayList();         try {             sftp.cd(directory);         } catch (SftpException e) {             return fileNameList;         }         Vector vector = sftp.ls(directory);         for (int i = 0; i < vector.size(); i++) {             if (vector.get(i) instanceof LsEntry) {                 LsEntry lsEntry = (LsEntry) vector.get(i);                 String fileName = lsEntry.getFilename();                 if (".".equals(fileName) || "..".equals(fileName)) {                     continue;                 }                 fileNameList.add(fileName);             }         }         disConnect(sftp);         return fileNameList;     }

    /**      * 断掉连接      */     public void disConnect(ChannelSftp sftp) {         try {             sftp.disconnect();             sftp.getSession().disconnect();         } catch (Exception e) {             e.printStackTrace();         }     }

    public SFTP(long count, long sleepTime) {         this.count = count;         this.sleepTime = sleepTime;     }

    public SFTP() {

    } } 3.4测试类实现 /**  * @ClassName: TestSFTPUtils  * @Description: SFTP工具类测试类  * @Author: 尚先生  * @CreateDate: 2019/4/25 11:09  * @Version: 1.0  */ public class TestSFTPUtils {

    private static final Logger logger = LoggerFactory.getLogger(TestSFTPUtils.class);          public static void main(String[] args) {             SFTP ftp = new SFTP(3, 6000);             SftpConfig sftpConfig = new SftpConfig("10.0.155.55", 22, "test", "test", 1000, "/opt/bdepfile/bdp/tset/20190425");             try {                 List list = ftp.listFiles("/opt/bdepfile/bdp/pucms/20190108", sftpConfig);                 logger.info("文件上传下载详情"  ,new Object[]{list});             } catch (SftpException e) {                 logger.error("文件上传下载异常:[{}]" ,new Object[]{e});             }         } } 4.sftp文件传输在java中的实现二 4.1Maven依赖     com.jcraft     jsch     0.1.54 4.2扩展上述工具类的实现 4.2.1SFTP.java改造 /**  * @ClassName: SFTP  * @Description: sftp上传通用类  * @Author: 尚先生  * @CreateDate: 2019/1/3  * @Version: 1.0  */ @Component public class SFTP {

    private ChannelSftp channelSftp;

    @Value("${sftp.remotepath}")     private String remotepath;

    @Value("${sftp.localpath}")     private String localpath;

    @Value("${sftp.filenames}")     private String filenames;

    private static final String COMPLATEG_FILE_FLAG = "over_%s.dat";

    private static final Logger logger = LoggerFactory.getLogger(SFTP.class);     ...     public void setChannelSftp(ChannelSftp channelSftp) {         this.channelSftp = channelSftp;     }

    /**      *      * @param remotePath      * @param remoteFileName      * @param localPath      * @param localFileName      * @return      */     public boolean downloadFile(String remotePath, String remoteFileName, String localPath, String localFileName){         logger.info("开始下载文件,远程路径:[{}],本地路径:[{}],文件名称:[{}]",new Object[]{remotePath,localPath,remoteFileName});         FileOutputStream fileOutputStream = null;         File file = new File(localPath + localFileName);         try {             fileOutputStream = new FileOutputStream(file);             channelSftp.get(remotePath + remoteFileName,fileOutputStream);             return true;         } catch (Exception e) {             logger.error("sftp下载文件失败:[{}]",new Object[]{e});             return false;         }     }

    /**      * 单个ok文件下载      * @param trandate      * @return      */     public boolean downloadOKFile(String trandate){         trandate = trandate.replace("-", "");         String localDirPath = localpath.concat("/").concat(trandate);         File localDirFile = new File(localDirPath);         if (!localDirFile.exists()){             localDirFile.mkdirs();         }else {             logger.info("文件[{}]已存在",new Object[]{localDirPath});             if (!localDirFile.isDirectory()){                 logger.error("文件[{}]已存在,但不是目录,文件下载失败",new Object[]{localDirPath});                 throw new RuntimeException(String.format("本地文件[{%s}]已存在,但不是目录,不能创建文件",localDirPath));             }         }         String filename = String.format(COMPLATEG_FILE_FLAG, trandate);         String remoteFilePath = remotepath.concat("/").concat(trandate).concat("/");         String localFilePath = localDirPath.concat("/");         boolean flag = downloadFile(remoteFilePath, filename, localFilePath, filename);         return flag;     }

    /**      * 多个文件下载      * @param trandate      * @return      */     public boolean downloadCoreFilesToLocal(String trandate){         boolean flag = false;         trandate = trandate.replace("-", "");         String localDirPath = localpath.concat("/").concat(trandate).concat("/");         String remoteDirPath = remotepath.concat("/").concat(trandate).concat("/");         for (String coreFileName : filenames.split(",")){             //文件名称截取             String coreFilaName = String.format(coreFileName.trim(), trandate);             flag = downloadFile(remoteDirPath, coreFileName, localDirPath, coreFileName);         }         return flag;     }

} 4.2.2自动装配Sftp连接器 /**  * @ClassName: SftpClientConfigure  * @Description: 自动装配Sftp连接器  * @Author: 尚先生  * @CreateDate: 2019/4/25  * @Version: 1.0  */ @Configuration @ConfigurationProperties(prefix = "sftp") public class SftpClientConfigure {

    private String hostname;     private Integer port;     private String username;     private String password;     private Integer timeout;     private String privateKey;     private String remoteRootPath;     private String fileSuffix;

    // 通道类型     private static final String CHANNEL_TYPE = "sftp";

    private static final Logger logger = LoggerFactory.getLogger(SftpClientConfigure.class);

    public String getHostname() {         return hostname;     }

    public void setHostname(String hostname) {         this.hostname = hostname;     }

    public Integer getPort() {         return port;     }

    public void setPort(Integer port) {         this.port = port;     }

    public String getUsername() {         return username;     }

    public void setUsername(String username) {         this.username = username;     }

    public String getPassword() {         return password;     }

    public void setPassword(String password) {         this.password = password;     }

    public String getPrivateKey() {         return privateKey;     }

    public void setPrivateKey(String privateKey) {         this.privateKey = privateKey;     }

    public String getRemoteRootPath() {         return remoteRootPath;     }

    public void setRemoteRootPath(String remoteRootPath) {         this.remoteRootPath = remoteRootPath;     }

    public String getFileSuffix() {         return fileSuffix;     }

    public void setFileSuffix(String fileSuffix) {         this.fileSuffix = fileSuffix;     }

    public Integer getTimeout() {         return timeout;     }

    public void setTimeout(Integer timeout) {         this.timeout = timeout;     }

    @Bean("sshSession")     @Lazy     @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)     public Session session() throws JSchException {         if (logger.isInfoEnabled()) {             logger.info("获取session,设置的超时时间为[{}]毫秒", timeout);         }         JSch jsch = new JSch();         Session session = jsch.getSession(username, hostname, port);         // 设置秘钥 //        jsch.addIdentity(privateKey);         session.setPassword(password);         Properties config = new Properties();         config.put("StrictHostKeyChecking", "no");         session.setConfig(config);  //为Session对象设置properties         session.setTimeout(timeout);  //设置timeout时间         session.connect();  //通过Session建立链接         return session;     }

    @Bean("coreSftpChannel")     @Lazy     @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)     public ChannelSftp channel(Session session) throws JSchException {         if (logger.isInfoEnabled()) {             logger.info("初始化sftp连接");         }         Channel channel = session.openChannel(CHANNEL_TYPE);  //打开SFTP通道         channel.connect();  //建立SFTP通道的连接         return (ChannelSftp) channel;     }

} 4.2.3配置文件 # sftp配置 sftp.hostname=10.0.155.55

sftp.port=22

sftp.username=test

sftp.password=test

sftp.timeout=6000

sftp.privateKey=

sftp.remotepath=/opt/bdepfile/bdp/tset

sftp.localpath=D:/core

sftp.filenames=duebillInfo_%s.dat,repayInfo_%s.dat 4.2.4测试类实现 /**  * @ClassName: TestAutoConfigurationSFTP  * @Description: SftpClientConfigure测试类  * @Author: 尚先生  * @CreateDate: 2019/4/25  * @Version: 1.0  */ @RunWith(SpringRunner.class) @SpringBootTest public class TestAutoConfigurationSFTP {

    private static final Logger logger = LoggerFactory.getLogger(TestAutoConfigurationSFTP.class);

    @Autowired     @Qualifier("coreSftpChannel")     private ChannelSftp channelSftp;

    @Autowired     private SFTP sftp;

    @Test     public void testAotuDownload(){         String trandate = "2019-04-25";         boolean flag = false;         sftp.setChannelSftp(channelSftp);         flag = sftp.downloadOKFile(trandate);         flag = sftp.downloadCoreFilesToLocal(trandate);         logger.error("下载文件结果:[{}]",new Object[]{flag});     } } 4.2.5测试结果 打开 Git Bash Here cd D:\core ll     20190425 cd 20190425 ll -als     ./     ../     duebillInfo_20190425.dat     repayInfo_20190425.dat     over_20190425.dat 4.3sftp扩展实现 由于当前Spring Boot环境实现,采用的是Spring Boot"自动装配"实现的,自动注入并调用实现从核心拉取文件的功能。

在项目中取固定文件时,只需动态追加或者替换下面的配置项sftp.filenames=duebillInfo_%s.dat,repayInfo_%s.dat

如果是新增sftp连接时可以手动创建

SftpConfig config = new SftpConfig();

SFTP sftp = new SFTP();

sftp.download(directory, downloadFile, saveFile, sftpConfig)

至此,多种方式实现sftp文件传输可以共存,而且在系统中可以实现"自动装配"。

完整代码和相关依赖请见GitHub https://github.com/dwyanewede/project-learn/tree/master/src/main/java/com/learn/demo/sftp

关注
打赏
1664074814
查看更多评论
立即登录/注册

微信扫码登录

0.0438s