SpringBoot开发案例之打造私人云网盘

前言

最近在做工作流的事情,正好有个需求,要添加一个附件上传的功能,曾找过不少上传插件,都不是特别满意。无意中发现一个很好用的开源web文件管理器插件 elfinder,功能比较完善,社区也很活跃,还方便二次开发。

环境搭建

软件

地址

SpringBoot

https://spring.io/projects/spring-boot/

elFinder

https://studio-42.github.io/elFinder/

项目截图

周末抽时间做了一个简单的案例,希望对大家有所帮助,下面是简单的项目截图。

项目功能

在线新建目录、文件、附件上传、下载、预览、在线打包,图片在线裁剪、编辑,实现列表试图、图标视图等等一些列功能。

项目配置

项目基于 SpringBoot 注解配置实现,在第三方插件进行二次开发。

application.properties 配置:

# 执行类,内部调用,实现前端相关功能file-manager.command=com.itstyle.cloud.common.elfinder.commandfile-manager.thumbnail.width=80file-manager.volumes[0].Node=file-manager.volumes[0].source=fileSystemfile-manager.volumes[0].alias=file# 文件存放目录,可以自定义file-manager.volumes[0].path=D:/cloudFilefile-manager.volumes[0]._default=truefile-manager.volumes[0].locale=file-manager.volumes[0].constraint.locked=falsefile-manager.volumes[0].constraint.readable=truefile-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:

@Configurationpublic 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

原文发布于微信公众号 - 好好学java(SIHAIloveJAVA)

原文发表时间:2019-04-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券