SpringBoot開發案例之打造私有雲網盤

来源:https://www.cnblogs.com/smallSevens/archive/2019/04/16/10712643.html
-Advertisement-
Play Games

前言 最近在做工作流的事情,正好有個需求,要添加一個附件上傳的功能,曾找過不少上傳插件,都不是特別滿意。無意中發現一個很好用的開源web文件管理器插件 elfinder,功能比較完善,社區也很活躍,還方便二次開發。 環境搭建 | 軟體 | 地址| | | | | SpringBoot| https: ...


前言

最近在做工作流的事情,正好有個需求,要添加一個附件上傳的功能,曾找過不少上傳插件,都不是特別滿意。無意中發現一個很好用的開源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.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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、資料庫基礎 1.1什麼是資料庫? 什麼是資料庫? 答:就是一個很大的一個文件,只不過這個文件可以通過一些‘命令’操作數據; 增、刪、改、查數據; 資料庫等於持久數據和數據操作的一個統稱。 資料庫是按照數據結構來組織、存儲及管理數據的倉庫。 資料庫有哪些? MySQL、SQL server、Ora ...
  • 文章首發: "行為型模式:訪問者模式" 十一大行為型模式之十一:訪問者模式。 簡介 姓名 :訪問者模式 英文名 :Visitor Pattern 價值觀 :來訪者便是客,招待就是 個人介紹 : Represent an operation to be performed on the element ...
  • 一、簡介 ntop是一家以技術為驅動的公司,用戶多為個人和小公司,主要經營四款產品:Packet Capture、Traffic Recording、Network Probe、Traffic Analysis。 二、packet Capture 網路抓包使用具有PF_RING的商用硬體進行線速數據 ...
  • 系列鏈接地址: 深入理解設計模式 系列目錄 一、產品汪的神助攻,代碼狗的安慰劑 定義:設計模式,指的是一個場景(context)下的一種解決方法(Solution),只要大家都認可某種模式,那麼就只需要很短的一個名字,就可以代替很多很多的語言和文字交流,如果你覺得設計模式降低生產效率,那隻能說你在這 ...
  • 類是不是越小越好?最近在讀John Ousterhout的《A Philosophy of Software Design》,感到作者文筆流暢,書中內容具有啟發性。這裡摘要一部分內容,以供參考、學習。 本文鏈接:https://www.cnblogs.com/hhelibeb/p/10708951. ...
  • 多態的概述多態是繼封裝、繼承之後,面向對象的第三大特性。現實事物經常會體現出多種形態,如學生,學生是人的一種,則一個具體的同學張三既是學生也是人,即出現兩種形態。 Java作為面向對象的語言,同樣可以描述一個事物的多種形態。如Student類繼承了Person類,一個Student的對象便既是Stu... ...
  • URL監控埋點作用 一個http請求來了之後,會自動打點,能夠記錄每個url的訪問情況,並將以此請求後續的調用鏈路串起來,可以在cat上查看logview 可以在cat Transaction及Event 頁面上都看到URL和URL.Forward(如果有Forward請求的話)兩類數據;Trans ...
  • 寫代碼也可以進行資源整合,實現相應的功能,達到預期的目標即可。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...