SpringBoot开发案例之打造私有云网盘的实现
程序员文章站
2023-12-14 14:22:04
前言
最近在做工作流的事情,正好有个需求,要添加一个附件上传的功能,曾找过不少上传插件,都不是特别满意。无意中发现一个很好用的开源web文件管理器插件 elfinder,...
前言
最近在做工作流的事情,正好有个需求,要添加一个附件上传的功能,曾找过不少上传插件,都不是特别满意。无意中发现一个很好用的开源web文件管理器插件 elfinder,功能比较完善,社区也很活跃,还方便二次开发。
环境搭建
软件 | 地址 |
---|---|
springboot | |
elfinder | https://studio-42.github.io/elfinder/ |
项目截图
周末抽时间做了一个简单的案例,希望对大家有所帮助,下面是简单的项目截图。
项目功能
在线新建目录、文件、附件上传、下载、预览、在线打包,图片在线裁剪、编辑,实现列表试图、图标视图等等一些列功能。
项目配置
项目在第三方插件进行二次开发,基于 springboot 注解配置实现。
application.properties 配置:
# 执行类,内部调用,实现前端相关功能 file-manager.command=com.itstyle.cloud.common.elfinder.command file-manager.thumbnail.width=80 file-manager.volumes[0].node= file-manager.volumes[0].source=filesystem file-manager.volumes[0].alias=file # 文件存放目录,可以自定义 file-manager.volumes[0].path=d:/cloudfile file-manager.volumes[0]._default=true file-manager.volumes[0].locale= file-manager.volumes[0].constraint.locked=false file-manager.volumes[0].constraint.readable=true file-manager.volumes[0].constraint.writable=true
elfinderconfiguration 读取配置:
@component @configurationproperties(prefix="file-manager") //接收application.properties中的file-manager下面的属性 public class elfinderconfiguration { private thumbnail thumbnail; private string command; private list<node> volumes; private long maxuploadsize = -1l; //省略部分代码 }
elfinderstoragefactory 初始化 基础bean:
@configuration public class elfinderconfig { @autowired private elfinderconfiguration elfinderconfiguration; @bean(name = "commandfactory") public commandfactory getcommandfactory() { commandfactory commandfactory = new commandfactory(); commandfactory.setclassnamepattern(elfinderconfiguration.getcommand()+".%scommand"); return commandfactory; } @bean(name = "elfinderstoragefactory") public elfinderstoragefactory getelfinderstoragefactory() { defaultelfinderstoragefactory elfinderstoragefactory = new defaultelfinderstoragefactory(); elfinderstoragefactory.setelfinderstorage(getelfinderstorage()); return elfinderstoragefactory; } @bean(name = "elfinderstorage") public elfinderstorage getelfinderstorage() { defaultelfinderstorage defaultelfinderstorage = new defaultelfinderstorage(); // creates thumbnail defaultthumbnailwidth defaultthumbnailwidth = new defaultthumbnailwidth(); defaultthumbnailwidth.setthumbnailwidth(elfinderconfiguration.getthumbnail().getwidth().intvalue()); // creates volumes, volumeids, volumelocale and volumesecurities character defaultvolumeid = 'a'; list<node> elfinderconfigurationvolumes = elfinderconfiguration.getvolumes(); list<volume> elfindervolumes = new arraylist<>(elfinderconfigurationvolumes.size()); map<volume, string> elfindervolumeids = new hashmap<>(elfinderconfigurationvolumes.size()); map<volume, locale> elfindervolumelocales = new hashmap<>(elfinderconfigurationvolumes.size()); list<volumesecurity> elfindervolumesecurities = new arraylist<>(); // creates volumes for (node elfinderconfigurationvolume : elfinderconfigurationvolumes) { final string alias = elfinderconfigurationvolume.getalias(); final string path = elfinderconfigurationvolume.getpath(); final string source = elfinderconfigurationvolume.getsource(); final string locale = elfinderconfigurationvolume.getlocale(); final boolean islocked = elfinderconfigurationvolume.getconstraint().islocked(); final boolean isreadable = elfinderconfigurationvolume.getconstraint().isreadable(); final boolean iswritable = elfinderconfigurationvolume.getconstraint().iswritable(); // creates new volume volume volume = volumesources.of(source).newinstance(alias, path); elfindervolumes.add(volume); elfindervolumeids.put(volume, character.tostring(defaultvolumeid)); elfindervolumelocales.put(volume, localeutils.tolocale(locale)); // creates security constraint securityconstraint securityconstraint = new securityconstraint(); securityconstraint.setlocked(islocked); securityconstraint.setreadable(isreadable); securityconstraint.setwritable(iswritable); // creates volume pattern and volume security final string volumepattern = character.tostring(defaultvolumeid) + elfinderconstants.elfinder_volume_sercurity_regex; elfindervolumesecurities.add(new defaultvolumesecurity(volumepattern, securityconstraint)); // prepare next volumeid character defaultvolumeid++; } defaultelfinderstorage.setthumbnailwidth(defaultthumbnailwidth); defaultelfinderstorage.setvolumes(elfindervolumes); defaultelfinderstorage.setvolumeids(elfindervolumeids); defaultelfinderstorage.setvolumelocales(elfindervolumelocales); defaultelfinderstorage.setvolumesecurities(elfindervolumesecurities); return defaultelfinderstorage; } }
clouddiskcontroller 控制层实现:
@controller @requestmapping("elfinder/connector") public class clouddiskcontroller { private static final logger logger = loggerfactory.getlogger(clouddiskcontroller.class); public static final string open_stream = "openstream"; public static final string get_parameter = "getparameter"; @resource(name = "commandfactory") private elfindercommandfactory elfindercommandfactory; @resource(name = "elfinderstoragefactory") private elfinderstoragefactory elfinderstoragefactory; @requestmapping public void connector(httpservletrequest request, final httpservletresponse response) throws ioexception { try { response.setcharacterencoding("utf-8"); request = processmultipartcontent(request); } catch (exception e) { throw new ioexception(e.getmessage()); } string cmd = request.getparameter(elfinderconstants.elfinder_parameter_command); elfindercommand elfindercommand = elfindercommandfactory.get(cmd); try { final httpservletrequest protectedrequest = request; elfindercommand.execute(new elfindercontext() { @override public elfinderstoragefactory getvolumesourcefactory() { return elfinderstoragefactory; } @override public httpservletrequest getrequest() { return protectedrequest; } @override public httpservletresponse getresponse() { return response; } }); } catch (exception e) { logger.error("unknown error", e); } } //省略部分代码 }
最后,前端页面引入:
<div id="elfinder"></div> <script type="text/javascript" charset="utf-8"> window.onload = function() { elfinder.prototype.loadcss('/elfinder/jquery-ui-1.12.1.custom/jquery-ui.css'); $('#elfinder').elfinder({ url : '/elfinder/connector', lang: 'zh_cn', height : window.innerheight-20, commandsoptions: { edit: { editors : [ { info:{ name:'编辑', urlascontent: false }, // ace editor // `mimes` is not set for support everything kind of text file load : function(textarea) { var self = this, dfrd = $.deferred(), cdn = './elfinder/ace/', init = function() { if (typeof ace === 'undefined') { console.log(cdn); this.fm.loadscript([ cdn+'/ace.js', cdn+'/ext-modelist.js', cdn+'/ext-settings_menu.js', cdn+'/ext-language_tools.js' ], start); } else { start(); } }, start = function() { var editor, editorbase, mode, ta = $(textarea), tabase = ta.parent(), dialog = tabase.parent(), id = textarea.id + '_ace', ext = self.file.name.replace(/^.+\.([^.]+)|(.+)$/, '$1$2').tolowercase(), // mime/mode map mimemode = { 'text/x-php' : 'php', 'application/x-php' : 'php', 'text/html' : 'html', 'application/xhtml+xml' : 'html', 'text/javascript' : 'javascript', 'application/javascript' : 'javascript', 'text/css' : 'css', 'text/x-c' : 'c_cpp', 'text/x-csrc' : 'c_cpp', 'text/x-chdr' : 'c_cpp', 'text/x-c++' : 'c_cpp', 'text/x-c++src' : 'c_cpp', 'text/x-c++hdr' : 'c_cpp', 'text/x-shellscript' : 'sh', 'application/x-csh' : 'sh', 'text/x-python' : 'python', 'text/x-java' : 'java', 'text/x-java-source' : 'java', 'text/x-ruby' : 'ruby', 'text/x-perl' : 'perl', 'application/x-perl' : 'perl', 'text/x-sql' : 'sql', 'text/xml' : 'xml', 'application/docbook+xml' : 'xml', 'application/xml' : 'xml' }; // set basepath of ace ace.config.set('basepath', cdn); // set base height tabase.height(tabase.height()); // detect mode mode = ace.require('ace/ext/modelist').getmodeforpath('/' + self.file.name).name; if (mode === 'text') { if (mimemode[self.file.mime]) { mode = mimemode[self.file.mime]; } } // show mime:mode in title bar tabase.prev().children('.elfinder-dialog-title').append(' (' + self.file.mime + ' : ' + mode.split(/[\/\\]/).pop() + ')'); // textarea button and setting button $('<div class="ui-dialog-buttonset"/>').css('float', 'left') .append( $('<button>文本框</button>') .button() .on('click', function(){ if (ta.data('ace')) { ta.removedata('ace'); editorbase.hide(); ta.val(editor.session.getvalue()).show().focus(); $(this).text('编辑器'); } else { ta.data('ace', true); editorbase.show(); editor.setvalue(ta.hide().val(), -1); editor.focus(); $(this).text('文本框'); } }) ) .append( $('<button>ace editor setting</button>') .button({ icons: { primary: 'ui-icon-gear', secondary: 'ui-icon-triangle-1-e' }, text: false }) .on('click', function(){ editor.showsettingsmenu(); }) ) .prependto(tabase.next()); // base node of ace editor editorbase = $('<div id="'+id+'" style="width:100%; height:100%;"/>').text(ta.val()).insertbefore(ta.hide()); // ace editor configure ta.data('ace', true); editor = ace.edit(id); ace.require('ace/ext/language_tools'); ace.require('ace/ext/settings_menu').init(editor); editor.$blockscrolling = infinity; editor.setoptions({ theme: 'ace/theme/dawn', mode: 'ace/mode/' + mode, fontsize: '14px', wrap: true, enablebasicautocompletion: true, enablesnippets: true, enableliveautocompletion: true }); editor.commands.addcommand({ name : "savefile", bindkey: { win : 'ctrl-s', mac : 'command-s' }, exec: function(editor) { self.dosave(); } }); editor.commands.addcommand({ name : "closeeditor", bindkey: { win : 'ctrl-w|ctrl-q', mac : 'command-w|command-q' }, exec: function(editor) { self.docancel(); } }); editor.resize(); dfrd.resolve(editor); }; // init & start init(); return dfrd; }, close : function(textarea, instance) { if (instance) { instance.destroy(); $(textarea).show(); } }, save : function(textarea, instance) { instance && $(textarea).data('ace') && (textarea.value = instance.session.getvalue()); }, focus : function(textarea, instance) { instance && $(textarea).data('ace') && instance.focus(); }, resize : function(textarea, instance, e, data) { instance && instance.resize(); } } ] }, quicklook : { // to enable preview with google docs viewer googledocsmimes : ['application/pdf', 'image/tiff', 'application/vnd.ms-office', 'application/msword', 'application/vnd.ms-word', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] } } }); }; </script>
小结
总体来说个人使用还是非常不错的,当然对于一些成熟的网盘系统还是有一些差距。
源码:https://gitee.com/52itstyle/spring-boot-clouddisk
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。