spring中使用ftp连接池(ftpClientPool)

如题,我们在一些项目中可能会涉及到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;
		}  
	 }

}



  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值