目的:在客戶端(瀏覽器)上像操做window系統中的文件/文件夾同樣,操做服務器上的某些指定文件/文件夾javascript
效果圖:php
框架:jsp + springMVC + Tomcatcss
前臺使用 elfinderhtml
這是一個很好用的開源web文件管理器插件,用jquery+jquery-ui寫的,在網上一搜文檔好像也挺多的,因而準備搬到項目中來(挖坑開始),瞭解事後發現做者附帶的後臺demo是php寫的,大多文檔資料也是php的,java的特別少,出了問題也不知道是爲何,急死我的,先後折騰了兩天才勉強能用了,在這裏記錄一下,以供你們參考,本人菜鳥,若是有什麼理解不對的地方,歡迎各位指正。前端
打開官網,把代碼dow下來:java
打開壓縮包:把選中的這些文件拷到項目中:jquery
選中的可能有用,沒選中的確定沒用(爲何?由於這沒拷進項目裏他也能跑,並且沒問題...)git
後臺使用的是一個大神開源的基於java實現demo elfinder-2.x-servletgithub
這個目前還在持續更新中web
接下來開始配置吧,基礎版:
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是最好的了,其次是權限的問題,特別是項目中涉及到一部分人能操做,一部分人只能查看、下載的問題,這個等下一篇再寫了。。。(拖延一下……^-^)
原文出處:https://www.cnblogs.com/aforever/p/10859828.html