项目中由于要使用到ftp服务,虽然之前对edtFTPj有研究,但是鉴于edtFTPj版本更新比较慢等原因,没有使用这个包,我们用的功能比较简单,先简单的介绍下。
过程一般是先建立连接,登陆,然后执行命令,最后关闭连接,相对来说比较简单,直接上代码。
需要说明的是,在写测试单元测试的时候,如果不依赖物理的ftp,就需要自己mock一个ftp了,我在网上找到一个mockFtpServer,具体用法大家可以参考。
package com.xxx.aaa.data.ftp;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.util.Calendar;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPReply;
import com.xxx.aaa.common.aaaConfig;
import com.xxx.aaa.common.exception.aaaBaseException;
import com.xxx.aaa.common.log.LoggerHelper;
import com.xxx.aaa.common.util.DateUtils;
import com.xxx.aaa.util.aaaConstants;
public class FtpClient {
private final FtpClientConfig ftpConfig;
private final FTPClient client;
private boolean ready = false;
public FtpClient(FtpClientConfig config) {
ftpConfig = config;
client = new FTPClient();
}
public void begin() throws aaaBaseException {
try {
if (connect() && login()) {
setConfig();
ready = true;
}
} catch (SocketException e) {
LoggerHelper.err(this.getClass(), "Connect socket error!", e);
throw new aaaBaseException("Connect socket error,reaseon:" + e.getMessage());
} catch (IOException e) {
LoggerHelper.err(this.getClass(), "Login server error!", e);
throw new aaaBaseException("Login server error,reaseon:" + e.getMessage());
}
}
private boolean connect() throws SocketException, IOException {
client.connect(ftpConfig.getServer(), ftpConfig.getPort());
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
LoggerHelper.info(this.getClass(), "Error connet server:{} on port:{}", ftpConfig.getServer(),
ftpConfig.getPort());
return false;
}
return true;
}
private boolean login() throws IOException {
boolean loginSuccess = client.login(ftpConfig.getUsername(), ftpConfig.getPassword());
if (!loginSuccess) {
client.logout();
LoggerHelper.info(this.getClass(), "Error login username:{} with password:{}", ftpConfig.getUsername(),
ftpConfig.getPassword());
return false;
}
return true;
}
/**
* ftp运行环境参数配置
*
* @throws IOException
*/
private void setConfig() throws IOException {
FTPClientConfig conf = new FTPClientConfig(ftpConfig.getFtpStyle());
client.configure(conf);
// 被动传输模式
if (ftpConfig.getPassiveMode()) {
client.enterLocalPassiveMode();
}
// 二进制传输模式
if (ftpConfig.getBinaryFileType()) {
client.setFileType(FTP.BINARY_FILE_TYPE);
}
// 设置当前工作目录
client.changeWorkingDirectory(ftpConfig.getRootPath());
}
/**
* 下载文件
*
* @param path
* @param name
* @return
* @throws UnsupportedEncodingException
* @throws IOException
*/
public String download(String fileName) throws aaaBaseException {
if (!ready) {
return "";
}
String localPath = aaaConfig.getTempDir();
if (!localPath.endsWith("/")) {
localPath = localPath + "/";
}
File file = null;
FileOutputStream fos = null;
String destFileName = generateDestFileName(fileName);
try {
file = new File(localPath + destFileName);
FileUtils.forceMkdir(file.getParentFile());
fos = new FileOutputStream(file);
client.retrieveFile(fileName, fos);
return destFileName;
} catch (IOException e) {
LoggerHelper.err(this.getClass(), "IO exception, fileName:{},reason:{}", destFileName, e.getMessage());
throw new aaaBaseException(String.format("IO exception, fileName:%s,reason:%s", fileName, e.getMessage()));
} finally {
IOUtils.closeQuietly(fos);
if (file != null) {
file.setReadOnly();
}
}
}
private String generateDestFileName(String srcFileName) {
Calendar now = Calendar.getInstance();
String yyMMddHH = DateUtils.getDate2String(DateUtils.YYYYMMDD_HH, now.getTime());
return yyMMddHH + "_" + srcFileName;
}
public String downloadWithMd5(String fileName, String... md5Name) throws aaaBaseException {
String downFileFileName = download(fileName);
String fileMd5Name = fileName + aaaConstants.MD5_EXTENSION;
if (md5Name != null && md5Name.length > 0 && StringUtils.isNotBlank(md5Name[0])) {
fileMd5Name = md5Name[0];
}
download(fileMd5Name);
return downFileFileName;
}
public String downloadQuiet(String fileName, String... md5Name) throws aaaBaseException {
begin();
String downFileFileName = downloadWithMd5(fileName, md5Name);
end();
return downFileFileName;
}
/**
* 关闭连接
*
* @throws aaaBaseException
*/
public void end() throws aaaBaseException {
try {
if (client.isConnected()) {
client.logout();
}
} catch (IOException e) {
LoggerHelper.err(this.getClass(), "Logout error!", e);
throw new aaaBaseException("Logout error,reason:" + e.getMessage());
} finally {
if (client.isConnected()) {
try {
client.disconnect();
} catch (IOException e) {
LoggerHelper.err(this.getClass(), "Disconnect socket error!", e);
throw new aaaBaseException("Disconnect socket error,reason:" + e.getMessage());
}
}
}
}
/**
* 上传文件到ftp服务上去
*
* @author wangye04
*/
public boolean upload(String filename) throws aaaBaseException {
if (!ready) {
throw new aaaBaseException("ftpClient isn't ready!");
}
String localPath = aaaConfig.getTempDir();
if (!localPath.endsWith("/")) {
localPath = localPath + "/";
}
FileInputStream fis = null;
try {
fis = new FileInputStream(new File(localPath + filename));
return client.storeFile(filename, fis);
} catch (Exception e) {
LoggerHelper.err(getClass(), "An exception happened, fileName:{},reason:{}", filename, e.getMessage());
throw new aaaBaseException(e);
} finally {
IOUtils.closeQuietly(fis);
}
}
}
package com.xxx.aaa.data.ftp;
import org.apache.commons.net.ftp.FTPClientConfig;
import com.xxx.aaa.common.AAAConfig;
/**
* ftp的配置类
*
*/
public class FtpClientConfig {
/** ftp服务器地址 */
private String server;
/** ftp服务器端口 */
private int port;
/** ftp服务器用户名 */
private String username;
/** ftp服务器密码 */
private String password;
/** ftp服务器显示风格 一般为unix 或者nt */
private String ftpStyle;
/** 是否设置 passiveMode模式 */
private boolean passiveMode;
/** 是否设置以二进制传输文件 */
private boolean binaryFileType;
/** ftp服务器工作根目录 */
private String rootPath;
/** 单例,上游ftp服务 */
private static FtpClientConfig sourceInstance = null;
/** 单例 */
private static FtpClientConfig targetInstance = null;
/**
* 从联盟获取配置实例
*
* @param file
* @return
*/
public static FtpClientConfig getSourceInstance() {
if (null == sourceInstance) {
sourceInstance = new FtpClientConfig();
sourceInstance.initSourceConfig();
}
return sourceInstance;
}
/**
* 给下游系统提供服务
*
* @return
*/
public static FtpClientConfig getTargetInstance() {
if (null == targetInstance) {
targetInstance = new FtpClientConfig();
targetInstance.initTargetConfig();
}
return targetInstance;
}
/**
* 设置源ftp的属性
*
* @throws Exception
*/
private void initSourceConfig() {
setServer(AAAConfig.getConfigValueByKey("ftp.server"));
setPort(Integer.parseInt(AAAConfig.getConfigValueByKey("ftp.port")));
setUsername(AAAConfig.getConfigValueByKey("ftp.username"));
setPassword(AAAConfig.getConfigValueByKey("ftp.password"));
setFtpStyle(AAAConfig.getConfigValueByKey("ftp.ftpstyle"));
setPassiveMode(AAAConfig.getConfigValueByKey("ftp.passivemode"));
setBinaryFileType(AAAConfig.getConfigValueByKey("ftp.binaryfiletype"));
setRootPath(AAAConfig.getConfigValueByKey("ftp.rootpath"));
}
/**
* 设置目标ftp的属性
*
* @throws Exception
*/
private void initTargetConfig() {
setServer(AAAConfig.getConfigValueByKey("ftp.target.server"));
setPort(Integer.parseInt(AAAConfig.getConfigValueByKey("ftp.target.port")));
setUsername(AAAConfig.getConfigValueByKey("ftp.target.username"));
setPassword(AAAConfig.getConfigValueByKey("ftp.target.password"));
setFtpStyle(AAAConfig.getConfigValueByKey("ftp.target.ftpstyle"));
setPassiveMode(AAAConfig.getConfigValueByKey("ftp.target.passivemode"));
setBinaryFileType(AAAConfig.getConfigValueByKey("ftp.target.binaryfiletype"));
setRootPath(AAAConfig.getConfigValueByKey("ftp.target.rootpath"));
}
/**
* 读取二进制传输方式设置
*
* @return
*/
public boolean getBinaryFileType() {
return binaryFileType;
}
/**
* 默认以二进制形式传输文件
*
* @param binaryFileType
*/
public void setBinaryFileType(String binaryFileType) {
if (null == binaryFileType) {
this.binaryFileType = true;
} else {
if ("".equals(binaryFileType.trim())) {
this.binaryFileType = true;
} else if ("true".equals(binaryFileType.trim())) {
this.binaryFileType = true;
} else if ("false".equals(binaryFileType.trim())) {
this.binaryFileType = false;
}
}
}
public String getFtpStyle() {
return ftpStyle;
}
/**
* 默认NT风格
*
* @param style
*/
public void setFtpStyle(String style) {
if (null == style) {
this.ftpStyle = FTPClientConfig.SYST_NT;
} else {
if ("".equals(style.trim())) {
this.ftpStyle = FTPClientConfig.SYST_NT;
} else if ("unix".equals(style.trim())) {
this.ftpStyle = FTPClientConfig.SYST_UNIX;
} else if ("nt".equals(style.trim())) {
this.ftpStyle = FTPClientConfig.SYST_NT;
}
}
}
public boolean getPassiveMode() {
return passiveMode;
}
/**
* 默认支持passiveMode
*
* @param passiveMode
*/
public void setPassiveMode(String passiveMode) {
if (passiveMode == null) {
this.passiveMode = true;
} else {
if ("".equals(passiveMode.trim())) {
this.passiveMode = true;
} else if ("true".equals(passiveMode.trim())) {
this.passiveMode = true;
} else if ("false".equals(passiveMode.trim())) {
this.passiveMode = false;
}
}
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getPort() {
return port;
}
/**
* 默认端口为21
*
* @param port
*/
public void setPort(Integer port) {
if (null == port) {
port = 21;
}
this.port = port;
}
public String getRootPath() {
return rootPath;
}
/**
* 默认根目录为"/"
*
* @param rootPath
*/
public void setRootPath(String rootPath) {
if (null == rootPath) {
rootPath = "/";
} else {
if ("".equals(rootPath.trim()))
rootPath = "/";
}
this.rootPath = rootPath.trim();
}
public String getServer() {
return server;
}
public void setServer(String server) {
this.server = server;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}