AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > JavaScript

Bootstrap fileinput组件封装及使用详解

51自学网 http://www.wanshiok.com
Bootstrap,fileinput

介绍

通过本文,你可以学习到如何封装或者开发一个前端组件,同时学习Bootstrap-fileinput组件的使用,封装后使用更加简单方便。

BaseFile是AdminEAP框架中基于Bootstrap-fileinput的附件上传组件,它支持 支持多文件、在线预览、拖拽上传等功能,封装后BaseFile主要包括以下功能:

  • 弹出窗口的附件上传
  • 当前界面的附件上传
  • 显示附件明细
  • 可编辑的附件明细(删除、预览、不可新增)

关于Bootstrap-fileinput的API文档可参考http://plugins.krajee.com/file-input

本文源码已在AdminEAP框架(一个基于AdminLTE的Java开发平台)中开源,可在Github下载相关代码:

Github:https://github.com/bill1012/AdminEAP

AdminEAP官网:http://www.admineap.com

使用说明

1、初始化

如果需要在当前界面使用附件上传功能(非弹窗方式)则需要在头部引入相关的css和js文件

css文件

<link rel="stylesheet" href="./resources/common/libs/fileinput/css/fileinput.min.css" rel="external nofollow" >

js文件

<script src="./resources/common/libs/fileinput/js/fileinput.js"></script><script src="./resources/common/libs/fileinput/js/locales/zh.js"></script><!--BaseFile组件--><script src="./resources/common/js/base-file.js"></script>

form表单上还需要配置enctype="multipart/form-data"属性

2、弹窗方式调用

BaseFile支持弹窗方式打开一个附件上传窗口,点击附件上传后,弹出窗口,上传附件关闭窗口后,上传的附件在type=file的控件回填。

在表单中点击弹窗上传附件:

上传完毕,关闭窗口,附件回填

再次打开上传附件上传窗口时,会把已有的附件回填到附件上传窗口。

配置如下:

html代码

   <input type="hidden" name="fileIds" id="fileIds">   <div class="form-group">    <div class="btn btn-default btn-file" id="uploadFile">     <i class="fa fa-paperclip"></i> 上传附件(Max. 10MB)    </div>   </div>   <div class="form-group" id="file_container">    <input type="file" name="file" id="attachment">   </div> 

js代码

$("#uploadFile").file({   title: "请上传附件",   fileinput: {    maxFileSize: 10240,    maxFileCount:3   },   fileIdContainer:"[name='fileIds']",   showContainer:'#attachment',   //显示文件类型 edit=可编辑 detail=明细 默认为明细   showType:'edit',   //弹出窗口 执行上传附件后的回调函数(window:false不调用此方法)   window:true,   callback:function(fileIds,oldfileIds){    //更新fileIds    this.showFiles({     fileIds:fileIds    });   }  });

3、本地界面调用

本地界面调用附件上传,如下图所示:

将上传附件嵌入到当前界面方式

上传后的附件可删除、可预览


(目前图片文件可预览,其他文件不可预览,后期将集成txt/xml/html/pdf的预览功能)

配置如下:

html代码

<div class="form-group" id="file_container">  <input type="file" name="file" id="attachment"></div>

js代码

 $("#attachment").file({   fileinput: {    maxFileSize: 10240,    maxFileCount:3   },   fileIdContainer:"[name='fileIds']",   window:false  });

4、控件参数说明

window 默认为true,弹窗方式打开

title window=true时配置,弹窗的标题,默认为“文件上传”

width window=true时配置,弹窗的宽度,默认900

winId window=true时配置,弹出的id,默认为fileWin

fileinput Bootstrap-fileinput的配置参数,会覆盖默认配置,比如允许上传哪种类型的附件allowedFileTypes,允许上传最大附件大小maxFileSize,允许上传附件的个数maxFileCount等,具体的配置参数可以查询Bootstrap-fileinput的API文档。

fileIdContainer 必须,上传后的附件id存储的位置,id以逗号分隔

showContainer window=true必须配置,文件上传后回填的区域,window=false时如不配置,则取base-file的初始对象

showType window=true配置,值为edit或者detail,edit表示回填后可对数据进行删除、预览,detail只能显示,不能删除

callback window=true配置,关闭附件上传的窗口后执行的回调函数(比如更新当前的文件列表),fileIds,oldfileIds两个参数分别是更新后文件ids和更新前的文件ids

BaseFile默认配置,BaseFile的更多实现,请查看BaseFile源码

BaseFile.prototype.default = {  winId: "fileWin",  width: 900,  title: "文件上传",  //通用文件上传界面  url: basePath + "/file/uploader",  //默认支持多文件上传  multiple: true,  //默认弹出附件上传窗口  window:true,  showType:"detail",  fileinput: {   language: 'zh',   uploadUrl: basePath + "/file/uploadMultipleFile",   deleteUrl:basePath+"/file/delete",   uploadAsync:false,   validateInitialCount:true,   overwriteInitial: false,   allowedPreviewTypes: ['image'],   previewFileIcon:'<i class="fa fa-file-o"></i>',   previewFileIconSettings: null,   slugCallback: function (text) {    var newtext=(!text||text=='') ? '' : String(text).replace(/[/-/[/]///{}:;#%=/(/)/*/+/?///^/$/|<>&"']/g, '_');    //去除空格    return newtext.replace(/(^/s+)|(/s+$)/g,"").replace(//s/g,"");   }  } }

5、BaseFile控件源码

/** * 通用文件管理组件 * @author billjiang qq:475572229 */(function ($, window, document, undefined) { 'use strict'; var pluginName = 'file'; $.fn[pluginName] = function (options) {  var self = $(this);  if (this == null)   return null;  var data = this.data(pluginName);  if (!data) {   data = new BaseFile(this, $.extend(true, {}, options));   self.data(pluginName, data);  } }; var BaseFile = function (element, options) {  this.element = element;  //extend优先级 后面的会覆盖前面的  //alert(this.element.selector);  //将容器ID传过去便于弹窗获取到BaseFile对象,如果页面布局不在使用jquery.load方法,则该方法会失效,因为不是一个页面了  options.container = options.container || this.element.selector.replace("#", "");  //初始化文件图标信息  this.getFileIconSettings();  this.options = $.extend(true, {}, this.default, options);  //初始化图标信息  this.initFileIds();  if(this.options.window) {   this.element.click(function () {    $(this).data('file').openWin();   });  }else{   //非弹窗形式   if(this.options.multiple)    this.element.attr("multiple","multiple");  }  //如果配置了附件编辑容器showContainer(附件列表,可单个删除),则进行初始化  if(this.hasDisplayZone()){   this.showFiles();  } } BaseFile.prototype.default = {  winId: "fileWin",  width: 900,  title: "文件上传",  //通用文件上传界面  url: basePath + "/file/uploader",  //默认支持多文件上传  multiple: true,  //默认弹出附件上传窗口  window:true,  showType:"detail",  fileinput: {   language: 'zh',   uploadUrl: basePath + "/file/uploadMultipleFile",   deleteUrl:basePath+"/file/delete",   uploadAsync:false,   validateInitialCount:true,   overwriteInitial: false,   allowedPreviewTypes: ['image'],   previewFileIcon:'<i class="fa fa-file-o"></i>',   previewFileIconSettings: null,   slugCallback: function (text) {    var newtext=(!text||text=='') ? '' : String(text).replace(/[/-/[/]///{}:;#%=/(/)/*/+/?///^/$/|<>&"']/g, '_');    //去除空格    return newtext.replace(/(^/s+)|(/s+$)/g,"").replace(//s/g,"");   }  } } BaseFile.prototype.getFileInputConfig=function () {  return this.options.fileinput; } BaseFile.prototype.getFileIconSettings = function () {  var self = this;  ajaxPost(basePath + "/file/icons", null, function (icons) {   self.previewFileIconSettings = icons;   //console.log(self.previewFileIconSettings);  }) } BaseFile.prototype.openWin = function () {  var that = this;  var self = $.extend(true, {}, this.options);  //深拷贝后删除属性,这样不会通过后台传送过去,防止被XSS过滤掉特殊字符  //不需要通过参数config=传递到弹窗的参数可使用delete删除  delete self.callback;  delete self.fileIds;  delete self.showContainer;  delete self.fileIdContainer;  delete self.fileinput;  /*console.log(this.options);   console.log("=============");   console.log(self);*/  modals.openWin({   winId: that.options.winId,   url: that.options.url + "?config=" + JSON.stringify(self),   width: that.options.width + "px",   title: that.options.title,   backdrop: "static"  }); } BaseFile.prototype.callbackHandler = function (fileIds) {  //更新fileIds并执行回调函数  var oldfileIds = this.options.fileIds;  this.options.fileIds = fileIds;  this.updateFileIds();  if (this.options.callback) {   this.options.callback.call(this, fileIds, oldfileIds);  } } //调用成功后执行显示附件 BaseFile.prototype.showFiles=function(options){  options=options||{};  if(!this.hasDisplayZone()){   modals.error("请配置showContainer属性,并在容器下配置type=file的input组件");   return;  }  var fileIds=options.fileIds||this.options.fileIds;  if(!fileIds&&this.options.window){   $(this.options.showContainer).hide();   return;  }  //显示  $(this.options.showContainer).show();  var fileComponet=$(this.options.showContainer);  var fileResult=this.getFileResult(fileIds),preview=fileResult.initialPreview,previewConfig=fileResult.initialPreviewConfig,self=this;  //配置三类参数 edit=附件列表(可删除) detail=附件列表(显示) 可上传  var defaultConfig={   initialPreview:preview,   initialPreviewConfig:previewConfig  };  var config;  if(this.options.window){   if(this.options.showType=="edit"){    //全局配置->本方法默认配置->edit属性下配置->外部参数    config=$.extend({},self.options.fileinput,defaultConfig,{     showRemove:false,     showUpload:false,     showClose:false,     showBrowse:false,     showCaption:false    },options);   }else if(this.options.showType=="detail"){    config=$.extend({},self.options.fileinput,defaultConfig,{     showRemove:false,     showUpload:false,     showClose:false,     showBrowse:false,     showCaption:false,     initialPreviewShowDelete:false    },options);   }  }else{   config=$.extend({},self.options.fileinput,defaultConfig,{    showClose:false   },options);  }  if(!config){   modals.error("未找到showFiles中的相关配置");   return;  }  //console.log("config=========="+JSON.stringify(config));  fileComponet.fileinput('destroy');  fileComponet.fileinput(config).on("filedeleted",function (event,key) {   var newfids=self.deleteFileIds(key,self.options.fileIds);   self.options.fileIds=newfids;   self.updateFileIds();  }).on("fileuploaded",function(event,data,previewId,index){   var newfids=self.addFileIds(data.response.fileIds,self.options.fileIds);   self.options.fileIds=newfids;   self.updateFileIds();  }).on("filebatchuploadsuccess",function (event,data,previewId,index) {   var newfids=self.addFileIds(data.response.fileIds,self.options.fileIds);   self.options.fileIds=newfids;   self.updateFileIds();  }).on("filezoomhidden", function(event, params) {   $(document.body).removeClass('modal-open');   $(document.body).css("padding-right","0px");  }); } /**  * 向targetIds里删除数据fileIds  * @param fileIds  * @param targetIds  */ BaseFile.prototype.deleteFileIds=function(fileIds,targetIds){  if(!fileIds) return targetIds;  //没有文件删除,其中必有蹊跷  if(!targetIds){   modals.error("没有要删除的文件,请检查是否数据没有初始化");   return;  }  var fileIdArr=fileIds.split(",");  var fresult=targetIds.split(",");  $.each(fileIdArr,function (index,fileId){   //存在则删除   if($.inArray(fileId,fresult)>-1){    fresult.splice($.inArray(fileId,fresult),1);   }  })  return fresult.join(); } /**  * 向targetIds里加数据fileIds  * @param fileIds  * @param targetIds  */ BaseFile.prototype.addFileIds=function (fileIds,targetIds) {  if(!fileIds)return targetIds;  var fileIdArr=fileIds.split(",");  var fresult=[];  if(targetIds){   fresult=targetIds.split(",");  }  $.each(fileIdArr,function (index,fileId){   //不存在,新增   if($.inArray(fileId,fresult)==-1){    fresult.push(fileId);   }  })  return fresult.join(); } BaseFile.prototype.updateFileIds=function(){  if(this.options.fileIdContainer)   $(this.options.fileIdContainer).val(this.options.fileIds); } BaseFile.prototype.initFileIds=function(){  //不弹出窗口的话一定要绑定fileIdContainer  if(!this.options.window){   if(!this.options.fileIdContainer||!$(this.options.fileIdContainer)){    modals.info("请设置fileIdContainer属性");    return;   }  }  if(!this.options.fileIds){   if(this.options.fileIdContainer){    this.options.fileIds=$(this.options.fileIdContainer).val();   }  } } BaseFile.prototype.getFileResult=function(fileIds){  var ret=null;  ajaxPost(basePath+"/file/getFiles",{fileIds:fileIds},function(result){   ret=result;  });  return ret; }; /**  * 是否有显示区域  * @returns {boolean}  */ BaseFile.prototype.hasDisplayZone=function(){  if(!this.options.showContainer){   this.options.showContainer=this.element.selector;  }  if(!this.options.showContainer||!$(this.options.showContainer)){   return false;  }  return true; }})(jQuery, window, document);

6、后端源码

package com.cnpc.framework.base.controller;import com.cnpc.framework.base.entity.SysFile;import com.cnpc.framework.base.entity.User;import com.cnpc.framework.base.pojo.AvatarResult;import com.cnpc.framework.base.pojo.FileResult;import com.cnpc.framework.base.pojo.MarkDownResult;import com.cnpc.framework.base.pojo.Result;import com.cnpc.framework.base.service.UploaderService;import com.cnpc.framework.util.SecurityUtil;import com.cnpc.framework.utils.DateUtil;import com.cnpc.framework.utils.FileUtil;import com.cnpc.framework.utils.PropertiesUtil;import com.cnpc.framework.utils.StrUtil;import org.apache.commons.fileupload.util.Streams;import org.hibernate.criterion.DetachedCriteria;import org.hibernate.criterion.Order;import org.hibernate.criterion.Restrictions;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.multipart.MultipartFile;import org.springframework.web.multipart.MultipartHttpServletRequest;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import java.io.*;import java.util.*;@Controller@RequestMapping("/file")public class UploaderController { private static Logger logger= LoggerFactory.getLogger(UploaderController.class); //previewFileIconSettings public static Map fileIconMap=new HashMap(); @Resource private UploaderService uploaderService; static {  fileIconMap.put("doc" ,"<i class='fa fa-file-word-o text-primary'></i>");  fileIconMap.put("docx","<i class='fa fa-file-word-o text-primary'></i>");  fileIconMap.put("xls" ,"<i class='fa fa-file-excel-o text-success'></i>");  fileIconMap.put("xlsx","<i class='fa fa-file-excel-o text-success'></i>");  fileIconMap.put("ppt" ,"<i class='fa fa-file-powerpoint-o text-danger'></i>");  fileIconMap.put("pptx","<i class='fa fa-file-powerpoint-o text-danger'></i>");  fileIconMap.put("jpg" ,"<i class='fa fa-file-photo-o text-warning'></i>");  fileIconMap.put("pdf" ,"<i class='fa fa-file-pdf-o text-danger'></i>");  fileIconMap.put("zip" ,"<i class='fa fa-file-archive-o text-muted'></i>");  fileIconMap.put("rar" ,"<i class='fa fa-file-archive-o text-muted'></i>");  fileIconMap.put("default" ,"<i class='fa fa-file-o'></i>"); } //从setting.properties文件中注入文件相对目录(相对目录为显示文件) //@Value("${uploaderPath}") 只有配置@Config才能注入 private static final String uploaderPath=PropertiesUtil.getValue("uploaderPath"); /**  * 跳转到通用文件上传窗口  * @return  */ @RequestMapping(value="/uploader",method = RequestMethod.GET) public String uploader(String config,HttpServletRequest request){  request.setAttribute("config",config);  return "base/file/file_uploader"; } /**  * 通用文件上传接口,存储到固定地址,以后存储到文件服务器地址  */ @RequestMapping(value = "/uploadFile", method = RequestMethod.POST) @ResponseBody public SysFile uploadFile(@RequestParam(value = "file", required = false) MultipartFile file,        HttpServletRequest request, HttpServletResponse response) {  //TODO dosomething  return new SysFile(); } /**  * 多文件上传,用于uploadAsync=false(同步多文件上传使用)  * @param files  * @param request  * @param response  * @return  */ @RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST) @ResponseBody public FileResult uploadMultipleFile(@RequestParam(value = "file", required = false) MultipartFile[] files,           HttpServletRequest request, HttpServletResponse response) throws IOException {  System.out.println("the num of file:"+files.length);  FileResult msg = new FileResult();  ArrayList<Integer> arr = new ArrayList<>();  //缓存当前的文件  List<SysFile> fileList=new ArrayList<>();  String dirPath = request.getRealPath("/");  for (int i = 0; i < files.length; i++) {   MultipartFile file = files[i];   if (!file.isEmpty()) {    InputStream in = null;    OutputStream out = null;    try {     File dir = new File(dirPath+uploaderPath);     if (!dir.exists())      dir.mkdirs();     //这样也可以上传同名文件了     String filePrefixFormat="yyyyMMddHHmmssS";     System.out.println(DateUtil.format(new Date(),filePrefixFormat));     String savedName=DateUtil.format(new Date(),filePrefixFormat)+"_"+file.getOriginalFilename();     String filePath=dir.getAbsolutePath() + File.separator + savedName;     File serverFile = new File(filePath);     //将文件写入到服务器     //FileUtil.copyInputStreamToFile(file.getInputStream(),serverFile);     file.transferTo(serverFile);     SysFile sysFile=new SysFile();     sysFile.setFileName(file.getOriginalFilename());     sysFile.setSavedName(savedName);     sysFile.setCreateDateTime(new Date());     sysFile.setUpdateDateTime(new Date());     sysFile.setCreateUserId(SecurityUtil.getUserId());     sysFile.setDeleted(0);     sysFile.setFileSize(file.getSize());     sysFile.setFilePath(uploaderPath+File.separator+savedName);     uploaderService.save(sysFile);     fileList.add(sysFile);     /*preview.add("<div class=/"file-preview-other/">/n" +       "<span class=/"file-other-icon/"><i class=/"fa fa-file-o text-default/"></i></span>/n" +       "</div>");*/     logger.info("Server File Location=" + serverFile.getAbsolutePath());    } catch (Exception e) {     logger.error( file.getOriginalFilename()+"上传发生异常,异常原因:"+e.getMessage());     arr.add(i);    } finally {     if (out != null) {      out.close();     }     if (in != null) {      in.close();     }    }   } else {    arr.add(i);   }  }  if(arr.size() > 0) {   msg.setError("文件上传失败!");   msg.setErrorkeys(arr);  }  FileResult preview=getPreivewSettings(fileList,request);  msg.setInitialPreview(preview.getInitialPreview());  msg.setInitialPreviewConfig(preview.getInitialPreviewConfig());  msg.setFileIds(preview.getFileIds());  return msg; } //删除某一项文件 @RequestMapping(value="/delete",method = RequestMethod.POST) @ResponseBody public Result delete(String id,HttpServletRequest request){  SysFile sysFile=uploaderService.get(SysFile.class,id);  String dirPath=request.getRealPath("/");  FileUtil.delFile(dirPath+uploaderPath+File.separator+sysFile.getSavedName());  uploaderService.delete(sysFile);  return new Result(); } /**  * 获取字体图标map,base-file控件使用  */ @RequestMapping(value="/icons",method = RequestMethod.POST) @ResponseBody public Map getIcons(){  return fileIconMap; } /**  * 根据文件名获取icon  * @param fileName 文件  * @return  */ public String getFileIcon(String fileName){  String ext= StrUtil.getExtName(fileName);  return fileIconMap.get(ext)==null?fileIconMap.get("default").toString():fileIconMap.get(ext).toString(); } /**  * 根据附件IDS 获取文件  * @param fileIds  * @param request  * @return  */ @RequestMapping(value="/getFiles",method = RequestMethod.POST) @ResponseBody public FileResult getFiles(String fileIds,HttpServletRequest request){  String[] fileIdArr=fileIds.split(",");  DetachedCriteria criteria=DetachedCriteria.forClass(SysFile.class);  criteria.add(Restrictions.in("id",fileIdArr));  criteria.addOrder(Order.asc("createDateTime"));  List<SysFile> fileList=uploaderService.findByCriteria(criteria);  return getPreivewSettings(fileList,request); } /**  * 回填已有文件的缩略图  * @param fileList 文件列表  * @param request  * @return initialPreiview initialPreviewConfig fileIds  */ public FileResult getPreivewSettings(List<SysFile> fileList,HttpServletRequest request){  FileResult fileResult=new FileResult();  List<String> previews=new ArrayList<>();  List<FileResult.PreviewConfig> previewConfigs=new ArrayList<>();  //缓存当前的文件  String dirPath = request.getRealPath("/");  String[] fileArr=new String[fileList.size()];  int index=0;  for (SysFile sysFile : fileList) {   //上传后预览 TODO 该预览样式暂时不支持theme:explorer的样式,后续可以再次扩展   //如果其他文件可预览txt、xml、html、pdf等 可在此配置   if(FileUtil.isImage(dirPath+uploaderPath+File.separator+sysFile.getSavedName())) {    previews.add("<img src='." + sysFile.getFilePath().replace(File.separator, "/") + "' class='file-preview-image kv-preview-data' " +      "style='width:auto;height:160px' alt='" + sysFile.getFileName() + " title='" + sysFile.getFileName() + "''>");   }else{    previews.add("<div class='kv-preview-data file-preview-other-frame'><div class='file-preview-other'>" +      "<span class='file-other-icon'>"+getFileIcon(sysFile.getFileName())+"</span></div></div>");   }   //上传后预览配置   FileResult.PreviewConfig previewConfig=new FileResult.PreviewConfig();   previewConfig.setWidth("120px");   previewConfig.setCaption(sysFile.getFileName());   previewConfig.setKey(sysFile.getId());   // previewConfig.setUrl(request.getContextPath()+"/file/delete");   previewConfig.setExtra(new FileResult.PreviewConfig.Extra(sysFile.getId()));   previewConfig.setSize(sysFile.getFileSize());   previewConfigs.add(previewConfig);   fileArr[index++]=sysFile.getId();  }  fileResult.setInitialPreview(previews);  fileResult.setInitialPreviewConfig(previewConfigs);  fileResult.setFileIds(StrUtil.join(fileArr));  return fileResult; }}

总结

本文源码已在AdminEAP框架(一个基于AdminLTE的Java开发平台)中开源,可在Github下载相关代码:

Github:https://github.com/bill1012/AdminEAP

AdminEAP官网:http://www.admineap.com

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


Bootstrap,fileinput  
上一篇:BootstrapValidator实现注册校验和登录错误提示效果  下一篇:Bootstrap栅格系统使用方法及页面调整变形的解决方法