spring中使用ftp連線池(ftpClientPool)
阿新 • • 發佈:2019-02-04
如題,我們在一些專案中可能會涉及到ftp上傳、下載客戶資料、附件。但是若每次上傳或下載時都去建立一次ftp連線,上傳( 下載)一個檔案再關閉,則太耗費連線資源,這時候可以考慮使用連線池(就如同我們需要jdbc資料庫連線池的道理一樣)
筆者參考了網上的一些示例、技術文章,以及現有的apache commons-pool元件的程式碼等,自己封裝了一套還算是比較完整的程式碼(此連線池底層依賴apache的commons-net和commons-pool2 元件) 。
此專案筆者已釋出到github上了,專案地址:
https://github.com/jellyflu/ftpClientPool (對原始碼感興趣的同學,請移步github哦 ~)
其實專案程式碼也不復雜,就是對apache ftp做了薄層的封裝,總共才幾個類,一千行程式碼不到。
FtpPoolConfig.java 繼承自GenericObjectPoolConfig ,封裝ftp的一些連線引數等。
package com.tingcream.ftpClientPool.config; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; /** * ftp配置引數物件 繼承自GenericObjectPoolConfig * * @author jelly * */ public class FtpPoolConfig extends GenericObjectPoolConfig{ private String host;//主機名 private int port=21;//埠 private String username;//使用者名稱 private String password;//密碼 private int connectTimeOut=5000;//ftp 連線超時時間 毫秒 private String controlEncoding="utf-8"; private int bufferSize =1024;//緩衝區大小 private int fileType =2 ;// 傳輸資料格式 2表binary二進位制資料 private int dataTimeout= 120000; private boolean useEPSVwithIPv4 =false; private boolean passiveMode =true;//是否啟用被動模式 public int getConnectTimeOut() { return connectTimeOut; } public void setConnectTimeOut(int connectTimeOut) { this.connectTimeOut = connectTimeOut; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public int getPort() { return port; } public void setPort(int 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 getControlEncoding() { return controlEncoding; } public void setControlEncoding(String controlEncoding) { this.controlEncoding = controlEncoding; } public int getBufferSize() { return bufferSize; } public void setBufferSize(int bufferSize) { this.bufferSize = bufferSize; } public int getFileType() { return fileType; } public void setFileType(int fileType) { this.fileType = fileType; } public int getDataTimeout() { return dataTimeout; } public void setDataTimeout(int dataTimeout) { this.dataTimeout = dataTimeout; } public boolean isUseEPSVwithIPv4() { return useEPSVwithIPv4; } public void setUseEPSVwithIPv4(boolean useEPSVwithIPv4) { this.useEPSVwithIPv4 = useEPSVwithIPv4; } public boolean isPassiveMode() { return passiveMode; } public void setPassiveMode(boolean passiveMode) { this.passiveMode = passiveMode; } }
FTPClientFactory.java ftp客戶端連線建立工廠
package com.tingcream.ftpClientPool.core; import java.io.IOException; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPReply; import org.apache.commons.pool2.BasePooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; import org.apache.log4j.Logger; import com.tingcream.ftpClientPool.config.FtpPoolConfig; /** * ftpclient 工廠 * @author jelly * */ public class FTPClientFactory extends BasePooledObjectFactory<FTPClient> { private static Logger logger =Logger.getLogger(FTPClientFactory.class); private FtpPoolConfig ftpPoolConfig; public FtpPoolConfig getFtpPoolConfig() { return ftpPoolConfig; } public void setFtpPoolConfig(FtpPoolConfig ftpPoolConfig) { this.ftpPoolConfig = ftpPoolConfig; } /** * 新建物件 */ @Override public FTPClient create() throws Exception { FTPClient ftpClient = new FTPClient(); ftpClient.setConnectTimeout(ftpPoolConfig.getConnectTimeOut()); try { logger.info("連線ftp伺服器:" +ftpPoolConfig.getHost()+":"+ftpPoolConfig.getPort()); ftpClient.connect(ftpPoolConfig.getHost(), ftpPoolConfig.getPort()); int reply = ftpClient.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftpClient.disconnect(); logger.error("FTPServer 拒絕連線"); return null; } boolean result = ftpClient.login(ftpPoolConfig.getUsername(),ftpPoolConfig.getPassword()); if (!result) { logger.error("ftpClient登入失敗!"); throw new Exception("ftpClient登入失敗! userName:"+ ftpPoolConfig.getUsername() + ", password:" + ftpPoolConfig.getPassword()); } ftpClient.setControlEncoding(ftpPoolConfig.getControlEncoding()); ftpClient.setBufferSize(ftpPoolConfig.getBufferSize()); ftpClient.setFileType(ftpPoolConfig.getFileType()); ftpClient.setDataTimeout(ftpPoolConfig.getDataTimeout()); ftpClient.setUseEPSVwithIPv4(ftpPoolConfig.isUseEPSVwithIPv4()); if(ftpPoolConfig.isPassiveMode()){ logger.info("進入ftp被動模式"); ftpClient.enterLocalPassiveMode();//進入被動模式 } } catch (IOException e) { logger.error("FTP連線失敗:", e); } return ftpClient; } @Override public PooledObject<FTPClient> wrap(FTPClient ftpClient) { return new DefaultPooledObject<FTPClient>(ftpClient); } /** * 銷燬物件 */ @Override public void destroyObject(PooledObject<FTPClient> p) throws Exception { FTPClient ftpClient = p.getObject(); ftpClient.logout(); super.destroyObject(p); } /** * 驗證物件 */ @Override public boolean validateObject(PooledObject<FTPClient> p) { FTPClient ftpClient = p.getObject(); boolean connect = false; try { connect = ftpClient.sendNoOp(); } catch (IOException e) { e.printStackTrace(); } return connect; } /** * No-op. * * @param p ignored */ @Override public void activateObject(PooledObject<FTPClient> p) throws Exception { // The default implementation is a no-op. } /** * No-op. * * @param p ignored */ @Override public void passivateObject(PooledObject<FTPClient> p) throws Exception { // The default implementation is a no-op. } }
FTPClientPool.java FTP客戶端連線池
package com.tingcream.ftpClientPool.core;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.impl.GenericObjectPool;
/**
* FTP 客戶端連線池
* @author jelly
*
*/
public class FTPClientPool {
/**
* ftp客戶端連線池
*/
private GenericObjectPool<FTPClient> pool;
/**
* ftp客戶端工廠
*/
private FTPClientFactory clientFactory;
/**
* 建構函式中 注入一個bean
*
* @param clientFactory
*/
public FTPClientPool( FTPClientFactory clientFactory){
this.clientFactory=clientFactory;
pool = new GenericObjectPool<FTPClient>(clientFactory, clientFactory.getFtpPoolConfig());
}
public FTPClientFactory getClientFactory() {
return clientFactory;
}
public GenericObjectPool<FTPClient> getPool() {
return pool;
}
/**
* 借 獲取一個連線物件
* @return
* @throws Exception
*/
public FTPClient borrowObject() throws Exception {
FTPClient client = pool.borrowObject();
// if(!client.sendNoOp()){
// //使池中的物件無效
// client.logout();
// client.disconnect();
// pool.invalidateObject(client);
// client =clientFactory.create();
// pool.addObject();
// }
//
return client ;
}
/**
* 還 歸還一個連線物件
* @param ftpClient
*/
public void returnObject(FTPClient ftpClient) {
if(ftpClient!=null){
pool.returnObject(ftpClient);
}
}
}
FTPClientHelper.java ftp客戶端輔助類
package com.tingcream.ftpClientPool.client;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.net.ftp.FTPClient;
import com.tingcream.ftpClientPool.core.FTPClientPool;
import com.tingcream.ftpClientPool.util.ByteUtil;
/**
* ftp客戶端輔助bean
*
* @author jelly
*
*/
public class FTPClientHelper {
private FTPClientPool ftpClientPool;
public void setFtpClientPool(FTPClientPool ftpClientPool) {
this.ftpClientPool = ftpClientPool;
}
/**
* 下載 remote檔案流
* @param remote 遠端檔案
* @return 位元組資料
* @throws Exception
*/
public byte[] retrieveFileStream(String remote) throws Exception {
FTPClient client=null;
InputStream in =null;
try {
// long start =System.currentTimeMillis();
client= ftpClientPool.borrowObject();
in=client.retrieveFileStream(remote);
// long end =System.currentTimeMillis();
// System.out.println("ftp下載耗時(毫秒):"+(end-start));
return ByteUtil.inputStreamToByteArray(in);
}finally{
if (in != null) {
in.close();
}
if (!client.completePendingCommand()) {
client.logout();
client.disconnect();
ftpClientPool.getPool().invalidateObject(client);
}
ftpClientPool.returnObject(client);
}
}
/**
* 建立目錄 單個不可遞迴
* @param pathname 目錄名稱
* @return
* @throws Exception
*/
public boolean makeDirectory(String pathname) throws Exception {
FTPClient client=null;
try {
client= ftpClientPool.borrowObject();
return client.makeDirectory(pathname);
} finally{
ftpClientPool.returnObject(client);
}
}
/**
* 刪除目錄,單個不可遞迴
* @param pathname
* @return
* @throws IOException
*/
public boolean removeDirectory(String pathname) throws Exception {
FTPClient client=null;
try {
client= ftpClientPool.borrowObject();
return client.removeDirectory(pathname);
} finally{
ftpClientPool.returnObject(client);
}
}
/**
* 刪除檔案 單個 ,不可遞迴
* @param pathname
* @return
* @throws Exception
*/
public boolean deleteFile(String pathname) throws Exception {
FTPClient client=null;
try {
client= ftpClientPool.borrowObject();
return client.deleteFile(pathname);
}finally{
ftpClientPool.returnObject(client);
}
}
/**
* 上傳檔案
* @param remote
* @param local
* @return
* @throws Exception
*/
public boolean storeFile(String remote, InputStream local) throws Exception {
FTPClient client=null;
try {
client= ftpClientPool.borrowObject();
return client.storeFile(remote, local);
} finally{
ftpClientPool.returnObject(client);
}
}
}
ByteUtil位元組工具類
package com.tingcream.ftpClientPool.util;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
/**
* 位元組工具類
* @author jelly
*
*/
public class ByteUtil {
public static byte[] inputStreamToByteArray(InputStream in) {
try {
ByteArrayOutputStream out=new ByteArrayOutputStream();
byte[] buffer=new byte[1024*4];
int n=0;
while ( (n=in.read(buffer)) >0) {
out.write(buffer,0,n);
}
return out.toByteArray();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}