首页 > 编程 > Java > 正文

SpringBoot开发案例之打造私有云网盘的实现

2019-11-26 09:05:16
字体:
来源:转载
供稿:网友

前言

最近在做工作流的事情,正好有个需求,要添加一个附件上传的功能,曾找过不少上传插件,都不是特别满意。无意中发现一个很好用的开源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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表