对sftp文件上传将行封装,实现连接的单例模式,完成线程安全的改进,sftp文件上传下载失败的重试。
application.yml配置文件
sftp: ip: 192.168.43.102 port: 22 username: admin password: admin downloadSleep: 100 #文件下载失败下次超时重试时间 downloadRetry: 10 #文件下载失败重试次数 uploadSleep: 100 #文件上传失败下次超时重试时间 uploadRettry: 10 #文件上传失败重试次数
SFTPClientUtils.java
包含sftp文件上传的一些基本方法,单个上传,批量下载,单个文件下载
@Component @ConfigurationProperties(prefix = "sftp") public class SFTPClientUtils { private static int downloadSleep; private static int downloadRetry; private static int uploadSleep; private static int uploadRettry; private static Logger LOGGER = LoggerFactory.getLogger(SFTPClientUtils.class); /** * 文件上传 * 将文件对象上传到sftp作为文件。文件完整路径=basePath+directory * 目录不存在则会上传文件夹 * @param basePath 服务器的基础路径 * @param directory 上传到该目录 * @param sftpFileName sftp端文件名 * @param file 文件对象 */ public synchronized static boolean upload(String basePath,String directory, String filePath){ boolean result = false; Integer i = 0; while(!result){ ChannelSftp sftp = SFTPConnectionFactory.getInstance().makeConnection(); try { sftp.cd(basePath); sftp.cd(directory); } catch (SftpException e) { LOGGER.info("sftp文件上传,目录不存在开始创建"); String [] dirs=directory.split("/"); String tempPath=basePath; for(String dir:dirs){ if(null== dir || "".equals(dir)) continue; tempPath+="/"+dir; try{ sftp.cd(tempPath); }catch(SftpException ex){ try { sftp.mkdir(tempPath); sftp.cd(tempPath); } catch (SftpException e1) { LOGGER.error("sftp文件上传,目录创建失败,错误信息:"+e1.getMessage()+ex.getMessage()); } } } } try { File file = new File(filePath); sftp.put(new FileInputStream(file) , file.getName()); if(i>0){ LOGGER.info("sftp重试文件上传成功,ftp路径:"+basePath+directory+",文件名称:"+file.getName()); }else{ LOGGER.info("sftp文件上传成功,ftp路径为"+basePath+directory+",文件名称:"+file.getName()); } result = true; } catch (Exception e) { i++; LOGGER.error("sftp文件上传失败,重试中。。。第"+i+"次,错误信息"+e.getMessage()); if(i>uploadRettry){ LOGGER.error("sftp文件上传失败,超过重试次数结束重试,错误信息"+e.getMessage()); return result; } try { TimeUnit.MILLISECONDS.sleep(uploadSleep); } catch (InterruptedException e1) { e1.printStackTrace(); } } } return result; } /** * 下载文件。 * @param directory 下载目录 * @param downloadFile 下载的文件 * @param saveFile 存在本地的路径 */ public synchronized static boolean download(String directory, String downloadFile, String saveFile){ boolean result = false; Integer i = 0; while(!result){ ChannelSftp sftp = SFTPConnectionFactory.getInstance().makeConnection(); if (directory != null && !"".equals(directory)) { try { sftp.cd(directory); } catch (SftpException e) { LOGGER.error("sftp文件下载,目录不存在,错误信息"+e.getMessage()); } } File file = new File(saveFile+downloadFile); FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(file); } catch (FileNotFoundException e1) { LOGGER.error("sftp文件下载失败,本地目录不存在"+e1.getMessage()); } try { sftp.get(downloadFile, fileOutputStream); if(i>0){ LOGGER.info("sftp文件重试下载成功,sftp地址:"+directory+",本地文件地址:"+saveFile); }else{ LOGGER.info("sftp文件下载成功,sftp地址:"+directory+",本地文件地址:"+saveFile); } result = true; } catch (SftpException e1) { i++; LOGGER.error("sftp文件下载失败,重试中。。。第"+i+"次,错误信息"+e1.getMessage()); if(i>downloadRetry){ LOGGER.error("ftp文件下载失败,超过重试次数结束重试,错误信息"+e1.getMessage()); return result; } try { TimeUnit.MILLISECONDS.sleep(downloadSleep); } catch (Exception e2) { e2.printStackTrace(); } }finally { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return result; } /** * 删除文件 * @param directory 要删除文件所在目录 * @param deleteFile 要删除的文件 */ public synchronized static boolean delete(String directory, String deleteFile){ boolean result = false; ChannelSftp sftp = SFTPConnectionFactory.getInstance().makeConnection(); try { sftp.cd(directory); sftp.rm(deleteFile); } catch (SftpException e) { // TODO Auto-generated catch block e.printStackTrace(); } result = true; return result; } public static int getDownloadSleep() { return downloadSleep; } public static void setDownloadSleep(int downloadSleep) { SFTPClientUtils.downloadSleep = downloadSleep; } public static int getDownloadRetry() { return downloadRetry; } public static void setDownloadRetry(int downloadRetry) { SFTPClientUtils.downloadRetry = downloadRetry; } public static int getUploadSleep() { return uploadSleep; } public static void setUploadSleep(int uploadSleep) { SFTPClientUtils.uploadSleep = uploadSleep; } public static int getUploadRettry() { return uploadRettry; } public static void setUploadRettry(int uploadRettry) { SFTPClientUtils.uploadRettry = uploadRettry; } }
SFTPConnectionFactory.java
是生成sftp上传对象的工场类
/** * SFTP工厂类,用于获取SFTP的连接 * @author 奇点_ */ @Component @ConfigurationProperties(prefix = "sftp") public class SFTPConnectionFactory { private static Logger LOGGER = LoggerFactory.getLogger(FTPClientUtils.class); /** SFTP 登录用户名*/ private static String username; /** SFTP 登录密码*/ private static String password; /** 私钥 */ private static String privateKey; /** SFTP 服务器地址IP地址*/ private static String ip; /** SFTP 端口*/ private static int port; private static final SFTPConnectionFactory factory = new SFTPConnectionFactory(); private ChannelSftp client; private Session session; private SFTPConnectionFactory(){ } public static SFTPConnectionFactory getInstance(){ return factory; } synchronized public ChannelSftp makeConnection(){ if(client==null||session==null||!client.isConnected()||!session.isConnected()){ try { JSch jsch = new JSch(); if (privateKey != null) { jsch.addIdentity(privateKey);// 设置私钥 } session = jsch.getSession(username, ip, 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(); client = (ChannelSftp) channel; LOGGER.info("sftp服务器连接成功"); } catch (JSchException e) { LOGGER.error("sftp登录失败,检测登录ip,端口号,用户名密码是否正确,错误信息为"+e.getMessage()); } } return client; } /** * 关闭连接 server */ public void logout(){ if (client != null) { if (client.isConnected()) { client.disconnect(); } } if (session != null) { if (session.isConnected()) { session.disconnect(); } } } public static String getUsername() { return username; } public static void setUsername(String username) { SFTPConnectionFactory.username = username; } public static String getPassword() { return password; } public static void setPassword(String password) { SFTPConnectionFactory.password = password; } public static String getPrivateKey() { return privateKey; } public static void setPrivateKey(String privateKey) { SFTPConnectionFactory.privateKey = privateKey; } public static String getIp() { return ip; } public static void setIp(String ip) { SFTPConnectionFactory.ip = ip; } public static int getPort() { return port; } public static void setPort(int port) { SFTPConnectionFactory.port = port; } }
pom.xml 依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>fakepath</groupId> <artifactId>ftp4j</artifactId> <version>1.7.2</version> </dependency> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.54</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> </dependencies>