背景:
部分老旧系统使用ftp进行文件传输,在当前技术趋势下及安全要求下,推荐使用对象存储进行文件传输。如何在不改造老旧系统前提下,无缝更换为对象存储?
解决办法:
apache ftpserver提供了纯java的ftp服务器解决方案。
提供了Ftplet来扩展相应ftp操作。
public interface Ftplet {
void init(FtpletContext var1) throws FtpException;
void destroy();
FtpletResult beforeCommand(FtpSession var1, FtpRequest var2) throws FtpException, IOException;
FtpletResult afterCommand(FtpSession var1, FtpRequest var2, FtpReply var3) throws FtpException, IOException;
FtpletResult onConnect(FtpSession var1) throws FtpException, IOException;
FtpletResult onDisconnect(FtpSession var1) throws FtpException, IOException;
}
应用开发者可以继承DefaultFtplet,重载其中的方法来处理上传和下载操作。
但使用此方法,只对下载有效。
下载时:先将对象存储上的文件下载在ftpserver,然后由具体RETR命令执行将文件下载至客户端。如果对象存储下载出现问题,客户端也会下载失败。
上传时:在STOR命令执行前,是无法获取至客户端的文件的,如在STOR命令后,相应的226文件传输完成报文已经发给客户端,在这时再向对象存储上传,不管是否成功,客户端都以为是成功的。问题出现了!
对于上传,如何进行控制呢,在不侵入ftpserver源码的前提下,可对NioListener进行继承,并增加新的IoFilterAdapter,对226报文进行拦截,即在完给客户端之前完成报文的上传,如果上传失败,则将返回消息改成551失败报文。
public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
if (writeRequest.getMessage() instanceof LocalizedDataTransferFtpReply) {
log.info("in file upload filter");
LocalizedDataTransferFtpReply reply = (LocalizedDataTransferFtpReply) writeRequest.getMessage();
if (LocalizedFtpReply.REPLY_226_CLOSING_DATA_CONNECTION == reply.getCode()) {
upload(writeRequest, reply);
}
}
nextFilter.filterWrite(session, writeRequest);
}
private void upload(WriteRequest writeRequest, LocalizedDataTransferFtpReply reply) throws Exception {
FtpFile file = reply.getFile();
String filepath = file.getAbsolutePath();
//
int code = 0;
try {
code = upload(filepath);
if (code != 200) {
throw new Exception("upload code " + code);
}
} catch (Exception e) {
(new File(tempDir + "/" + filepath)).delete();
log.error("error on uploading! file {} ", filepath, e);
DefaultFtpReply newReply = new DefaultFtpReply(LocalizedFtpReply.REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN, "upload to fts failed, " + e.getMessage());
writeRequest.setMessage(newReply);
}
}
这里还有个小问题,就是226报文,在上传和下载时都会用到,卖个关子,请各位自行脑补。
源代码请看附件。