bootStrap+fileinput插件使用:
(坑属实多,可能各种版本之间兼容问题,官方文档给的例
子也是模糊不清的,没有一个完整的Dome,于是在baidu上搜搜搜,也有适用的例子,但也试了很长时间,东拼西凑的才算搞出来了)
一:准备阶段
1、那肯定是要下载fileinput插件了
链接: https://plugins.krajee.com/file-input.
2、要看bootStrap版本和fileinput版本兼容问题,版本不匹配会导致图标和样式出不来
3、插件、js和css样式都引入进来后就开始着手代码部分了。
二:代码部分
新增信息,(也新增图片)
前端引入的js和css文件,(注意顺序,和文档规定的路径,比如:themes,你就必须要创建个themes包)
<link href="${ctxStatic}/bootstrap/bsie/css/fileinput.css" type="text/css" rel="stylesheet" />
<script src="${ctxStatic}/bootstrap/bsie/js/fileinput.js" type="text/javascript"></script>
<script src="${ctxStatic}/bootstrap/bsie/themes/fas/theme.js" type="text/javascript"></script>
<script src="${ctxStatic}/bootstrap/bsie/themes/explorer-fas/theme.js" type="text/javascript"></script>
<script src="${ctxStatic}/bootstrap/bsie/js/locales/zh.js" type="text/javascript"></script>
1、(添加)前台初始化代码片
$("#input-100").fileinput({
<%--uploadUrl: "${ctx}/postmedia/mediainfo/uploadmediafileMore",--%>
enableResumableUpload: true,
uploadExtraData: {
'uploadToken': 'SOME-TOKEN', // for access control / security
},
maxFileCount: 15, //最大上传数量
language: 'zh', //中文语言
allowedFileTypes: ['image'], //Image图片种类
showUpload:false, //是否显示上传按钮,(因为要走同步提交,所以在这里我就关闭)
uploadAsync:false, //false 同步上传,后台用数组接收,true 异步上传,每次上传一个file,会调用多次接口
initialPreviewAsData: true,
overwriteInitial: false,
autoReplace:false, //是否自动替换
theme: 'fas', //主题(我bootStrap版本可能低了,样式有点问题)
deleteUrl: "${ctx}/postmedia/mediainfo/deletemediafile" //(删除路径,其实在新增信息的时候我没用到,因为我把他归类到编辑的时候去删除,不过有一点:没点保存的可以移除)
}).on('fileuploaded', function(event,data,previewId,index) {
imgPath=imgPath+index;
console.log('File Uploaded', 'ID: ' + index + ', Thumb ID: ' + previewId);
console.log(data.response);
}).on('fileuploaderror', function(event, data, msg) {
console.log('File Upload Error', 'ID: ' + data.fileId + ', Thumb ID: ' + data.previewId);
}).on('filebatchuploadcomplete', function(event, data, msg) {
console.log(imgPath,'File Batch Uploaded', data,msg);
});//(走同步,这些压根也没用到)
//这一步也是比较重要的(在提交表单之前,去upload一下文件):
$("#input-100").fileinput("upload");
$("#inputForm").submit();
<!-- fileinput选择框 -->
<div class="row-fluid row-fluid_custom">
<label class="control-label" style="font-size: 15px"></span>上传图片:</label>
<p class="help-block" style="font-weight: bold">支持JPG、JPEG、PNG格式</p>
<input type="file" id="input-100" name="files" accept="image/*" multiple>
</div>
2、(添加)后台代码
。
@RequestMapping(value = {"add"}, method = RequestMethod.POST)
@RequiresPermissions(value = "mediainfo:add")
public String add(TbMediaInfo dto, HttpServletRequest request,@RequestParam MultipartFile[] files, Model model){
if (StringUtils.isNotBlank(files[0].getOriginalFilename())){
if (newId != null && newId != 0) {
AbstractFileUtil fileUtil = FileUploadManager.builder();
TbMediaResource mrDbDto = new TbMediaResource();
MultipartFile[] dtoFiles = files;
String xdPath = null;
String fileName = null;
for (int i = 0; i < dtoFiles.length; i++) {
File fileFb = new File(dtoFiles[i].getOriginalFilename());
String filePath = fileUtil.getPrefixPath(loginuser.getOrg().getDeptCode(), FileUploadContstant.MEDIA_FILE_UPLOAD_PATH, request);
try {
dtoFiles[i].transferTo(fileFb);
xdPath = fileUtil.uploadFile(filePath, fileFb);
} catch (IOException e) {
e.printStackTrace();
addMessage(model, "保存文件失败!");
model.addAttribute("redirectUrl", Global.getAdminPath() + "/postmedia/mediainfo/list");
return super.GLOBAL_ERROR;
}
//TODO:将文件添加到图片内存表中
//拆分文件名
fileName = xdPath.substring(xdPath.lastIndexOf("/")+1);
mrDbDto.setMediaId(Long.valueOf(newId));
mrDbDto.setName(fileName);
mrDbDto.setPath(xdPath);
mrDbDto.setCreateTime(new Date());
mediaresourceService.insert(mrDbDto);
if (i == 0){
dto.setImgName(fileName);
dto.setImgPath(xdPath);
mediainfoService.update(dto);
}
}
}
}
addMessage(model, "资源信息新增成功");
model.addAttribute("redirectUrl", Global.getAdminPath()+"/postmedia/mediainfo/list");
return super.GLOBAL_SUCCESS;
}
//此处只是展示局部代码,主要是看看这个传值,files就是前台的 name = “files”,这里用数组接收即可
编辑信息,(也编辑图片的信息操作)
3、(编辑)前台代码
var imgPath = ${ImgPaths}; //此处是拿到了后台查询到的关于此条信息的相关图片
var path;
let arrayImgPath = new Array; //定义一个数组,因为回显图片需要用数组形式接收
let initialPreviewConfig = new Array; //定义一个给后台传输删除参数的数组
$.each(imgPath, function(i) {
path = "${sctx}/" + imgPath[i]; //在本系统里面,因这里牵扯到一个路径拼接,所以这里要做一个路径的追加
arrayImgPath.push(path);
initialPreviewConfig.push({key:imgPath[i]}); //这里把每个图片信息塞到数组中,(也是个初始化的过程,后面删除图片他会自动去拿数据传给后台,这里还有个属性:extra(额外传输给后台的参数,可随意定义参数名))
});
$("#input-100").fileinput({
uploadUrl: "${ctx}/postmedia/mediainfo/uploadmediafile?cryptId=${cryptId}",//(在编辑信息这里,我采用的是异步,因为同步会有一些业务上的bug,这个id我是要传给后台去保存该条信息的,也就是标识这个图片是属于这个信息里面的)
enableResumableUpload: true,
uploadExtraData: {
'uploadToken': 'SOME-TOKEN', // for access control / security
},
maxFileCount: 15,
language: 'zh',
allowedFileTypes: ['image'], // allow only images
showCancel: true,
showPreview:true,
showUpload:true, //是否显示上传按钮
showRemove:true, //显示移除按钮
uploadAsync:true, //false 同步上传,后台用数组接收,true 异步上传,每次上传一个file,会调用多次接口
initialPreviewAsData: true,
overwriteInitial: false,
theme: 'fas',
autoReplace:false,
initialPreview:arrayImgPath,//接收历史图片,
initialPreviewConfig:initialPreviewConfig,
deleteUrl: "${ctx}/postmedia/mediainfo/deletemediafile"
}).on('fileuploaded', function(event,data,previewId,index) {
imgPath=imgPath+index;
console.log('File Uploaded', 'ID: ' + index + ', Thumb ID: ' + previewId);
console.log(data.response);
}).on('fileuploaderror', function(event, data, msg) {
console.log('File Upload Error', 'ID: ' + data.fileId + ', Thumb ID: ' + data.previewId);
}).on('filebatchuploadcomplete', function(event, data, msg) {
console.log(imgPath,'File Batch Uploaded', data,msg);
}).on('filepredelete', function(event, key, jqXHR, data) {
if(!confirm("确定删除该图片?删除后不可恢复")){
return true;
}
});
4、(编辑)后台代码
//上传文件(媒介资源信息)
@ResponseBody
@RequestMapping(value = { "/uploadmediafile" }, method = { RequestMethod.POST })
public Map<String, String> uploadMediaFile(Model model,String cryptId, HttpServletRequest request) {
WebUserInfo loginuser = UserUtils.getPrincipal();
String mediaId = AesUtils.getInstance().decrypt(loginuser.getUser().getSalt(),cryptId);
// 转型为MultipartHttpRequest(这里取file文件的值要用这个方式来取,可能还有其他方式)
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
if (multipartRequest.getMultiFileMap().size() == 0){
return super.renderJsonError("请选择要上传的文件!");
}
//获取文件(因为走异步上传,即使是选择多张照片去点击上传,它就会重复去调这个方法,所以只取数组中第一个(本来也只有一个))
MultipartFile files = multipartRequest.getMultiFileMap().get("fileBlob").get(0);
//上传文件(根据上传类型传入不同位置)
if (StringUtils.isNotBlank(files.getOriginalFilename())){
AbstractFileUtil fileUtil = FileUploadManager.builder();
TbMediaResource mrDbDto = new TbMediaResource();
String xdPath = null;
String fileName = null;
File fileFb = new File(files.getOriginalFilename());
String filePath = fileUtil.getPrefixPath(loginuser.getOrg().getDeptCode(), FileUploadContstant.MEDIA_FILE_UPLOAD_PATH, request);
try {
files.transferTo(fileFb);
xdPath = fileUtil.uploadFile(filePath, fileFb);
} catch (IOException e) {
e.printStackTrace();
return super.renderJsonError("上传失败!");
}
//TODO:将文件添加到图片内存表中
//拆分文件名
fileName = xdPath.substring(xdPath.lastIndexOf("/")+1);
mrDbDto.setMediaId(Long.valueOf(mediaId));
mrDbDto.setName(fileName);
mrDbDto.setPath(xdPath);
mrDbDto.setCreateTime(new Date());
mediaresourceService.insert(mrDbDto);
return super.renderJsonSuccess("上传成功!");
}
return super.renderJsonError("文件为空!");
}
在这里着重说一下这个request里的值,在网上看有几种接收方式,但都试了无果,在debug调试的时候看到文件存在request里面,那么直接get(“fileBlob”)就能拿到了,还必须按他的这个参数命名来取,所以就有了上述multipartRequest.getMultiFileMap().get(“fileBlob”).get(0);它以数组形式存在的,取也就取第一个。即使多张图片去走异步,它依然是重复掉这个上传方法
5、编辑中删除图片
。
@ResponseBody
@RequestMapping(value = {"/deletemediafile"}, method = {RequestMethod.POST})
public Map<String, String> deleteMediaFile(String key) {
if (StringUtils.isNotBlank(key)) {
mediaresourceService.deleteByName(key.substring(key.lastIndexOf("/") + 1));
return super.renderJsonSuccess("删除成功!");
}
return super.renderJsonSuccess("未找到数据!");
}
注意到:在编辑页面的初始化中这次用到了deleteUrl,这个就是调后台删除的方法,initialPreviewConfig就是给后台传值的,拿到的是点击这张图片时的值,在这里回显的时候我只传了路径,所以也就直接拿它去做后台删除操作了,总之是唯一的。(在此项目中因为上传的时候做了一些封装,给名称会随机添加一些字母数字,所以永远不会重复,其实建议用id)
自此,同步和异步上传的方式大概就是这样子了,因为项目原因,目前bootStrap版本用的还是2.0+版本所以导致和fileinput的版本有些不兼容,样式简陋,害…
附图:
其实上传常用的属性就那几个,多试试就行了,从官方文档来看这个插件还是很成熟的,深入还需多学习,欢迎交流!