ftp连接池客户端
1、添加ftp配置
1 package com.scenetec.isv.utils.ftp.config; 2 3 import lombok.Getter; 4 import lombok.Setter; 5 import org.apache.commons.net.ftp.FTP; 6 import org.springframework.boot.context.properties.ConfigurationProperties; 7 import org.springframework.stereotype.Component; 8 9 /** 10 * @author shendunyuan@scenetec.com 11 * @date 2018/12/19 12 */ 13 @Getter 14 @Setter 15 @Component 16 @ConfigurationProperties(ignoreUnknownFields = false, prefix = "ftp.client") 17 public class FtpClientProperties { 18 19 /** 20 * ftp地址 21 */ 22 private String host; 23 24 /** 25 * 端口号 26 */ 27 private Integer port = 21; 28 29 /** 30 * 登录用户 31 */ 32 private String username; 33 34 /** 35 * 登录密码 36 */ 37 private String password; 38 39 /** 40 * 被动模式 41 */ 42 private boolean passiveMode = false; 43 44 /** 45 * 编码 46 */ 47 private String encoding = "UTF-8"; 48 49 /** 50 * 连接超时时间(秒) 51 */ 52 private Integer connectTimeout; 53 54 /** 55 * 缓冲大小 56 */ 57 private Integer bufferSize = 1024; 58 59 /** 60 * 设置keepAlive 61 * 单位:秒 0禁用 62 */ 63 private Integer keepAliveTimeout = 0; 64 65 /** 66 * 传输文件类型 67 */ 68 private Integer transferFileType = FTP.BINARY_FILE_TYPE; 69 70 }
1 ftp: 2 client: 3 host: 132.232.68.30 4 port: 21 5 username: isv 6 password: xintai1234 7 passiveMode: true
2、ftp客户端工厂处理类
1 package com.scenetec.isv.utils.ftp.core; 2 3 import com.scenetec.isv.utils.ftp.config.FtpClientProperties; 4 import lombok.extern.slf4j.Slf4j; 5 import org.apache.commons.net.ftp.FTPClient; 6 import org.apache.commons.net.ftp.FTPReply; 7 import org.apache.commons.pool2.BasePooledObjectFactory; 8 import org.apache.commons.pool2.PooledObject; 9 import org.apache.commons.pool2.impl.DefaultPooledObject; 10 import org.springframework.stereotype.Component; 11 12 /** 13 * @author shendunyuan@scenetec.com 14 * @date 2018/12/19 15 */ 16 @Slf4j 17 @Component 18 public class FtpClientFactory extends BasePooledObjectFactory<FTPClient> { 19 20 private FtpClientProperties config; 21 22 public FtpClientFactory(FtpClientProperties config) { 23 this.config = config; 24 } 25 26 @Override 27 public FTPClient create() { 28 29 FTPClient ftpClient = new FTPClient(); 30 ftpClient.setControlEncoding(config.getEncoding()); 31 if (null != config.getConnectTimeout()) { 32 ftpClient.setConnectTimeout(config.getConnectTimeout()); 33 } 34 35 try { 36 ftpClient.connect(config.getHost(), config.getPort()); 37 int replyCode = ftpClient.getReplyCode(); 38 if (!FTPReply.isPositiveCompletion(replyCode)) { 39 ftpClient.disconnect(); 40 log.warn("FTPServer refused connection,replyCode:{}", replyCode); 41 return null; 42 } 43 44 if (!ftpClient.login(config.getUsername(), config.getPassword())) { 45 log.warn("FTPClient login failed... username is {}; password: {}", config.getUsername(), config.getPassword()); 46 } 47 48 ftpClient.setBufferSize(config.getBufferSize()); 49 ftpClient.setFileType(config.getTransferFileType()); 50 if (config.isPassiveMode()) { 51 ftpClient.enterLocalPassiveMode(); 52 } 53 54 } catch (Exception ex) { 55 ex.printStackTrace(); 56 log.error("Failed to create FTP connection"); 57 } 58 59 return ftpClient; 60 } 61 62 void destroyObject(FTPClient client) { 63 destroyObject(wrap(client)); 64 } 65 66 /** 67 * 用PooledObject封装对象放入池中 68 * @param ftpClient ftp客户端 69 * @return 默认池对象 70 */ 71 @Override 72 public PooledObject<FTPClient> wrap(FTPClient ftpClient) { 73 return new DefaultPooledObject<>(ftpClient); 74 } 75 76 /** 77 * 销毁FtpClient对象 78 * @param ftpPooled ftp池对象 79 */ 80 @Override 81 public void destroyObject(PooledObject<FTPClient> ftpPooled) { 82 if (ftpPooled == null) { 83 return; 84 } 85 86 FTPClient ftpClient = ftpPooled.getObject(); 87 88 close(ftpClient); 89 } 90 91 /** 92 * 销毁FtpClient对象 93 * @param client ftp对象 94 */ 95 public void close(FTPClient client) { 96 try { 97 if (client.isConnected()) { 98 client.logout(); 99 } 100 } catch (Exception ex) { 101 ex.printStackTrace(); 102 log.error("Failure to destroy FTP connection pool."); 103 } finally { 104 try { 105 client.disconnect(); 106 } catch (Exception ex) { 107 ex.printStackTrace(); 108 log.error("Failed to close FTP connection pool."); 109 } 110 } 111 } 112 113 /** 114 * 验证FtpClient对象 115 * @param ftpPooled ftp池对象 116 * @return 发送一个NOOP命令到FTP服务器,如果成功返回true,否则为false。 117 */ 118 @Override 119 public boolean validateObject(PooledObject<FTPClient> ftpPooled) { 120 try { 121 FTPClient ftpClient = ftpPooled.getObject(); 122 if (ftpClient == null) { 123 return false; 124 } 125 if (!ftpClient.isConnected()) { 126 return false; 127 } 128 return ftpClient.sendNoOp(); 129 } catch (Exception ex) { 130 ex.printStackTrace(); 131 } 132 return false; 133 } 134 135 }
3、ftp资源池处理类
1 package com.scenetec.isv.utils.ftp.core; 2 3 import lombok.extern.slf4j.Slf4j; 4 import org.apache.commons.net.ftp.FTPClient; 5 import org.apache.commons.pool2.BaseObjectPool; 6 import org.springframework.util.ObjectUtils; 7 8 import java.util.NoSuchElementException; 9 import java.util.concurrent.ArrayBlockingQueue; 10 import java.util.concurrent.BlockingQueue; 11 import java.util.concurrent.TimeUnit; 12 13 /** 14 * @author shendunyuan@scenetec.com 15 * @date 2018/12/19 16 */ 17 @Slf4j 18 public class FtpClientPool extends BaseObjectPool<FTPClient> { 19 20 private static final int DEFAULT_POOL_SIZE = 5; 21 private final BlockingQueue<FTPClient> pool; 22 private final FtpClientFactory factory; 23 24 25 /** 26 * 初始化连接池,需要注入一个工厂来提供FTPClient实例 27 * @param factory 28 */ 29 public FtpClientPool(FtpClientFactory factory) { 30 this(DEFAULT_POOL_SIZE, factory); 31 } 32 33 public FtpClientPool(int poolSize, FtpClientFactory factory) { 34 this.factory = factory; 35 this.pool = new ArrayBlockingQueue<>(poolSize * 2); 36 initPool(poolSize); 37 } 38 39 /** 40 * 初始化连接池,需要注入一个工厂来提供FTPClient实例 41 * @param maxPoolSize 42 */ 43 private void initPool(int maxPoolSize) { 44 try { 45 for (int i = 0; i < maxPoolSize; i++) { 46 addObject(); 47 } 48 } catch (Exception ex) { 49 ex.printStackTrace(); 50 throw new RuntimeException("Failed to initialize FTP thread pool."); 51 } 52 } 53 54 /** 55 * 客户端从池中借出一个对象 56 * @return 57 * @throws Exception 58 * @throws NoSuchElementException 59 * @throws IllegalStateException 60 */ 61 @Override 62 public FTPClient borrowObject() throws Exception, NoSuchElementException, IllegalStateException { 63 FTPClient client = pool.take(); 64 if (ObjectUtils.isEmpty(client)) { 65 // 创建新的连接 66 client = factory.create(); 67 } 68 // 验证对象是否有效 69 else if (!factory.validateObject(factory.wrap(client))) { 70 // 对无效的对象进行处理 71 invalidateObject(client); 72 // 创建新的对象 73 client = factory.create(); 74 } 75 // 返回ftp对象 76 return client; 77 } 78 79 /** 80 * 返还对象到连接池中 81 * @param client 82 * @throws Exception 83 */ 84 @Override 85 public void returnObject(FTPClient client) { 86 try { 87 long timeout = 3L; 88 if (client != null) { 89 if (client.isConnected()) { 90 if (pool.size() < DEFAULT_POOL_SIZE) { 91 // 添加回队列 92 if (!pool.offer(client, timeout, TimeUnit.SECONDS)) { 93 factory.destroyObject(client); 94 } 95 } else { 96 factory.destroyObject(client); 97 } 98 } else { 99 factory.destroyObject(client); 100 } 101 } 102 } catch (Exception ex) { 103 ex.printStackTrace(); 104 log.error("Failed to return FTP connection object."); 105 } 106 } 107 108 /** 109 * 移除无效的对象 110 * @param client 111 * @throws Exception 112 */ 113 @Override 114 public void invalidateObject(FTPClient client) { 115 try { 116 // 移除无效对象 117 pool.remove(client); 118 // 注销对象 119 factory.destroyObject(client); 120 } catch (Exception ex) { 121 ex.printStackTrace(); 122 log.error("Failed to remove invalid FTP object."); 123 } 124 } 125 126 /** 127 * 增加一个新的链接,超时失效 128 * @throws Exception 129 * @throws IllegalStateException 130 * @throws UnsupportedOperationException 131 */ 132 @Override 133 public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { 134 pool.offer(factory.create(), 3, TimeUnit.SECONDS); 135 } 136 137 @Override 138 public void close() { 139 try { 140 while (pool.iterator().hasNext()) { 141 FTPClient client = pool.take(); 142 factory.destroyObject(client); 143 } 144 } catch (Exception ex) { 145 ex.printStackTrace(); 146 log.error("Failed to close FTP object."); 147 } 148 } 149 }
4、ftp上传下载基础处理类
1 package com.scenetec.isv.utils.ftp.template; 2 3 import lombok.extern.slf4j.Slf4j; 4 import org.apache.commons.lang3.StringUtils; 5 import org.apache.commons.net.ftp.FTPClient; 6 7 import java.io.*; 8 9 /** 10 * @author shendunyuan@scenetec.com 11 * @date 2019/1/22 12 */ 13 @Slf4j 14 public abstract class FtpBaseTemplate { 15 16 /** 17 * 上传文件 18 * 19 * @param localPath 本地路径 20 * @param remotePath 远程路径,必须包含文件名("/"为当前ftp用户根路径) 21 * @return 上传成功返回true, 否则返回false 22 */ 23 public boolean uploadFile(String localPath, String remotePath) { 24 if (StringUtils.isBlank(localPath)) { 25 log.error("本地文件路径为空"); 26 return false; 27 } 28 return uploadFile(new File(localPath), remotePath); 29 } 30 31 /** 32 * 上传文件 33 * 34 * @param localFile 本地文件 35 * @param remotePath 远程文件,必须包含文件名 36 * @return 上传成功返回true, 否则返回false 37 */ 38 public boolean uploadFile(File localFile, String remotePath) { 39 if (!localFile.exists()) { 40 log.error("本地文件不存在"); 41 return false; 42 } 43 if (!localFile.isFile()) { 44 log.error("上传类型不是文件"); 45 } 46 if (StringUtils.isBlank(remotePath)) { 47 remotePath = "/"; 48 } 49 FileInputStream fis = null; 50 BufferedInputStream bis = null; 51 try { 52 fis = new FileInputStream(localFile); 53 bis = new BufferedInputStream(fis); 54 // 上传 55 return uploadFile(bis, remotePath); 56 } catch (FileNotFoundException fex) { 57 fex.printStackTrace(); 58 log.error("系统找不到指定的文件:{}", localFile); 59 } catch (Exception ex) { 60 ex.printStackTrace(); 61 log.error("上传文件异常。"); 62 } finally { 63 try { 64 if (bis != null) { 65 bis.close(); 66 } 67 } catch (Exception ex) { 68 ex.printStackTrace(); 69 } 70 try { 71 if (fis != null) { 72 fis.close(); 73 } 74 } catch (Exception ex) { 75 ex.printStackTrace(); 76 } 77 } 78 return false; 79 } 80 81 /** 82 * 上传文件 83 * 84 * @param fileContent 文件内容 85 * @param remotePath 远程文件,必须包含文件名 86 * @return 上传成功返回true, 否则返回false 87 */ 88 public boolean uploadFile(byte[] fileContent, String remotePath) { 89 if (fileContent == null || fileContent.length <= 0) { 90 log.error("上传文件内容为空。"); 91 return false; 92 } 93 InputStream is = null; 94 try { 95 is = new ByteArrayInputStream(fileContent); 96 // 上传 97 return uploadFile(is, remotePath); 98 } catch (Exception ex) { 99 ex.printStackTrace(); 100 log.error("上传文件异常。原因:【{}】", ex.getMessage()); 101 } finally { 102 try { 103 if (is != null) { 104 is.close(); 105 } 106 } catch (Exception ex) { 107 ex.printStackTrace(); 108 } 109 } 110 return false; 111 } 112 113 /** 114 * 下载文件 115 * @param remotePath 远程文件,必须包含文件名 116 * @param localPath 本地路径,必须包含文件名(全路径) 117 * @return 下载成功返回true,否则返回false 118 */ 119 public boolean downloadFile(String remotePath, String localPath) { 120 if (StringUtils.isBlank(remotePath)) { 121 remotePath = "/"; 122 } 123 if (StringUtils.isBlank(localPath)) { 124 log.error("本地文件路径为空"); 125 return false; 126 } 127 return downloadFile(new File(localPath), remotePath); 128 } 129 130 /** 131 * 下载文件 132 * @param remotePath 远程文件,必须包含文件名 133 * @param localFile 本地文件 134 * @return 下载成功返回true,否则返回false 135 */ 136 public boolean downloadFile(File localFile, String remotePath) { 137 // 创建本地文件路径 138 if (!localFile.exists()) { 139 File parentFile = localFile.getParentFile(); 140 if (!parentFile.exists()) { 141 boolean bool = parentFile.mkdirs(); 142 if (!bool) { 143 log.error("创建本地路径失败"); 144 return false; 145 } 146 } 147 } 148 OutputStream os = null; 149 try { 150 os = new FileOutputStream(localFile); 151 // 下载 152 return downloadFile(remotePath, os); 153 } catch (Exception ex) { 154 ex.printStackTrace(); 155 log.error("下载文件异常。原因:【{}】", ex.getMessage()); 156 } finally { 157 try { 158 if (os != null) { 159 os.close(); 160 } 161 } catch (Exception ex) { 162 ex.printStackTrace(); 163 } 164 } 165 return false; 166 } 167 168 /** 169 * 删除文件 170 * @param remotePath 远程文件,必须包含文件名 171 * @return 删除成功返回true,否则返回false 172 */ 173 public boolean deleteFile(String remotePath) { 174 if (StringUtils.isBlank(remotePath)) { 175 log.info("远程路径为空"); 176 return false; 177 } 178 return deleFile(remotePath); 179 } 180 181 /** 182 * 上传文件 183 * @param inputStream 文件流 184 * @param remotePath 远程路径,必须包含文件名 185 * @return 上传成功返回true,否则返回false 186 */ 187 protected abstract boolean uploadFile(InputStream inputStream, String remotePath); 188 /** 189 * 下载文件 190 * @param remotePath 远程文件,必须包含文件名 191 * @param outputStream 本地文件流 192 * @return 下载成功返回true,否则返回false 193 */ 194 protected abstract boolean downloadFile(String remotePath, OutputStream outputStream); 195 /** 196 * 删除文件 197 * @param remotePath 程文件,必须包含文件名 198 * @return 删除成功返回true,否则返回false 199 */ 200 protected abstract boolean deleFile(String remotePath); 201 202 /** 203 * 上传文件 204 * 205 * @param client ftp客户端 206 * @param inputStream 文件流 207 * @param remotePath 远程文件,必须包含文件名 208 * @return 上传成功返回true, 否则返回false 209 */ 210 protected boolean uploadHandle(FTPClient client, InputStream inputStream, String remotePath) { 211 // 上传 212 try { 213 // 获取远程文件路径 214 String remoteFilePath = getRemoteFilePath(remotePath); 215 // 获取远程文件名 216 String remoteFileName = getRemoteFileName(remotePath); 217 // 切换工作路径 218 boolean bool = changeDirectory(client, remoteFilePath); 219 if (!bool) { 220 log.error("切换工作路径失败,{}", client.getReplyString()); 221 return false; 222 } 223 // 设置重试次数 224 final int retryTime = 3; 225 boolean retryResult = false; 226 227 for (int i = 0; i <= retryTime; i++) { 228 boolean success = client.storeFile(remoteFileName, inputStream); 229 if (success) { 230 log.info("文件【{}】上传成功。", remotePath); 231 retryResult = true; 232 break; 233 } else { 234 log.error("文件上传失败。{}", client.getReplyString()); 235 } 236 log.warn("文件【{}】上传失败,重试上传...尝试{}次", remotePath, i); 237 } 238 239 return retryResult; 240 } catch (Exception ex) { 241 ex.printStackTrace(); 242 log.error("上传文件异常。"); 243 } 244 245 return false; 246 } 247 248 /** 249 * 下载文件 250 * @param client ftp客户端 251 * @param remotePath 远程文件,必须包含文件名 252 * @param outputStream 本地文件流 253 * @return 下载成功返回true,否则返回false 254 */ 255 protected boolean downloadHandle(FTPClient client, String remotePath, OutputStream outputStream) { 256 // 下载 257 try { 258 // 获取远程文件路径 259 String remoteFilePath = getRemoteFilePath(remotePath); 260 // 获取远程文件名 261 String remoteFileName = getRemoteFileName(remotePath); 262 // 切换工作路径 263 boolean bool = client.changeWorkingDirectory(remoteFilePath); 264 if (!bool) { 265 log.error("切换工作路径失败,{}", client.getReplyString()); 266 return false; 267 } 268 // 设置重试次数 269 final int retryTime = 3; 270 boolean retryResult = false; 271 272 for (int i = 0; i <= retryTime; i++) { 273 boolean success = client.retrieveFile(remoteFileName, outputStream); 274 if (success) { 275 log.info("文件【{}】下载成功。", remotePath); 276 retryResult = true; 277 break; 278 } else { 279 log.error("文件下载失败。 {}", client.getReplyString()); 280 } 281 log.warn("文件【{}】下载失败,重试下载...尝试{}次", remotePath, i); 282 } 283 // 返回结果 284 return retryResult; 285 } catch (Exception ex) { 286 ex.printStackTrace(); 287 log.error("下载文件异常。"); 288 } finally { 289 290 } 291 return false; 292 } 293 294 /** 295 * 删除文件 296 * @param remotePath 远程文件,必须包含文件名 297 * @return 删除成功返回true,否则返回false 298 */ 299 protected boolean deleteHandle(FTPClient client, String remotePath) { 300 try { 301 // 删除文件 302 boolean bool = client.deleteFile(remotePath); 303 if (!bool) { 304 log.error("删除文件失败,{}", client.getReplyString()); 305 } 306 return bool; 307 } catch (Exception ex) { 308 ex.printStackTrace(); 309 log.error("删除文件异常。"); 310 } 311 return false; 312 } 313 314 /** 315 * 获取远程工作目录 316 * @param remotePath 远程路径 317 * @return 返回工作路径 318 */ 319 private String getRemoteFilePath(String remotePath) { 320 if (StringUtils.isNotBlank(remotePath)) { 321 return remotePath.substring(0, remotePath.lastIndexOf("/") + 1); 322 } 323 return "/"; 324 } 325 326 /** 327 * 获取远程文件名 328 * @param remotePath 远程路径 329 * @return 返回文件名 330 */ 331 private String getRemoteFileName(String remotePath) { 332 if (StringUtils.isNotBlank(remotePath)) { 333 return remotePath.substring(remotePath.lastIndexOf("/") + 1); 334 } 335 return ""; 336 } 337 338 /** 339 * 切换工作目录 340 * @param client ftp客户端 341 * @param dir 工作目录 342 * @return 切换成功返回true,否则返回false 343 */ 344 private boolean changeDirectory(FTPClient client, String dir) { 345 try { 346 if (client == null || StringUtils.isBlank(dir)) { 347 return false; 348 } 349 350 String fileBackslashSeparator = "\\"; 351 String fileSeparator = "/"; 352 353 if (StringUtils.contains(dir, fileBackslashSeparator)) { 354 dir = StringUtils.replaceAll(dir, fileBackslashSeparator, fileSeparator); 355 } 356 357 String[] dirArray = StringUtils.split(dir, fileSeparator); 358 359 String tmp = ""; 360 for (String aDirArray : dirArray) { 361 tmp += fileSeparator + aDirArray; 362 if (!client.changeWorkingDirectory(tmp)) { 363 // 创建工作目录 364 client.makeDirectory(tmp); 365 // 切换工作目录 366 client.changeWorkingDirectory(tmp); 367 } 368 } 369 return true; 370 } catch (Exception ex) { 371 ex.printStackTrace(); 372 log.error("切换工作目录失败。"); 373 } 374 return false; 375 } 376 377 }
5、ftp一次连接处理上传下载
1 package com.scenetec.isv.utils.ftp.template; 2 3 import com.scenetec.isv.utils.ftp.core.FtpClientFactory; 4 import lombok.extern.slf4j.Slf4j; 5 import org.apache.commons.net.ftp.FTPClient; 6 import org.springframework.stereotype.Component; 7 8 import javax.annotation.Resource; 9 import java.io.InputStream; 10 import java.io.OutputStream; 11 12 /** 13 * @author shendunyuan@scenetec.com 14 * @date 2019/1/22 15 */ 16 @Slf4j 17 @Component 18 public class FtpOnceTemplate extends FtpBaseTemplate { 19 20 @Resource 21 private FtpClientFactory factory; 22 23 /** 24 * 上传文件 25 * 26 * @param inputStream 文件流 27 * @param remotePath 远程文件,必须包含文件名 28 * @return 上传成功返回true, 否则返回false 29 */ 30 @Override 31 public boolean uploadFile(InputStream inputStream, String remotePath) { 32 // 上传 33 FTPClient client = null; 34 try { 35 // 创建对象 36 client = factory.create(); 37 // 上传 38 return uploadHandle(client, inputStream, remotePath); 39 } catch (Exception ex) { 40 ex.printStackTrace(); 41 log.error("上传文件异常。"); 42 } finally { 43 factory.close(client); 44 } 45 return false; 46 } 47 48 /** 49 * 下载文件 50 * @param remotePath 远程文件,必须包含文件名 51 * @param outputStream 本地文件流 52 * @return 下载成功返回true,否则返回false 53 */ 54 @Override 55 public boolean downloadFile(String remotePath, OutputStream outputStream) { 56 // 下载 57 FTPClient client = null; 58 try { 59 // 获取对象 60 client = factory.create(); 61 // 文件下载 62 return downloadHandle(client, remotePath, outputStream); 63 } catch (Exception ex) { 64 ex.printStackTrace(); 65 log.error("下载文件异常。"); 66 } finally { 67 if (client != null) { 68 factory.close(client); 69 } 70 } 71 return false; 72 } 73 74 /** 75 * 删除文件 76 * @param remotePath 远程文件,必须包含文件名 77 * @return 下载成功返回true,否则返回false 78 */ 79 @Override 80 public boolean deleFile(String remotePath) { 81 FTPClient client = null; 82 try { 83 // 获取对象 84 client = factory.create(); 85 // 删除文件 86 return deleteHandle(client, remotePath); 87 } catch (Exception ex) { 88 ex.printStackTrace(); 89 log.error("删除文件异常。"); 90 } finally { 91 if (client != null) { 92 factory.close(client); 93 } 94 } 95 return false; 96 } 97 98 }
6、ftp使用资源池处理上传下载
1 package com.scenetec.isv.utils.ftp.template; 2 3 import com.scenetec.isv.utils.ftp.core.FtpClientFactory; 4 import lombok.extern.slf4j.Slf4j; 5 import org.apache.commons.net.ftp.FTPClient; 6 import org.apache.commons.net.ftp.FTPReply; 7 import org.apache.commons.pool2.impl.GenericObjectPool; 8 import org.springframework.stereotype.Component; 9 10 import java.io.InputStream; 11 import java.io.OutputStream; 12 13 /** 14 * @author shendunyuan@scenetec.com 15 * @date 2018/12/20 16 */ 17 @Slf4j 18 @Component 19 public class FtpPoolTemplate extends FtpBaseTemplate { 20 21 private GenericObjectPool<FTPClient> ftpClientPool; 22 23 public FtpPoolTemplate(FtpClientFactory ftpClientFactory) { 24 this.ftpClientPool = new GenericObjectPool<>(ftpClientFactory); 25 } 26 27 /** 28 * 上传文件 29 * 30 * @param inputStream 文件流 31 * @param remotePath 远程文件,必须包含文件名 32 * @return 上传成功返回true, 否则返回false 33 */ 34 @Override 35 public boolean uploadFile(InputStream inputStream, String remotePath) { 36 // 上传 37 FTPClient client = null; 38 try { 39 // 从池中获取对象 40 client = getFtpClient(); 41 // 上传 42 return uploadHandle(client, inputStream, remotePath); 43 } catch (Exception ex) { 44 ex.printStackTrace(); 45 log.error("上传文件异常。"); 46 } finally { 47 // 将对象放回池中 48 if (client != null) { 49 ftpClientPool.returnObject(client); 50 } 51 } 52 return false; 53 } 54 55 /** 56 * 下载文件 57 * @param remotePath 远程文件,必须包含文件名 58 * @param outputStream 本地文件流 59 * @return 下载成功返回true,否则返回false 60 */ 61 @Override 62 public boolean downloadFile(String remotePath, OutputStream outputStream) { 63 // 下载 64 FTPClient client = null; 65 try { 66 // 从池中获取对象 67 client = getFtpClient(); 68 // 下载 69 return downloadHandle(client, remotePath, outputStream); 70 } catch (Exception ex) { 71 ex.printStackTrace(); 72 log.error("下载文件异常。"); 73 } finally { 74 if (client != null) { 75 ftpClientPool.returnObject(client); 76 } 77 } 78 return false; 79 } 80 81 /** 82 * 删除文件 83 * @param remotePath 远程文件,必须包含文件名 84 * @return 下载成功返回true,否则返回false 85 */ 86 @Override 87 public boolean deleFile(String remotePath) { 88 FTPClient client = null; 89 try { 90 // 从池中获取对象 91 client = getFtpClient(); 92 // 删除文件 93 return deleteHandle(client, remotePath); 94 } catch (Exception ex) { 95 ex.printStackTrace(); 96 log.error("删除文件异常。"); 97 } finally { 98 if (client != null) { 99 ftpClientPool.returnObject(client); 100 } 101 } 102 return false; 103 } 104 105 106 /** 107 * 验证连接是否成功 108 * @return 连接登录成功返回true,否则返回false 109 */ 110 private FTPClient getFtpClient () { 111 FTPClient client = null; 112 try { 113 while (true) { 114 // 获取客户端 115 client = ftpClientPool.borrowObject(); 116 // 验证客户端 117 if (client == null) { 118 continue; 119 } else { 120 if (!client.isConnected() || !FTPReply.isPositiveCompletion(client.getReplyCode())) { 121 ftpClientPool.invalidateObject(client); 122 } else { 123 break; 124 } 125 } 126 } 127 } catch (Exception ex) { 128 ex.printStackTrace(); 129 } 130 return client; 131 } 132 133 }
7、ftp部分依赖配置
1 <dependencies> 2 <dependency> 3 <groupId>org.apache.commons</groupId> 4 <artifactId>commons-lang3</artifactId> 5 <version>3.7</version> 6 </dependency> 7 <dependency> 8 <groupId>org.slf4j</groupId> 9 <artifactId>slf4j-api</artifactId> 10 <version>1.7.25</version> 11 </dependency> 12 <dependency> 13 <groupId>commons-net</groupId> 14 <artifactId>commons-net</artifactId> 15 <version>3.3</version> 16 </dependency> 17 <dependency> 18 <groupId>org.projectlombok</groupId> 19 <artifactId>lombok</artifactId> 20 <version>1.16.8</version> 21 <scope>provided</scope> 22 </dependency> 23 <dependency> 24 <groupId>org.apache.commons</groupId> 25 <artifactId>commons-pool2</artifactId> 26 <version>2.5.0</version> 27 </dependency> 28 </dependencies>
8、ftp测试类
1 package com.scenetec.isv.operation.ftp; 2 3 import com.scenetec.isv.operation.ISVOperationManagerApplication; 4 import com.scenetec.isv.utils.ftp.template.FtpOnceTemplate; 5 import com.scenetec.isv.utils.ftp.template.FtpPoolTemplate; 6 import org.junit.Test; 7 import org.junit.runner.RunWith; 8 import org.springframework.beans.factory.annotation.Autowired; 9 import org.springframework.boot.test.context.SpringBootTest; 10 import org.springframework.test.context.junit4.SpringRunner; 11 12 import javax.annotation.Resource; 13 import java.io.File; 14 15 /** 16 * @author shendunyuan@scenetec.com 17 * @date 2018/12/20 18 */ 19 @SpringBootTest(classes = ISVOperationManagerApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 20 @RunWith(SpringRunner.class) 21 public class FtpClientPoolTest { 22 23 @Autowired 24 private FtpPoolTemplate ftpPoolTemplate; 25 @Resource 26 private FtpOnceTemplate ftpOnceTemplate; 27 28 private String localPath = "/Users/sdy/test/isv/platform.cer"; 29 private String localDownPath = "/Users/sdy/test/isv/2019/111test.cer"; 30 private String remotePath = "/2019/111.cer"; 31 32 @Test 33 public void upload() { 34 boolean bool = ftpPoolTemplate.uploadFile(localPath, remotePath); 35 if (bool) { 36 System.out.println("success"); 37 } else { 38 System.out.println("failed"); 39 } 40 } 41 42 @Test 43 public void up() { 44 boolean bool = ftpOnceTemplate.uploadFile(localPath, remotePath); 45 if (bool) { 46 System.out.println("success"); 47 } else { 48 System.out.println("failed"); 49 } 50 } 51 52 @Test 53 public void uploadFile() { 54 File file = new File(localPath); 55 boolean bool = ftpPoolTemplate.uploadFile(file, remotePath); 56 if (bool) { 57 System.out.println("success"); 58 } else { 59 System.out.println("failed"); 60 } 61 } 62 63 @Test 64 public void downloadFile() { 65 boolean bool = ftpPoolTemplate.downloadFile(remotePath, localDownPath); 66 if (bool) { 67 System.out.println("success"); 68 } else { 69 System.out.println("failed"); 70 } 71 } 72 73 @Test 74 public void deleteFile() { 75 boolean bool = ftpPoolTemplate.deleteFile(remotePath); 76 if (bool) { 77 System.out.println("success"); 78 } else { 79 System.out.println("failed"); 80 } 81 } 82 }
注意:ftp多线程处理时容易超时,目前没有找到更好的处理办法。
完整项目代码请参见:https://github.com/sxpdy8571/ftpUtils/tree/develop