• java web项目 使用elfinder 实现文件管理器


      目的在客户端(浏览器)上像操作window系统中的文件/文件夹一样,操作服务器上的某些指定文件/文件夹

      效果图:

      

      框架:jsp + springMVC + Tomcat

      前台使用 elfinder

      这是一个很好用的开源web文件管理器插件,用jquery+jquery-ui写的,在网上一搜文档好像也挺多的,于是准备搬到项目中来(挖坑开始),了解过后发现作者附带的后台demo是php写的,大多文档资料也是php的,java的特别少,出了问题也不知道是为什么,急死个人,前后折腾了两天才勉强能用了,在这里记录一下,以供大家参考,本人菜鸟,如果有什么理解不对的地方,欢迎各位指正。

      打开官网,把代码dow下来:

      

      打开压缩包:把选中的这些文件拷到项目中:

      

      选中的可能有用,没选中的肯定没用(为什么?因为这没拷进项目里他也能跑,而且没问题...)

      

      后台使用的是一个大神开源的基于java实现demo  elfinder-2.x-servlet

      这个目前还在持续更新中

      接下来开始配置吧,基础版:

      Maven项目中添加依赖项

    1 <!-- web文件夹管理器jar包 -->
    2     <dependency>
    3         <groupId>com.github.bluejoe2008</groupId>
    4         <artifactId>elfinder-servlet-2</artifactId>
    5         <version>1.2</version>
    6         <classifier>classes</classifier>
    7     </dependency>

      或者直接点击下载 elfinder-servlet-2.jar 包放到lib目录下

      接下来在servlet.xml中配置需要spring管理的各对象

     1 <!-- find appropriate  command executor for given command-->
     2 <bean id="commandExecutorFactory"
     3     class="cn.bluejoe.elfinder.controller.executor.DefaultCommandExecutorFactory">
     4     <property name="classNamePattern"
     5         value="cn.bluejoe.elfinder.controller.executors.%sCommandExecutor" />
     6     <property name="map">
     7         <map>
     8         <!-- 
     9             <entry key="tree">
    10                 <bean class="cn.bluejoe.elfinder.controller.executors.TreeCommandExecutor" />
    11             </entry>
    12         -->
    13         </map>
    14     </property>
    15 </bean>
    16 
    17 <!-- FsService is often retrieved from HttpRequest -->
    18 <!-- while a static FsService is defined here -->
    19 <bean id="fsServiceFactory" class="cn.bluejoe.elfinder.impl.StaticFsServiceFactory">
    20     <property name="fsService">
    21         <bean class="cn.bluejoe.elfinder.impl.DefaultFsService">
    22             <property name="serviceConfig">
    23                 <bean class="cn.bluejoe.elfinder.impl.DefaultFsServiceConfig">
    24                     <property name="tmbWidth" value="80" />
    25                 </bean>
    26             </property>
    27             <property name="volumeMap">
    28                 <!-- two volumes are mounted here -->
    29                 <map>
    30                     <entry key="A">
    31                         <bean class="cn.bluejoe.elfinder.localfs.LocalFsVolume">
    32                             <property name="name" value="MyFiles" />
    33                             <property name="rootDir" value="/tmp/a" />
    34                         </bean>
    35                     </entry>
    36                     <entry key="B">
    37                         <bean class="cn.bluejoe.elfinder.localfs.LocalFsVolume">
    38                             <property name="name" value="Shared" />
    39                             <property name="rootDir" value="/tmp/b" />
    40                         </bean>
    41                     </entry>
    42                 </map>
    43             </property>
    44             <property name="securityChecker">
    45                 <bean class="cn.bluejoe.elfinder.impl.FsSecurityCheckerChain">
    46                     <property name="filterMappings">
    47                         <list>
    48                             <bean class="cn.bluejoe.elfinder.impl.FsSecurityCheckFilterMapping">
    49                                 <property name="pattern" value="A_.*" />
    50                                 <property name="checker">
    51                                     <bean class="cn.bluejoe.elfinder.impl.FsSecurityCheckForAll">
    52                                         <property name="readable" value="true" />
    53                                         <property name="writable" value="true" />
    54                                     </bean>
    55                                 </property>
    56                             </bean>
    57                             <bean class="cn.bluejoe.elfinder.impl.FsSecurityCheckFilterMapping">
    58                                 <property name="pattern" value="B_.*" />
    59                                 <property name="checker">
    60                                     <bean class="cn.bluejoe.elfinder.impl.FsSecurityCheckForAll">
    61                                         <property name="readable" value="true" />
    62                                         <property name="writable" value="false" />
    63                                     </bean>
    64                                 </property>
    65                             </bean>
    66                         </list>
    67                     </property>
    68                 </bean>
    69             </property>
    70         </bean>
    71     </property>
    72 </bean>

       这里配置就是服务器上的文件夹名称,服务器上是在你有tomcat所在盘的根目录下建一个叫tmp的文件夹,但在客户端(浏览器)上显示的就是你配置的名称:MyFiles

       

      加载jar包后,为了查看后台接收数据的url,需要加载源文件(我给的jar包压缩包里)

      

      我们打开这个类cn.bluejoe.elfinder.controller.ConnectorController可以看到映射路径为”connector”,这就是前台请求后台时的url路径(先暂时记住)

      

      看到这里的@controller,说明这就是后台的接收所有请求的入口,要让springmvc管理这个类,我们需要在springmvc-servlet.xml中加入这个类所在包的扫描

    <context:component-scan base-package="cn.bluejoe.elfinder.controller" />

      

      接着开始写前台页面(我用的是jsp页面):

      可以直接拿elfinder那个包里的elfinder.html改,但他里面没有引入js和css,所以还是自己来写吧

      最好按照下面给出的顺序导入,因为在最开始我没有注意,导致很多样式是乱的,响应到了错误的地方

      导入jquery.js,版本稍高的好,因为我发现他的里面用的是jquery-3.*的版本,这个根据自己的路径来导  

    <script src="${pageContext.request.contextPath}/js/jquery-3.2.1.min.js" type="text/javascript" charset="utf-8"></script>

      导入jquery-ui.js jquery-ui.css ,接下来的这些文件的路径都是根据最开始拷到项目中的elfinder包里去找

    <link href="${pageContext.request.contextPath}/elfinder/jquery/jquery-ui-1.12.0.css" rel="stylesheet" type="text/css" media="screen" charset="utf-8"> 
    <script src="${pageContext.request.contextPath}/elfinder/jquery/jquery-ui-1.12.0.js" type="text/javascript" charset="utf-8"></script>

      导入elfinder.css、theme.css

    <link rel="stylesheet" href="${pageContext.request.contextPath}/elfinder/css/elfinder.min.css" type="text/css" media="screen" charset="utf-8">
    <link rel="stylesheet" href="${pageContext.request.contextPath}/elfinder/css/theme.css" type="text/css" media="screen" charset="utf-8">

      导入elfinder.js

    <script src="${pageContext.request.contextPath}/elfinder/js/elfinder.min.js" type="text/javascript" charset="utf-8"></script>

      导入中文语言包elfinder.zh_CN.js,elfinder是支持国际化的,从2.0版本开始可以完美支持中文了,如果这里不导入,不配置,默认是英文的

    <script src="${pageContext.request.contextPath}/elfinder/js/i18n/elfinder.ru.js" type="text/javascript" charset="utf-8"></script>
    <script src="${pageContext.request.contextPath}/elfinder/js/i18n/elfinder.zh_CN.js" type="text/javascript" charset="utf-8"></script>

      在html标签中声明容器:

    <div id="elfinder" ></div>

      Js代码:

    <script type="text/javascript" charset="utf-8">
        $(document).ready(function() {
            $('#elfinder').elfinder({
                url : '${pageContext.request.contextPath}/connector',    //这里的请求地址对应controller中的地址
                lang : 'zh_CN',        //配置默认语言为中文
                height : parseInt(window.screen.availHeight * 0.7)        //配置高度为浏览器高度的0.7
            });
        });
    </script>

      此时启动项目应该能看到以下页面了

      此时一个坑出现了,我传什么文件都提示“未知的命令:null”,以及后台提示:unknown command:null,  google了几个小时才发现是因数servlet.xml中配置了

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <property name="defaultEncoding" value="UTF-8" />
            <property name="maxUploadSize" value="104857600" />
            <property name="maxInMemorySize" value="2048" />
    </bean>

      两个冲突了,去掉CommonsMultipartResolver就可以,但是项目中其他地方用到的上传就无法使用了,度娘了很久说冲突可以写一个代理来解决(不太会),直接把别人的代码拿来(好几百行),发现并没卵用,气死个人,于是又开始疯狂搜索...

      最后发现根本不用什么代理,CommonsMultipartResolver这个类中有一个public boolean isMultipart(HttpServletRequest request)方法,我们继承这个类,重写这个isMultipart方法返回true和false就可以达到是否使用这个类来处理上传了

      此处使用拦截器来判断其是我们的elfinder的上传文件或是其他上传方式,这里主要是用请求url的方式来判断是否为elfinder的请求,分三个类,代码如下:

    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    
    public class MultipartContextFileter implements Filter  {
    
        FilterConfig config;
        
        @Override
        public void destroy() {
            
        }
    
        @Override
        public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain chain)
                throws IOException, ServletException {
            boolean isData = false;
            HttpServletRequest req = (HttpServletRequest)srequest;
             
            // 根据web.xml中的配置,判断当前url是否跳过此过滤器
            String excludeURL = config.getInitParameter("excludeURL");
            if (excludeURL != null && !"".equals(excludeURL)) {
                if (req.getRequestURI().indexOf(excludeURL) != -1) {
                    isData = true;
                }
            }
             
            if (isData) {
                String content_type = req.getContentType();
                if (content_type != null && content_type.indexOf("multipart/form-data") != -1) {
                    MyMultiPartRequest jakarta = new MyMultiPartRequest(req);
                    jakarta.isData = true;
                    req = jakarta;
                }
            }
             
            chain.doFilter(req, sresponse);
            
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
            config = arg0;
            
        }
    
    }
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
     /**
      * 继承request,对其进行包装,以保存更多信息,用于保存判断是否是elfinder的请求,后面执行时可以判断是否跳过CommonsMultipartResolver的处理
      */ public class MyMultiPartRequest extends HttpServletRequestWrapper { public boolean isData = false; //是否执行自定义的CommonsMultipartResolver public MyMultiPartRequest(HttpServletRequest request) { super(request); } }
    public class CommonsMultipartResolver extends org.springframework.web.multipart.commons.CommonsMultipartResolver {
    
        /**
         * 这里是处理Multipart http的方法。如果这个返回值为true,那么Multipart http
         * body就会MyMultipartResolver 消耗掉.如果这里返回false
         * 那么就会交给后面的自己写的处理函数处理例如刚才elfinder请求
         * */
        @Override
        public boolean isMultipart(HttpServletRequest request) {
            if(request instanceof MyMultiPartRequest){
                MyMultiPartRequest trequest = (MyMultiPartRequest)request;
                if(trequest.isData){
                    return false;
                }
            }
            return super.isMultipart(request);
        }
    }

      然后在web.xml中配置拦截器,使其生效

    <filter>
        <filter-name>MultiPartFilter</filter-name>
        <filter-class>com.sctbyc.sware.controller.resourceLibrary.filter.MultipartContextFileter</filter-class>
        <init-param>
            <param-name>excludeURL</param-name>
            <param-value>connector</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>MultiPartFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

      当然也不要忘记把自己刚刚写的处理文件上传的类配置到xml中,这样就spring就会自动创建及调用我们写的这个类了

      

    <bean id="multipartResolver" class="我们定义的CommonsMultipartResolver这个类的全路径名">
         <property name="defaultEncoding" value="UTF-8" />
         <property name="maxUploadSize" value="104857600" />
         <property name="maxInMemorySize" value="2048" />
    </bean>

      好了,这下就可以正常使用了上传文件了,好TM开心,赶紧各种建文件夹,上传文件

      此时第二个坑出现了(文件超过2M传上去就是一个blob文件,且只有几十k到1M多不等),第一反应这应该是个不完整的二进制文件,但为什么呢?F12打开浏览器,看了下发现上传文件时它一直在不停的发请求,原来是这个前端框架使用的大文件分段上传的技术,就是把一个文件切成很多小块,一直发请求,一点点的上传,而后台似乎并没有这样实现,所以造成了这种情况,相当于多大的文件,最后都只保存了最后一次上传的那一块,知道了原因,开始查elfinder的文档看看他怎么说:果然还真有这样一个配置项:

      他说默认是10M,这寻思也没有啊,我的文件超过2M就不行了,于是我就配置了一个这个,再在后面加了两个0,约等于1G了,再试,还是不行啊,超过2M就截断了,又开始查文档,以为是自己配置的姿势没对,弄了很久,不行,没办法,只能看他的elfinder.full.js了,看看是不是这其中有什么鬼,果然我发现了一个东西

      这里默认为2M-8K的大小,和我们配置的大小中取一个,但使用的是Math.min,取得是其中小的一个,难怪我们的大了他就不用了,所能我们把他改成Math.max就可以使用我们配置的大小了,妈妈再也不用担心我给的容量不够了,注意这里查看的是elfinder.full.js(即原版),但我们引入的时候是引入的elfinder.mini.js(压缩版),所以要去mini.js中修改才有用,(因为mini版没有格式,不好找,这里告诉大家一个小技巧,可以Ctrl+F打开搜索框,搜索2097152,也就是上图里的数字,一下就找到了)(这里测试的时候因为本地tomcat给的空间不够,所报了一个OutMemoryError,内存溢出,不过不用担心,生产环境给的是16个G,随便他传)

      还有一个问题就是上传时有一个选择目录,但好像支持得不太好,传不上去,也不知道怎么改,所以我索性就在elfinder.js中把这个给屏蔽了,过程如下:

      浏览器中检查这个按钮,发现他的html代码为:

    <div class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only elfinder-tabstop elfinder-focus"><span class="ui-button-text">

      所以去elfinder.mini.js中搜索出来,在他之前加上一个判断,如果是选择目录,就返回一个空:

    if(i=='selectFolder')return '<span></span>';

      这里等于selectFolder是因为在elfinder.zh_CN.js 中可以找到 "选择目录"对应的英文就是“selectFolder”

     

      到这里,基本配置就结束了,从使用上来说几乎是没有问题了。

      剩下的就该考虑到部分需要优化的内容了:还记得我们最开始的时候说过,后台的jar包中给定了请求的url了,但只有一个,这很容易冲突,特别是项目大了过后,更大概率会出现了,所以我们就需要自己来定义url是最好的了,其次是权限的问题,特别是项目中涉及到一部分人能操作,一部分人只能查看、下载的问题,这个等下一篇再写了。。。(拖延一下……^-^)

  • 相关阅读:
    枚举求解,也叫暴力破解
    多线程之线程的中止
    beginners with the Multithreading programming
    EditBox control Update Problem (A CString type EditBox control in a loop cannot be updated immidiately)
    有关多线程的一些技术问题
    多线程编程基础知识
    VC的若干实用小技巧 (如何干净的删除一个类)
    进入MFC讲坛的前 (Window 程序详细分析)
    Multithreading using MFC in Plain English: Part I
    关于在VS2005环境下无法从源视图切换到设计视图的解决方案
  • 原文地址:https://www.cnblogs.com/aforever/p/10859828.html
Copyright © 2020-2023  润新知