Bootstrap fileinput组件封装及使用详解

网友投稿 356 2023-06-04


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://admineap.com

使用说明

1、初始化

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

css文件

js文件

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

2、弹窗方式调用

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

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

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

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

配置如下:

html代码

上传附件(Max. 10MB)

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代码

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:'',

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:'',

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" ,"");

fileIconMap.put("docx","");

fileIconMap.put("xls" ,"");

fileIconMap.put("xlsx","");

fileIconMap.put("ppt" ,"");

fileIconMap.put("pptx","");

fileIconMap.put("jpg" ,"");

fileIconMap.put("pdf" ,"");

fileIconMap.put("zip" ,"");

fileIconMap.put("rar" ,"");

fileIconMap.put("default" ,"");

}

//从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 arr = new ArrayList<>();

//缓存当前的文件

List 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("

"\n" +

"

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 fileIchttp://onMap.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 fileList=uploaderService.findByCriteria(criteria);

return getPreivewSettings(fileList,request);

}

/**

* 回填已有文件的缩略图

* @param fileList 文件列表

* @param request

* @return initialPreiview initialPreviewConfig fileIds

*/

public FileResult getPreivewSettings(List fileList,HttpServletRequest request){

FileResult fileResult=new FileResult();

List previews=new ArrayList<>();

List 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("

"style='width:auto;height:160px' alt='" + sysFile.getFileName() + " title='" + sysFile.getFileName() + "''>");

}else{

previews.add("

""+getFileIcon(sysFile.getFileName())+"

}

//上传后预览配置

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://admineap.com


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java通过正则表达式获取字符串中数字的方法示例
下一篇:Vue实现自带的过滤器实例
相关文章

 发表评论

暂时没有评论,来抢沙发吧~