引言
最近项目中对接了几个将客户,在案件传输的时候都采用SFTP + excel 或者 csv的方式传输,下面分享一下小编在项目中对sftp操作的封装的工具类。同时分享一下在实际中的应用。
1、相关包依赖
<dependency> <groupId>org.apache.sshd</groupId> <artifactId>sshd-sftp</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.54</version> </dependency> <!-- https://mvnrepository.com/artifact/com.trilead/trilead-ssh2 --> <dependency> <groupId>com.trilead</groupId> <artifactId>trilead-ssh2</artifactId> <version>1.0.0-build221</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3</version> </dependency>
2、SFTPutil工具类
package com.jack.cmbc.tools; import com.jcraft.jsch.*; import org.apache.poi.util.IOUtils; import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.Vector; /** * Created by zhenghao on 2018/9/18. */ public class SFTPUtil { private ChannelSftp sftp; private Session session; /** * SFTP 登录用户名 */ private String username; /** * SFTP 登录密码 */ private String password; /** * 私钥 */ private String privateKey; /** * SFTP 服务器地址IP地址 */ private String host; /** * SFTP 端口 */ private int port; /** * 构造基于密码认证的sftp对象 */ public SFTPUtil(String username, String password, String host, int port) { this.username = username; this.password = password; this.host = host; this.port = port; } /** * 构造基于秘钥认证的sftp对象 */ public SFTPUtil(String username, String host, int port, String privateKey) { this.username = username; this.host = host; this.port = port; this.privateKey = privateKey; } public SFTPUtil() { } /** * 连接sftp服务器 */ public void login() { try { JSch jsch = new JSch(); if (privateKey != null) { jsch.addIdentity(privateKey);// 设置私钥 } session = jsch.getSession(username, host, port); if (password != null) { session.setPassword(password); } Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); session.connect(); Channel channel = session.openChannel("sftp"); channel.connect(); sftp = (ChannelSftp) channel; } catch (JSchException e) { e.printStackTrace(); } } /** * 关闭连接 server */ public void logout() { if (sftp != null) { if (sftp.isConnected()) { sftp.disconnect(); } } if (session != null) { if (session.isConnected()) { session.disconnect(); } } } /** * 将输入流的数据上传到sftp作为文件。文件完整路径=basePath+directory * * @param directory 上传到该目录 * @param sftpFileName sftp端文件名 */ public boolean upload(String directory, String sftpFileName, InputStream input) throws SftpException { try { if (directory != null && !"".equals(directory)) { sftp.cd(directory); } sftp.put(input, sftpFileName); //上传文件 return true; } catch (SftpException e) { return false; } } public void cd(String directory) throws SftpException { if (directory != null && !"".equals(directory) && !"/".equals(directory)) { sftp.cd(directory); } } /** * 下载文件。 * * @param directory 下载目录 * @param downloadFile 下载的文件 * @param saveFile 存在本地的路径 */ public void download(String directory, String downloadFile, String saveFile) { System.out.println("download:" + directory + " downloadFile:" + downloadFile + " saveFile:" + saveFile); File file = null; try { if (directory != null && !"".equals(directory)) { sftp.cd(directory); } file = new File(saveFile); sftp.get(downloadFile, new FileOutputStream(file)); } catch (SftpException e) { e.printStackTrace(); if (file != null) { file.delete(); } } catch (FileNotFoundException e) { e.printStackTrace(); if (file != null) { file.delete(); } } } /** * 下载文件 * * @param directory 下载目录 * @param downloadFile 下载的文件名 * @return 字节数组 */ public byte[] download(String directory, String downloadFile) throws SftpException, IOException { if (directory != null && !"".equals(directory)) { sftp.cd(directory); } InputStream is = sftp.get(downloadFile); byte[] fileData = IOUtils.toByteArray(is); return fileData; } /** * 删除文件 * * @param directory 要删除文件所在目录 * @param deleteFile 要删除的文件 */ public void delete(String directory, String deleteFile) throws SftpException { if (directory != null && !"".equals(directory)) { sftp.cd(directory); } sftp.rm(deleteFile); } /** * 列出目录下的文件 * * @param directory 要列出的目录 */ public Vector<?> listFiles(String directory) throws SftpException { return sftp.ls(directory); } public boolean isExistsFile(String directory, String fileName) { List<String> findFilelist = new ArrayList(); ChannelSftp.LsEntrySelector selector = new ChannelSftp.LsEntrySelector() { @Override public int select(ChannelSftp.LsEntry lsEntry) { if (lsEntry.getFilename().equals(fileName)) { findFilelist.add(fileName); } return 0; } }; try { sftp.ls(directory, selector); } catch (SftpException e) { e.printStackTrace(); } if (findFilelist.size() > 0) { return true; } else { return false; } } //上传文件测试 public static void main(String[] args) throws SftpException, IOException { SFTPUtil sftp = new SFTPUtil("xxx", "xxx", "xx.com.cn", 22); sftp.login(); File file = new File("/Volumes/work/new1.xlsx"); InputStream is = new FileInputStream(file); //sftp.upload("/test", "", "test_sftp.jpg", is); sftp.logout(); } }
3、下载文件使用
package com.jack.xxxx.service; import com.jack.xxxx.tools.FileUtils; import com.jack.xxxx.tools.GPGUtil; import com.jack.xxxx.tools.SFTPUtil; import com.jack.common.exception.TpErrorCodeGeneral; import com.jack.common.model.BaseResult; import com.jack.common.utils.DateUtils; import com.jack.common.utils.service.ErrorLogService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * @Description: * @author: zhenghao * @date: 2019/6/12 10:04 */ @Service public class XiaoMiFtpService { @Resource ErrorLogService errorLogService; @Autowired private XiaoMiNotifyService notifyService; @Value("${xiaomi_ftp_host}") private String xiaomiFtpHost; @Value("${xiaomi_ftp_port}") private String xiaomiFtpPort; @Value("${xiaomi_ftp_user}") private String xiaomiFtpUser; @Value("${xiaomi_prikey_file}") private String xiaomiPriKeyFile; @Value("${xiaomi_ftp_local_file_path}") private String XIAOMI_LOCAL_FilPath; private static final String SFTPDirectory = "/home"; private static String todayDownLoadFile = null; private static String todayCsvFilePath = null; private static String todayGpgFilePath = null; private boolean firstExistsFileFlag = false; /** * 为了保证服务器上文件上传结束,做一次文件保护 */ public void sync( int times) { String localFilePath = this.initLocalFilePath(); //zhiqing6.12-1.xlsx ==zhiqing月份.几号-当天第几次.xlsx String gpgFileName = "zhiqing" + DateUtils.getCurrentMonth() + "." + DateUtils.getCurrentDay() + "-" + times +".xlsx"; //判断今日是否下载成功了文件 if (gpgFileName.equals(todayDownLoadFile)) { System.out.println(DateUtils.getStrDate()+ " 今日文件已经下载:" + todayDownLoadFile); return; } //判断本地是否存在文件 if (isLocalFileExists(localFilePath + "/" + gpgFileName)) { System.out.println(DateUtils.getStrDate()+" 本地文件已经存在:" + gpgFileName); return; } //初始化服务器链接 SFTPUtil sftpUtil = this.initFtp(); if (sftpUtil == null) { writeErrorMsg("initFtp failed"); return; } //判断服务器上 if (!sftpUtil.isExistsFile(SFTPDirectory, gpgFileName)) { System.out.println(DateUtils.getStrDate()+" 服务器上不存在文件:" + gpgFileName); closeFtp(sftpUtil); return; } if (!firstExistsFileFlag) { System.out.println(DateUtils.getStrDate()+" 第一次发现文件存在:" + gpgFileName); firstExistsFileFlag = true; closeFtp(sftpUtil); return; } //下载文件 String downloadFile = downloadFtpFiles(sftpUtil, localFilePath, gpgFileName); System.out.println(DateUtils.getStrDate()+" 下载文件:" + downloadFile); if (downloadFile != null) { todayDownLoadFile = gpgFileName; todayGpgFilePath = localFilePath + "/" + gpgFileName; todayCsvFilePath = downloadFile; writeErrorMsg("今日文件下载完成:" + todayDownLoadFile); firstExistsFileFlag = false; //通知业务系统进行文件处理 参数为文件全路径 notifyService.notifyFilesChanged(downloadFile); } closeFtp(sftpUtil); } private String downloadFtpFiles(SFTPUtil sftpUtil, String localFilePath, String fileName) { String downloadFileName = null; try { sftpUtil.cd(SFTPDirectory); sftpUtil.download(SFTPDirectory, fileName, localFilePath + "/" + fileName); if (fileName.endsWith(".xlsx")) { downloadFileName = localFilePath + "/" + fileName; } if (downloadFileName != null) { File file = new File(downloadFileName); if (!file.exists()) { System.out.println("本地不存在" + downloadFileName); downloadFileName = null; } } } catch (Exception e) { e.printStackTrace(); } return downloadFileName; } private SFTPUtil initFtp() { //基于秘钥链接sftp SFTPUtil sftp = new SFTPUtil(xiaomiFtpUser, xiaomiFtpHost, Integer.valueOf(xiaomiFtpPort),xiaomiPriKeyFile); sftp.login(); System.out.println("login successed"); return sftp; } private void closeFtp(SFTPUtil sftp) { try { sftp.logout(); } catch (Exception e) { e.printStackTrace(); } } private boolean isLocalFileExists(String filePathName) { File file = new File(filePathName); if (file.exists()) { return true; } else { return false; } } private String initLocalFilePath() { String filePath = XIAOMI_LOCAL_FilPath; File file = new File(filePath); file.mkdirs(); return filePath; } private void writeErrorMsg(String msg) { System.out.println(DateUtils.date2FullStr(new Date()) + "=====" + msg); errorLogService.writeErrorLog("", msg); } }
4、定时任务调用
package com.jack.xxxx.task; import com.jack.xxxx.service.xxxxFtpService; import com.jack.xxxx.service.XiaoMiFtpService; import com.jack.common.utils.DateUtils; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @Description: * @author: zhenghao * @date: 2019/6/12 16:30 */ @Component public class SynXiaoMiFtpTask { @Resource XiaoMiFtpService xiaoMiFtpService; /** * @Description: 第一次 导入 * @author: zhenghao * @date: 2019/6/12 16:33 */ @Scheduled(cron = "0 0/2 09 * * ? ") public void firsRrunTask() { System.out.println(DateUtils.getStrDate() + " 小米第一次runTask"); try { xiaoMiFtpService.sync(1); } catch (Exception e) { e.printStackTrace(); } } }
5、配置文件
#sftp地址 xiaomi_ftp_host=xxx.com xiaomi_ftp_user=xxx xiaomi_ftp_port=2222 xiaomi_ftp_local_file_path=/xmdata #秘 xiaomi_prikey_file =/root/xx xiaomi_notify_host_url = http://xx.xx.xx.xx.:8096/xx/xx/xx
6、小结
以上最近使用sftp传送数据的总结,希望对读者有些帮助!