Apache FtpServer是当下最热门的走ftp协议的用于用户上传下载的服务器。
一般来说,用的话,去官网下载完整的项目文件ftpserver-1.0.6.zip【windows版】和ftpserver-1.0.6.tar.gz【linux版】到本地,解压之后配置一下\ftpserver-1.0.6\apache-ftpserver-1.0.6\res\conf\下的users.properties或者ftpd-full.xml【主要看你走什么样的用户验证方式。users.properties:把用户信息配置在这个文件中。ftpd-full.xml:把用户信息配置在数据库中】
这样去bin目录下启动程序就好了。
但是Apache FtpServer从官方文档来看,都没有提及如何改变其中一些功能,只是解释一些它提供的标准功能。
这样对于企业级的应用来说,有些功能并不能满足现有的业务。
比如,我想限制每个ftp用户上传文件到他的文件目录下时,我想限制每个用户最多上传文件的总大小不超过50M。因为我不想被恶意用户弄爆我的服务器。我查阅了大量资料,发现标准的官方版里面是没有这样的功能的,在ftpd-full.xml和users.properties这里面也没有任何可以修改的参数来控制这样的业务。最后我决定自己通过编程来实现这样一个专门服务于我的这样的FtpServer。
我有这种想法的原因是,Apache FtpServer是纯java写的服务,而且提供了丰富的java接口。
查阅了大量资料后,还是找不到怎么用代码从jar里面启动整个server。
最后用反编译工具反编译整个Apache FtpServer项目后发现了,找到了启动的入口。
1 public MyFtpServer() throws FtpException{ 2 3 //读取my-ftpd-full.xml,连接数据库和监控配置,然后来启动server 4 FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(xmlPath); 5 FtpServer server = null; 6 if (ctx.containsBean("server")) { 7 server = (FtpServer)ctx.getBean("server"); 8 } else { 9 String[] beanNames = ctx.getBeanNamesForType(FtpServer.class); 10 if (beanNames.length == 1) { 11 server = (FtpServer)ctx.getBean(beanNames[0]); 12 } else if (beanNames.length > 1) { 13 logger.info("Using the first server defined in the configuration, named " + beanNames[0]); 14 server = (FtpServer)ctx.getBean(beanNames[0]); 15 } else { 16 logger.info("XML configuration does not contain a server configuration"); 17 } 18 } 19 20 //ftp服务器启动 21 server.start(); 22 23 //在jvm关闭的时候,清理函数 24 addShutdownHook(server); 25 } 26 27 /** 28 * 清理的垃圾的钩子函数 29 * @param engine 30 */ 31 private void addShutdownHook(final FtpServer engine) 32 { 33 Runnable shutdownHook = new Runnable() { 34 public void run() { 35 logger.info("Stopping server..."); 36 engine.stop(); 37 } 38 }; 39 Runtime runtime = Runtime.getRuntime(); 40 runtime.addShutdownHook(new Thread(shutdownHook)); 41 }
配合上我的研究发现,提供的接口中可以在ftpd-full.xml中配置
<ftplets> <ftplet name="MyFtplet"> <beans:bean class="com.shiyi.km.ftpserver.control.MyFtplet"> <!-- <beans:property name="foo" value="123" /> --> </beans:bean> </ftplet> </ftplets>
类似于监听器的东西,可以监听每个用户在上传或者下载的动作,在这些监听事件里面,我每次都去计算那个用户目录下面的文件size总大小,如果超过限制,就stop,并返回警告代码和消息给用户。
1 import java.io.File; 2 import java.io.IOException; 3 4 import org.apache.ftpserver.ftplet.DefaultFtpReply; 5 import org.apache.ftpserver.ftplet.DefaultFtplet; 6 import org.apache.ftpserver.ftplet.FtpException; 7 import org.apache.ftpserver.ftplet.FtpRequest; 8 import org.apache.ftpserver.ftplet.FtpSession; 9 import org.apache.ftpserver.ftplet.FtpletResult; 10 import org.apache.ftpserver.ftplet.User; 11 import org.apache.log4j.Logger; 12 13 import com.shiyi.km.ftpserver.util.ConfigUtil; 14 import com.shiyi.km.ftpserver.util.FileUtil; 15 16 /** 17 * 18 * @fileName MyFtplet.java 19 * @author chenkaideng 20 * @date 2015年8月11日 21 * @describe 监控事件 22 */ 23 public class MyFtplet extends DefaultFtplet{ 24 private static final Logger logger = Logger.getLogger(MyFtplet.class); 25 26 27 @Override 28 public FtpletResult onUploadStart(FtpSession session, FtpRequest request) 29 throws FtpException, IOException { 30 //获取用户信息 31 User user = session.getUser(); 32 logger.info(String.format("用户信息,用户名【%s】,用户工作目录【%s】", user.getName(),user.getHomeDirectory())); 33 File file=new File(user.getHomeDirectory()); 34 35 //判断传入对象是否为一个文件夹对象 36 if(!file.isDirectory()){ 37 logger.info("用户的HomeDirectory不是一个文件夹,请检查路径是否有误!!"); 38 } 39 else{ 40 ConfigUtil configUtil = ConfigUtil.getInstance(); 41 if(FileUtil.overSizeLimit(configUtil.getQuota(), file)){ 42 logger.error(String.format("目前用户[%s]目录下的文件总大小超过配额!!!", user.getName())); 43 session.write(new DefaultFtpReply(228, "The files under the directory over quota")); 44 return FtpletResult.DISCONNECT; 45 } 46 } 47 return super.onUploadStart(session, request); 48 } 51 }
差不多整体的思路是这样的。
有了这些基础,还可以实现各种各样的不同需求,来管理用户目录或者一些其他的业务。