シーン:オリジナルの古いプロジェクト・ファイル・システムは、高い同時実行に対処するために最適化されています
1、Mavenを導入に依存しています
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
<classifier>ftp</classifier>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
2、FtpPoolConfig.java:FTP設定パラメータはGenericObjectPoolConfigから継承オブジェクト
public class FtpPoolConfig extends GenericObjectPoolConfig {
private String host = "192.168.0.***";//主机名
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;
}
}
3、ftpclient工場
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.
}
}
4、FTPクライアントの接続プール
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);
}
}
}
5、FTPクライアントのバッキングBean
public class FTPClientHelper {
private FTPClientPool ftpClientPool;
private FTPClientFactory ftpClientFactory;
private FtpPoolConfig ftpPoolConfig;
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 {
if(ftpClientPool==null) ftpClientPool = returnFTPClientPool(ftpClientPool);
client = ftpClientPool.borrowObject();
// 将路径中的斜杠统一
char[] chars = pathname.toCharArray();
StringBuffer sbStr = new StringBuffer(256);
for (int i = 0; i < chars.length; i++) {
if ('\\' == chars[i]) {
sbStr.append('/');
} else {
sbStr.append(chars[i]);
}
}
pathname = sbStr.toString();
if (pathname.indexOf('/') == -1) {
// 只有一层目录
client.makeDirectory(new String(pathname.getBytes(), "iso-8859-1"));
client.changeWorkingDirectory(new String(pathname.getBytes(), "iso-8859-1"));
} else {
// 多层目录循环创建
String[] paths = pathname.split("/");
for (int i = 0; i < paths.length; i++) {
client.makeDirectory(new String(paths[i].getBytes(),"iso-8859-1"));
client.changeWorkingDirectory(new String(paths[i].getBytes(), "iso-8859-1"));
}
}
return true;
}catch (Exception e){
e.printStackTrace();
return false;
} 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 ftpDirectory,String remote, InputStream local) throws Exception {
FTPClient client=null;
try {
if(ftpClientPool==null) ftpClientPool = returnFTPClientPool(ftpClientPool);
client= ftpClientPool.borrowObject();
makeDirectory(ftpDirectory);
return client.storeFile(remote, local);
} finally{
ftpClientPool.returnObject(client);
}
}
public FTPClientPool returnFTPClientPool(FTPClientPool ftpClientPool) throws Exception{
if(ftpClientPool==null){
if(ftpClientFactory==null){
ftpClientFactory = new FTPClientFactory();
if(ftpPoolConfig==null) ftpPoolConfig = new FtpPoolConfig();
ftpClientFactory.setFtpPoolConfig(ftpPoolConfig);
ftpClientFactory.create();
}
ftpClientPool = new FTPClientPool(ftpClientFactory);
}
return ftpClientPool;
}
public static void main(String[] args) throws Exception{
FTPClientHelper ftpClientHelper = new FTPClientHelper();
for(int i=0;i<1000;i++){
boolean a = ftpClientHelper.storeFile("test","test/hahaha"+i+".png",new FileInputStream(new File("C:\\FileSystem\\72035b95379844a09506ab11b7f1edf3.png")));
System.out.println(a);
if(i==500){
System.out.println(500+"-----------------------------------------");
}
}
}
}
6、バイトツール
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;
}
}
}
7、効果:各アップロードは、接続プールからのすべてのFTP接続を取得します