目的:在客户端(浏览器)上像操做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