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是最好的了,其次是權限的問題,特別是項目中涉及到一部分人能操作,一部分人只能查看、下載的問題,這個等下一篇再寫了。。。(拖延一下……^-^)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM