本文介绍如何在AngularJS项目中利用Bootstrap-fileinput插件实现多文件上传、加载与删除功能。通过定义已选择、已上传、已保存三种状态,结合selectedPics数组与data-fileindex属性,解决文件删除后索引错乱问题,并演示如何与JFinal后端交互完成数据库持久化。
多文件上传与管理需求分析
在最近的一个项目中,我们需要实现多文件上传与管理功能。由于项目基于Bootstrap开发,经过对比多种Bootstrap文件上传插件,最终选择了bootstrap-fileinput,因其界面美观且支持多文件管理(插件官方地址:http://plugins.krajee.com/file-input)。具体效果如下:

(注:bootstrap-fileinput不仅限于图片上传,也支持普通文件上传。鉴于图片缩略图更易于辨识,本文以图片上传为例进行说明。)
关于该插件的基本操作,可参考《JS文件上传神器bootstrap fileinput详解》一文。本文重点在于多文件的管理逻辑。
在介绍插件用法之前,先明确项目中对图片管理的具体需求:
1、支持上传多个图片;
2、仅当点击保存按钮时,图片信息才持久化至数据库;
3、支持加载已保存至数据库的图片信息,并提供删除功能。
基于上述需求,我们将文件状态划分为以下三类:
已选择:图片已放入插件界面,但尚未上传至服务器。如上图第3张图片所示,其下方显示有上传按钮。
已上传:图片已上传至服务器,但图片信息尚未保存至数据库。如上图第2张图片所示,其下方显示进度条为100%。
已保存:图片信息已保存至数据库。如上图第1张图片所示,其下方显示有删除按钮,点击即可从数据库中删除该图片信息。
引入必要文件与基础配置
一、引入必要文件
<link href="<%=path%>/static/css/bootstrap-3.3.5/bootstrap.min.css" rel="stylesheet">
<link href="<%=path%>/static/css/bootstrap-3.3.5/fileinput.css" rel="stylesheet">
<script src="<%=path%>/static/js/jquery-1.11.3.js"></script>
<script src="<%=path%>/static/js/angularjs-1.3.9/angular.min.js"></script>
<script src="<%=path%>/static/js/bootstrap-3.3.5/bootstrap.min.js"></script>
<script src="<%=path%>/static/js/bootstrap-3.3.5/fileinput.js"></script>
<script src="<%=path%>/static/js/bootstrap-3.3.5/fileinput_locale_zh.js"></script>
其中fileinput.js和fileinput_locale_zh.js均包含在插件官方包中,angular.min.js和bootstrap.min.js为常规依赖,此处不再赘述。
多文件上传实现
二、多文件上传实现
首先在页面中定义文件控件:
<input id="input-images" type="file" multiple class="file-loading" accept="image/*">
随后对该控件进行初始化,即可实现多文件上传功能:
$("#input-images").fileinput({
uploadUrl: "<%=path%>" + "/album/pictureFileUpload",
allowedFileExtensions: ["jpg", "png", "gif"],
resizePreference: 'height',
maxFileCount: 10,
language: 'zh',
overwriteInitial: false,
resizeImage: true,
});
初始化时包含诸多属性,此处不一一列举。后台代码(使用JFinal框架)如下:
public void pictureFileUpload() {
UploadFile uploadFile = getFile();
renderJson("{\"link\":" + "\"/fileinput/upload/" + uploadFile.getFileName()
+ "\"" + ",\"fileName\":\"" + uploadFile.getOriginalFileName()
+ "\"}");
}
注意:后端必须返回Json格式数据,即使为空JSON串(“{}”)也可。该返回值将保存在前台的data.response中。
已有文件的加载与删除
三、已有文件的加载与删除
已有文件的加载旨在展示服务器上已存在的文件,以实现文件管理并提供删除功能,这主要依赖于initialPreview属性。
获取服务器上的文件名称和地址后,使用initialPreview和initialPreviewConfig完成加载及删除操作的定义:
var initPreview = new Array();//展示元素
var initPreviewConfig = new Array();//展示设置
$.post(
"<%=path%>" + "/album/getPicsByAlbum",
{albumId : albumId},
function(result) {
for(var i=0;i<result.length;i++){
var pictureFile = result[i];
//用于展示已经上传的图片
initPreview.push("<img src='" + pictureFile.PICADDRESS
+ "' class='file-preview-image' alt='"+pictureFile.PICNAME+"' title='"+pictureFile.PICNAME+"'>");
var config = new Object();
config.caption = pictureFile.PICNAME;
config.url="<%=path%>" + "/album/deletePicById";
config.key=pictureFile.ID;
initPreviewConfig.push(config);
}
initFileInput($scope);
$("#input-images").fileinput('refresh', {
initialPreview: initPreview,
initialPreviewConfig: initPreviewConfig
});
}
);
点击删除图标时,默认会将config中的key值传递至后台,后台需定义deletePicById方法进行处理:
public void deletePicById() {
String picId = getPara("key");
service.deletePicById(Integer.valueOf(picId));
renderJson("{}");
}
关键问题解答
四、几点疑问的解答
1、为什么model里没有属性,却可以在前端展示相关属性? 这里主要使用了JFinal的ActiveRecord功能,无需定义属性和setter、getter方法,属性值被映射在model里的attrs中,该属性是<key, value>的键值对,key即为数据库字段名。特别提醒:虽然SQL语句不区分大小写,但字段名存在大小写敏感。若字段名为大写,映射到model里的key也将是大写。同时,JFinal默认的主键策略可能失效,需在configPlugin中设置,例如:arp.addMapping("pictures", "ID", Picture.class)。建议大家遵循Java命名规范命名数据库字段。
2、(参考代码)中初始化FileInput时为何要执行clear、destroy操作?
因为FileInput插件在选择文件后,无论是否上传,都会保留文件在file域中。再次点击时会显示上一次选择的文件,这不符合多相册管理的需求。原本以为clear操作即可清空file域(官方文档如此说明),但实际操作发现并未生效,因此才调用clear、destroy后再重新初始化文件上传控件。(这一点尚存疑,希望有大神指点。)
3、保存时如何知道哪些图片需要存入数据库?这是基于什么实现的?
$scope上有一个selectedPics数组,该属性负责保存最终需存入数据库的文件。文件选择后,选择的信息会保存至该数组,但hasUpload属性为false;文件上传后,对应的hasUpload会被修改为true;上传成功后执行删除(尚未保存至数据库)会从数组中移除对应元素。有人可能会问:若选择文件后不上传直接删除,文件信息是否会占用数据位置从而导致元素错乱?其实并不会。在fileuploaded事件中,哪些图片已hasUpload,是直接修改数组对应位置元素的值。数组坐标通过图片所在DIV的data-fileindex属性值获得,该值会一直递增,不会替补空缺值,也不会因删除图片而变动,正好与selectedPics数组相对应。 var idx = $("#"+previewId).attr("data-fileindex"); 例如,我选择了3张图片,此时未上传,它们依次对应的data-fileindex为0、1、2。当我删除中间那张图片并重新选择新图片时,它们的data-fileindex将变为0、2、3。
五、代码参考 本人初学AngularJS,代码编写尚不够纯熟,如有不妥之处,欢迎大家留言指正。示例代码见文章末尾,数据库脚本为files.sql(MySQL),请大家多参考代码。
源码下载:http://xiazai.jb51.net/201611/yuanma/BSfileinput(jb51.net).rar
如果大家还想深入学习,可以点击这里进行学习,再为大家附两个精彩的专题:Bootstrap学习教程 Bootstrap实战教程
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。