BootStrap fileinput文件上傳組件實例代碼以及遇到的問題
最近用到圖片文件上傳的功能,對比之後本人決定選用bootstrap fileinput控件,本篇介紹如何使用bootstrap fileinput.js,file input等插件,該插件功能強大,樣式非常美觀,並且支持上傳文件預覽,ajax同步或異步上傳,拖曳文件上傳等炫酷的功能,最好用的文件上傳組件。說實話:本人已經是使用了一段時間纔來分享給大家的。非常實用、好用。
bootstrap-fileinput是一款非常優秀的HTML5文件上傳插件,支持文件預覽、多選等一系列特性。一款非常優秀的HTML5文件上傳插件,支持bootstrap 3.x 和4.x版本,具有非常多的特性:多文件選擇。這個插件能最簡單的幫你完成文件上傳功能,且使用bootstrap樣式。還支持多種文件的預覽,images, text, html, video, audio, flash。另外還支持ajax方式上傳文件,可以看到上傳進度。支持拖拽的方式添加和刪除文件。
接下來我就一步一步來說怎麼實現它,以及可能會遇到的一些問題。首先,大家需要的話,可以看看如下的源碼以及API地址:
- bootstrap-fileinput源碼:https://github.com/kartik-v/bootstrap-fileinput
- bootstrap-fileinput在線API:http://plugins.krajee.com/file-input
- bootstrap-fileinput Demo展示:http://plugins.krajee.com/file-basic-usage-demo
其次我還參考了其他一些資料,
Git下載以及參考地址:
- bootstrap-fileinput:https://github.com/kartik-v/bootstrap-fileinput
- Deme實例:http://plugins.krajee.com/file-basic-usage-demo#basic-example-1
- API詳細說明:http://bootstrap-fileinput.com/
OK,看了這麼多實例、Demo,我們就來用一用吧。
一、安裝bootstrap fileinput
本人在項目中是使用npm進行安裝的,只需要在項目的webapps下,空白地方按住shift點擊右鍵,選擇在此處打開命令查看,輸入如下命令即可安裝,如下圖:
npm install bootstrap-fileinput
回車後安裝完成即可。在對應的package.json文件和node_modules文件中就會生成版本號並下載好該控件的js和css文件;
二、實戰
安裝完成後,我們就可以使用了。
1、首先我們先將js和css文件引入到jsp中。
完整代碼如下:
<!-- 這個文件中集中存放引入共用的css文件-->
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<script>
//'assets/bootstrap-table/src/extensions/editable/bootstrap-table-editable.js',
//'http://rawgit.com/hhurz/tableExport.jquery.plugin/master/tableExport.js',
//'http://rawgit.com/vitalets/x-editable/master/dist/bootstrap3-editable/js/bootstrap-editable.js'
var scripts = [
"<c:url value='/node_modules/bootstrap-table/dist/bootstrap-table.min.js'/>",
"<c:url value='/node_modules/bootstrap-table/dist/extensions/export/bootstrap-table-export.min.js'/>",
"<c:url value='/js/lib/bootstrap-table-treegrid.js'/>",
"<c:url value='/node_modules/bootstrap-table/dist/locale/bootstrap-table-zh-CN.min.js'/>",
"<c:url value='/node_modules/jquery-validation/dist/jquery.validate.min.js'/>",
"<c:url value='/node_modules/jquery-validation/dist/additional-methods.js'/>",
"<c:url value='/node_modules/jquery-validation/dist/localization/messages_zh.js'/>",
"<c:url value='/node_modules/sweetalert/dist/sweetalert.min.js'/>",
"<c:url value='/node_modules/x-editable/dist/bootstrap3-editable/js/bootstrap-editable.min.js'/>",
"<c:url value='/node_modules/bootstrap-table/dist/extensions/editable/bootstrap-table-editable.min.js'/>",
"<c:url value='/node_modules/node-waves/dist/waves.min.js'/>",
"<c:url value='/node_modules/jquery-confirm/dist/jquery-confirm.min.js'/>",
"<c:url value='/node_modules/bootstrap-fileinput/js/fileinput.js'/>",
"<c:url value='/node_modules/bootstrap-fileinput/js/locales/zh.js'/>",
"<c:url value='/node_modules/lightgallery/dist/js/lightgallery-all.min.js'/>",
"<c:url value='/node_modules/admin-lte/plugins/iCheck/icheck.min.js'/>",
"<c:url value='/node_modules/jquery-jsonview/dist/jquery.jsonview.js'/>",
"<c:url value='/node_modules/quill/dist/quill.js'/>",
"<c:url value='/node_modules/video.js/dist/video.min.js'/>",
"<c:url value='/node_modules/videojs-flash/dist/videojs-flash.min.js'/>",
"<c:url value='/node_modules/videojs-contrib-hls/dist/videojs-contrib-hls.min.js'/>",
],
eachSeries = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
return callback();
}
var completed = 0;
var iterate = function () {
iterator(arr[completed], function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed >= arr.length) {
callback(null);
}
else {
iterate();
}
}
});
};
iterate();
};
function getScript(url ,callback){
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = url;
var done = false;
// 對所有的瀏覽器添加頭部
script.onload = script.onreadystatechange = function() {
if (!done && (!this.readyState ||
this.readyState == 'loaded' || this.readyState == 'complete')) {
done = true;
if (callback)
callback();
// 處理IE內存泄露
script.onload = script.onreadystatechange = null;
}
};
head.appendChild(script);
// 處理所有使用腳本元素注入
return undefined;
}
//動態獲取css
function getCss(path){
if(!path || path.length === 0){
throw new Error('argument "path" is required !');
}
var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.href = path;
link.rel = 'stylesheet';
link.type = 'text/css';
head.appendChild(link);
}
</script>
<script>
getCss("<c:url value='/css/copyImgUtl.css'/>")
getCss("<c:url value='/node_modules/bootstrap-table/dist/bootstrap-table.min.css'/>")
getCss("<c:url value='/node_modules/lightgallery/dist/css/lightgallery.min.css'/>")
getCss("<c:url value='/node_modules/bootstrap-fileinput/css/fileinput.css'/>")
getCss("<c:url value='/node_modules/admin-lte/plugins/iCheck/all.css'/>")
getCss("<c:url value='/node_modules/jquery-confirm/dist/jquery-confirm.min.css'/>")
</script>
2、在jsp中編寫HTML代碼塊,如下圖:
完整代碼如下:
<div class="box box-success">
<div class="box-body">
<div class="modal-header">
<%-- <span class="modal-title" id="exampleModalLabel">
<i class="fa fa-hand-o-right" aria-hidden="true"></i>【 縮略圖 】<i class="fa fa-hand-o-left" aria-hidden="true"></i>
</span>--%>
<div class="form-group">
<%-- <label for="selectedImgTypeId">模板名稱</label>--%>
<select id="selectedImgTypeId" class="form-control" style="width: 100%;">
<option selected="selected" value="">請先選擇圖片分類名稱...</option>
<c:forEach items="${mgFileTypeList}" var="fileType" varStatus="vs">
<option value='${fileType.valueUUID}'>${fileType.imgTypeName}</option>
</c:forEach>
</select>
</div>
</div>
<div class="text-muted">
<i class="fa fa-circle-o"> 圖片上傳的格式爲:'jpg'、'jpeg'、'png'、'gif'; 文件大小不能超過5M.</i>
</div>
<div class="form-group" id="divId">
<input id="selectImgDataFileId" name="myFile" type="file" multiple>
</div>
</div>
</div>
3、在js編寫控件初始化代碼,以及相關事件方法。如下圖所示:
<script>
//上傳圖片設置
var projectfileoptions = {
language : 'zh',
uploadUrl:'rest/imagesData/saveImgData',//上傳後臺操作的方法
allowedFileExtensions: ['jpg','jpeg','png','gif'],//限制上傳文件後綴
initialCaption: '請選擇上傳素材',
showUpload: true, //是否顯示上傳按鈕
showCaption: true, //是否顯示標題,
showRemove:true,//是否顯示文件刪除/清除按鈕
//maxFilePreviewSize:10240,
showBrowse:false,//是否顯示瀏覽按鈕
showPreview :true, //是否顯示預覽區域
//maxFileCount: 30, //表示允許同時上傳的最大文件個數
enctype: 'multipart/form-data',
validateInitialCount:true,
browseOnZoneClick: true,
previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",
msgFilesTooMany: "上傳的圖片的數量爲({n}),超過允許的最大數值【{m}】!",
uploadExtraData:function (previewId,index) {//傳遞額外的參數
return {optionVal:$("#selectedImgTypeId option:selected").val(),optionText:$("#selectedImgTypeId option:selected").text()};
},
layoutTemplates:{
//actionDelete:'',//去掉刪除按鈕
actionUpload:'',//去掉上傳按鈕
}
};
$("#selectImgDataFileId").fileinput(projectfileoptions).on('filepreajax', function(event, data,msg, previewId, index) {
// filepreajax此事件在提交ajax請求上傳之前觸發
//獲取下拉菜單的值
var obj = $("#selectedImgTypeId option:selected");
var option_val = obj.val();
//console.log(option_val);
if(option_val == ""){
$(".file-error-message").css("display","block");
$(".file-error-message").html('<ul><li>請先選擇圖片分類名稱</li></ul>');
$("#divId").find(".kv-upload-progress").css("display","none");
$('#selectImgDataFileId').fileinput('enable');
return false;
}
}).on('fileuploaderror', function(event, data, msg) {
//此事件僅在ajax上傳時觸發,並且主要針對ajax上傳時遇到上載或文件輸入驗證錯誤。此事件僅針對ajax上傳並在以下情況下觸發:
//當每個預覽縮略圖中的上傳圖標被點擊並且文件面臨上傳中的驗證錯誤時,或者
//當你將uploadAsync設置爲true並且已觸發批量上傳時。在這種情況下,在任何所選文件面臨上傳驗證錯誤後,會觸發fileuploaderror事件。
var form = data.form, files = data.files, extra = data.extra,jqXHR = data.jqXHR,
response = data.response, reader = data.reader;
//console.log(jqXHR);
//console.log(jqXHR.responseJSON);
$(".file-error-message").html('<ul><li>'+jqXHR.responseJSON+'</li></ul>');
}).on("fileuploaded", function(event, data) {
//此事件僅在ajax上傳且上載每個縮略圖文件之後觸發,即上傳圖片成功後的處理操作
if(data.response.data.num == 1) {
getRefreshImgDataTable();
dialogImgUploadBox.close();
}
});
/**
* 點擊遮罩時重置圖片信息
*/
$("#uploadImgBtnDataTarget").on('show.bs.modal',function () {
$("#selectImgFileId").fileinput('destroy');
$("#selectImgFileId").fileinput(projectfileoptions);
});
//選擇下拉菜單後錯誤信息消失
$("#selectedImgTypeId").on("blur",function () {
var obj = $(this).attr("selected","selected");
var option_val = obj.val();
if(option_val != ""){
$(".file-error-message").css("display","none");
$(".file-error-message").empty();
$("#divId").find(".kv-upload-progress").css("display","none");
$('#selectImgDataFileId').fileinput('enable');
}
});
</script>
代碼中都有註釋加以說明,這裏就不再一 一 進行介紹了。具體要用到的API請參考本文開頭的資料或API文檔;以上的js代碼和HTML給出一個完整的Demo,如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<script>
//上傳圖片設置
var projectfileoptions = {
language : 'zh',
uploadUrl:'rest/imagesData/saveImgData',//上傳後臺操作的方法
allowedFileExtensions: ['jpg','jpeg','png','gif'],//限制上傳文件後綴
initialCaption: '請選擇上傳素材',
showUpload: true, //是否顯示上傳按鈕
showCaption: true, //是否顯示標題,
showRemove:true,//是否顯示文件刪除/清除按鈕
//maxFilePreviewSize:10240,
showBrowse:false,//是否顯示瀏覽按鈕
showPreview :true, //是否顯示預覽區域
//maxFileCount: 30, //表示允許同時上傳的最大文件個數
enctype: 'multipart/form-data',
validateInitialCount:true,
browseOnZoneClick: true,
previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",
msgFilesTooMany: "上傳的圖片的數量爲({n}),超過允許的最大數值【{m}】!",
uploadExtraData:function (previewId,index) {//傳遞額外的參數
return {optionVal:$("#selectedImgTypeId option:selected").val(),optionText:$("#selectedImgTypeId option:selected").text()};
},
layoutTemplates:{
//actionDelete:'',//去掉刪除按鈕
actionUpload:'',//去掉上傳按鈕
}
};
$("#selectImgDataFileId").fileinput(projectfileoptions).on('filepreajax', function(event, data,msg, previewId, index) {
// filepreajax此事件在提交ajax請求上傳之前觸發
//獲取下拉菜單的值
var obj = $("#selectedImgTypeId option:selected");
var option_val = obj.val();
//console.log(option_val);
if(option_val == ""){
$(".file-error-message").css("display","block");
$(".file-error-message").html('<ul><li>請先選擇圖片分類名稱</li></ul>');
$("#divId").find(".kv-upload-progress").css("display","none");
$('#selectImgDataFileId').fileinput('enable');
return false;
}
}).on('fileuploaderror', function(event, data, msg) {
//此事件僅在ajax上傳時觸發,並且主要針對ajax上傳時遇到上載或文件輸入驗證錯誤。此事件僅針對ajax上傳並在以下情況下觸發:
//當每個預覽縮略圖中的上傳圖標被點擊並且文件面臨上傳中的驗證錯誤時,或者
//當你將uploadAsync設置爲true並且已觸發批量上傳時。在這種情況下,在任何所選文件面臨上傳驗證錯誤後,會觸發fileuploaderror事件。
var form = data.form, files = data.files, extra = data.extra,jqXHR = data.jqXHR,
response = data.response, reader = data.reader;
//console.log(jqXHR);
//console.log(jqXHR.responseJSON);
$(".file-error-message").html('<ul><li>'+jqXHR.responseJSON+'</li></ul>');
}).on("fileuploaded", function(event, data) {
//此事件僅在ajax上傳且上載每個縮略圖文件之後觸發,即上傳圖片成功後的處理操作
if(data.response.data.num == 1) {
getRefreshImgDataTable();
dialogImgUploadBox.close();
}
});
/**
* 點擊遮罩時重置圖片信息
*/
$("#uploadImgBtnDataTarget").on('show.bs.modal',function () {
$("#selectImgFileId").fileinput('destroy');
$("#selectImgFileId").fileinput(projectfileoptions);
});
//選擇下拉菜單後錯誤信息消失
$("#selectedImgTypeId").on("blur",function () {
var obj = $(this).attr("selected","selected");
var option_val = obj.val();
if(option_val != ""){
$(".file-error-message").css("display","none");
$(".file-error-message").empty();
$("#divId").find(".kv-upload-progress").css("display","none");
$('#selectImgDataFileId').fileinput('enable');
}
});
</script>
<section class="content-header">
<h1>
圖片數據
<small> >> 上傳圖片</small>
</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-th"></i> 圖片管理</a></li>
<li class="active">圖片數據</li>
<li class="active">上傳圖片</li>
</ol>
</section>
<section class="content">
<div class="box box-success">
<div class="box-body">
<div class="modal-header">
<%-- <span class="modal-title" id="exampleModalLabel">
<i class="fa fa-hand-o-right" aria-hidden="true"></i>【 縮略圖 】<i class="fa fa-hand-o-left" aria-hidden="true"></i>
</span>--%>
<div class="form-group">
<%-- <label for="selectedImgTypeId">模板名稱</label>--%>
<select id="selectedImgTypeId" class="form-control" style="width: 100%;">
<option selected="selected" value="">請先選擇圖片分類名稱...</option>
<c:forEach items="${mgFileTypeList}" var="fileType" varStatus="vs">
<option value='${fileType.valueUUID}'>${fileType.imgTypeName}</option>
</c:forEach>
</select>
</div>
</div>
<div class="text-muted">
<i class="fa fa-circle-o"> 圖片上傳的格式爲:'jpg'、'jpeg'、'png'、'gif'; 文件大小不能超過5M.</i>
</div>
<div class="form-group" id="divId">
<input id="selectImgDataFileId" name="myFile" type="file" multiple>
</div>
</div>
</div>
</section>
4、特別說明,見下圖:
代碼就是通過 data.jqXHR.responseJSON 進行獲取。
$(".file-error-message").html('<ul><li>'+jqXHR.responseJSON+'</li></ul>');
其中file-error-message是FileInput控件命名的class屬性名稱,我是直接拿來就用,主要是將默認的錯誤信息替換爲我自己的錯誤信息或後臺返回的錯誤信息。
5、我們看一下後臺代碼的上傳圖片代碼方法,完整方法代碼如下:
/**
* 保存上傳圖片
* @param request
* @param response
* @param multipartFiles
* @return
*/
@RequestMapping(value = "/saveImgData", method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> saveImgData(HttpServletRequest request, HttpServletResponse response,String optionVal,String optionText,
@RequestParam("myFile")MultipartFile[] multipartFiles) throws IOException, SQLException {
Map<String, Object> result = null;
if(null == multipartFiles && multipartFiles.length == 0){
throw new IllegalArgumentException("文件參數爲空");
}
//臨時文件目錄
File tempFileDirectory = new File(templatePath);
if(!tempFileDirectory.exists() || !tempFileDirectory.isDirectory()){
//不存在,則創建目錄
tempFileDirectory.mkdirs();
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
File templateFile = null;
List<File> fileList = new ArrayList<File>();
List<ImgDataVO> imgDataVOList = new ArrayList<ImgDataVO>();
List<String> fileNamesList = new ArrayList<String>();
for(MultipartFile multipartFile : multipartFiles){
ImgDataVO imgDataVO = new ImgDataVO();
if(null != multipartFile && null != multipartFile.getOriginalFilename()
&& !"".equals(multipartFile.getOriginalFilename().trim())
&& !"null".equals(multipartFile.getOriginalFilename().trim())){
//輸出圖片名稱
String filename = multipartFile.getOriginalFilename();
//圖片大小
long img_size = multipartFile.getSize();
long fileSizeConstant = 5242880;
if(img_size > fileSizeConstant){
throw new DataNotFoundException("圖片大小不能超過5M.");
}
//格式
String format = filename.substring(filename.lastIndexOf(".")+1);
//文件格式判斷工具類
if(FileTool.fileTypeAllowed(format,FileTool.ALLOWED_IMAGE)){
try {
fileNamesList.add(multipartFile.getOriginalFilename().substring(0,
multipartFile.getOriginalFilename().lastIndexOf(".")));
templateFile = File.createTempFile(UUID.randomUUID().toString(),"."+format,tempFileDirectory);
multipartFile.transferTo(templateFile);//存儲爲臨時圖片文件
} catch (IllegalStateException | IOException e) {
deleteTemplateFiles(fileList);
throw new IOException("系統忙,請稍後重試!");
}
fileList.add(templateFile);
}
}
imgDataVOList.add(imgDataVO);
}
try {
result = imgDataInfoService.insertImgDataInfo(fileNamesList,fileList,optionVal,optionText,imgDataVOList);
}catch (IOException e) {
deleteTemplateFiles(fileList);
throw new IOException("系統忙,請稍後重試!");
}catch (SQLException e) {
e.printStackTrace();
deleteTemplateFiles(fileList);
logger.error("查詢出錯" + e.getMessage());
throw new SQLException("系統忙,請稍後重試!");
}
deleteTemplateFiles(fileList);
return result;
}
三、效果展示
我們來看看最後的效果,初始加載如下:
點擊虛線塊就可以進行圖片文件選擇,如下:
這是我們上傳就會看到圖片上傳的進度和成功後的效果,如下:
上傳成功後,我將彈出的dialog關閉,並刷新了Table,這樣就可以在table中看到我們上傳的最新圖片了,如下:
當然也可以選擇同時上傳多張圖片,如下:
具體配置上傳單張或是上傳多張,可以參考projectfileoptions屬性中的配置,可以通過直接配置屬性進行控制。如maxFileCount: 30, 表示允許同時上傳的最大文件個數爲30張圖片,具體配置請參考API詳情文檔http://bootstrap-fileinput.com/options.html中一一進行查找使用即可。
四、關於文件大小的限制
我是限制了文件上傳的大小,如下圖所示:
將上傳的圖片大小和限制的大小進行比較,若超過限制的大小,則爬出異常,並返回前端頁面進行提示用戶。後臺代碼如下:
前端頁面效果如下:
關於Bootstrap FileInput中文API方法的整理,CSDN上也有很多,大家自己去查找搜索看看就可以了,不過不是很全。比較全的還是多多參考http://bootstrap-fileinput.com/options.html這個文檔吧。
好了,就到這裏了,有不足之處,多多指教,也歡迎大家一起討論,一起學習,一起進步噢!!!