bootstrap File Input 多文件上传插件使用记录(二)删除原文件

在上一篇文章中,主要介绍了file input插件的初始化和多文件同步上传到服务器的相关配置等。这篇主要介绍file input插件的编辑等。

使用场景:

在后台管理框架中,一条数据中包含不固定的多张图片属性,然后需要同其他数据一起做增删改查。多文件同时新增上一篇已经做过了,需要的请点击打开链接,但是编辑的时候,就需要吧原来上传的图片展示出来,然后可以进行删除和重新上传,,这就是我现在要做的功能。


直接上代码吧。。

1.HTML

[html] view plain copy
  1. <form>  
  2.      .......//其他数据  
  3.      <div class="form-group" style="width:99%">  
  4.          <input id="update_bachPic" name="commoPicArr" type="file" multiple >  
  5.      </div>  
  6. </form>  

2.JS代码 当点击数据的编辑按钮,则通过后台返回的数据初始化编辑页面,并初始化文件上传插件。

[javascript] view plain copy
  1. $("#update_bachPic").fileinput({  
  2.         language: 'zh',                                        //语言  
  3.         uploadUrl:'<%=basePath%>/commodity/addCommodityPic',   //上传地址  
  4.         showPreview: true,              //展前预览  
  5.         showUpload: false,              //显示上传按钮  
  6.         showCaption: false,             //显示文字表述  
  7.         uploadAsync:false,                             //false 同步上传,后台用数组接收,true 异步上传,每次上传一个file,会调用多次接口  
  8.         removeFromPreviewOnError:true//当选择的文件不符合规则时,例如不是指定后缀文件、大小超出配置等,选择的文件不会出现在预览框中,只会显示错误信息  
  9.         maxFileCount: 5,  
  10.         maxFileSize: 1024*10,           //单位为kb,如果为0表示不限制文件大小  
  11.         allowedFileExtensions: ["jpg""jpeg""gif""png","bmp"],  
  12.                                   
  13.         previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",  
  14.         overwriteInitial: false,  
  15.         initialPreviewAsData: true,  
  16.         initialPreview: [        //这里配置需要初始展示的图片连接数组,字符串类型的,通常是通过后台获取后然后组装成数组直接赋给initialPreview就行了  
  17.                         "http://......img",  
  18.                         "http://......img",  
  19.                         ],  
  20.         initialPreviewConfig: [ //配置预览中的一些参数   
  21.                                 {caption: "transport-1.jpg", size: 329892, width: "120px", url: "deletePic", key: 1},  
  22.                                 {caption: "transport-2.jpg", size: 872378, width: "120px", url: "deletePic", key: 2}  
  23.                               ]  
  24.         }).on('filepredelete'function(event, key, jqXHR, data) {  
  25.                     console.log('Key = ' + key);  
  26.                     console.log(jqXHR);  
  27.                     console.log(data);   
  28.         });  
注意:
配置initialPreview:[ ] 配置的是数组,也就是需要初始展示图片的地址数组,字符串类型,当然通常是通过ajax从后台获取到链接后再组装成数组直接赋给他就行了。
配置initialPreviewConfig:[ ]也是一个数组,他主要是配置预览图片的相关显示参数,名字啊、大小啊。但是最重要的配置是url,他是你在点击图中的删除按钮后,会调用的地址,然后通过ajax去后台删除原图片。配置key,表示删除的时候向后台传递的参数,看图:

       很神奇,你会发现,在url中我只配置了deletePic,但是通过调试发现,删除请求的url竟然自动拼接了前面的一段url,我猜测可能是从上面的配置updateUrl而来,或者是从请求头中的Referer而来。

        配置的key是请求传递的参数,实测发现名字key不能改成自己的其他名字,而且传递的值不能是对象,这就有个问题了,万一我想传多个值怎么办?那就自己动手丰衣足食,改造源码吧。。


 3.更改fileinput.js源码

  需求一:将key传递的参数改为: key: "{'id':'1','name':'name1'}"
  注意:既然直接传递对象不行,那就传递json字符串吧,然后在源码中转换成json不就行了?


       更改源码中2379行左右,当点击删除按钮时,会调用settings,里面就是已经配置好的参数,我们获取key值,然后将单引号替换成双引号,然后转换为json对象,替换data参数。

       这里为什么要替换单引号为双引号,为什么不直接在key配置的时候就写双引号呢?别问,我试了,不行,转换会出错,要不就是传递不过来,不然我也不会使用这个多此一举的办法啊。。。你直接传递json字符串到后台,用后台代码解析为json也可以。。然后我们的调试请求发现传递的值就变成我们想要的了。。


       好,传值的问题解决了。就可以点击按钮的时候去后台删除此图片了,并传递我们其他的参数。新选择的图片并不会调用后台方法,会直接删除的。


  需求二:当用户点击删除按钮的时候,提示他这是原图片,并问他是否确认删除,确认后才去后台调用删除,取消则不删除。这是为了避免用户点错,而导致删除了原图片,那么久需要在后台调用ajax之前执行一段我们的提示代码。

 解决:查看API,发现了这么几个事件可以调用。
    $('#input-id').on('filepreremove', function(event, id, index) {       //只是你删除重新选择的图片才会触发,而删除原图片不会触发。
       console.log('id = ' + id + ', index = ' + index);
    });


   $('#input-id').on('filepredelete', function(event, key, jqXHR, data) {  //就是在删除原图片之前触发,而新选择的图片不会触发。能满足我们的要求。
      console.log('Key = ' + key);
   });


  解决一:

    采用filepredelete时间监听,在删除之前询问用户是否确定,并在确定后执行后面的。如果采用一般bootstrap的询问框,都是采用回调的方式监听用户操作的,还没等回调结束,后面的代码就已经开始调用ajax执行删除了。所以需要一个js线程的暂停机制,类似于alert,当用户操作后再往下执行,原始的js confirm()方法可以实现询问,然后点击确定则继续执行,所以代码改为:

[javascript] view plain copy
  1. $("#update_bachPic").fileinput({  
  2.         language: 'zh',  
  3.         uploadUrl:'<%=basePath%>/commodity/addCommodityPic',  
  4.         showPreview: true,              //展前预览  
  5.         showUpload: false,              //显示上传按钮  
  6.         showCaption: false,             //显示文字表述  
  7.         uploadAsync:false,  
  8.         removeFromPreviewOnError:true,  
  9.         maxFileCount: 5,  
  10.         maxFileSize: 1024*10,           //单位为kb,如果为0表示不限制文件大小  
  11.         allowedFileExtensions: ["jpg""jpeg""gif""png","bmp"],  
  12.         previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",  
  13.         overwriteInitial: false,  
  14.         initialPreviewAsData: true,  
  15.         initialPreview: urlArr,  
  16.         initialPreviewConfig: [  
  17.                             {caption: "transport-1.jpg", size: 329892, width: "120px", url: "deletePic", key: "{'id':'1','name':'name1'}"},  
  18.                             {caption: "transport-2.jpg", size: 872378, width: "120px", url: "deletePic", key: "{'id':'1','name':'name1'}"},  
  19.                             ]  
  20.         }).on('filepredelete'function(event, key, jqXHR, data) {  
  21.                 if(!confirm("确定删除原文件?删除后不可恢复")){  
  22.                     return false;  
  23.                 }  
  24.         });  
当用户点击取消,则返回false,到源码中去阻止事件的继续执行。


在源码2323行左右,执行ajax方法中beforSend,我们在filepredelete中返回false,返回false则再return给beforSend,他就会停止执行ajax方法,从而达到我们的目的。

这种方法确实能实现我们的要求,但是使用原始的confirm难免有些难看,也不符合整个系统的UI。但是使用bootstrap其他的询问框,则没办法实现线程暂停机制。但是我们可以在他执行ajax之前去判断,从而阻止执行。

 解决二:

  更改源码2379行左右,当点击删除按钮时,调用$.ajax(setting)方法之前采用其他bootstrap询问插件来监听,当然你也可以把他封装成一个内部事件,在初始化fileinput的时候去监听,




好了,这就是一些简单的删除原文件的方法,其中不乏需要我们去更改源码来符合我们的需求。后面使用中还遇到什么问题,再来研究吧。

















功能相关代码:

[javascript] view plain copy
  1. $("#inputfile").fileinput({  
  2.         language: 'zh'//设置语言  
  3.         uploadUrl: "{:U('localhost/learnFileUpload')}"//上传的地址  
  4.         allowedFileExtensions : ['jpg''png','gif''jpeg'],//接收的文件后缀  
  5.         initialPreview: [  
  6.                  "<img src='__ROOT__"+imagePath+"' class='file-preview-image'>"  
  7.              ],  
  8.         showUpload: false//是否显示上传按钮  
  9.         showRemove:false// 是否显示移除按钮  
  10.         showCaption: false,//是否显示标题  
  11.         showPreview: true,// 是否预展示图片  
  12.         maxFileCount:1,//上传图片最大数量  
  13.         maxImageHeight:67,// 上传图片最大高度  
  14.         initialPreviewConfig: [{  
  15.                caption: 'desert.jpg',// 展示的图片名称  
  16.                width: '120px',// 图片高度  
  17.                url: '{:U('localhost/delete')}',// 预展示图片的删除调取路径  
  18.                key: 100,// 可修改 场景2中会用的  
  19.                extra: {id: 100} //调用删除路径所传参数   
  20.            }],  
  21.         enctype: 'multipart/form-data',// 上传图片的设置  
  22.         browseClass: "btn btn-primary"//按钮样式  
  23.         uploadExtraData:{},上传路径的参数  
  24.         previewFileIcon: "<i class='glyphicon glyphicon-king'></i>"// 按钮样式  
  25.     }).on('fileuploaded'function(event, data, id, index) { // 上传按钮的回调事件  
  26. if (data.response.result == 3) {  
  27.                 window.parent.location.href = "{:U('Login/disp')}";  
  28. else {  
  29.          $("#img_path").val(data.response.fileMsg);  
  30.     $('#content').html(data.response.content);  
  31. }  
  32. });  


场景1:新增图片,并上传之后的删除

[javascript] view plain copy
  1. $('#input-id').on('filesuccessremove'function(event, id) {  
  2.     if (some_processing_function(id)) {  
  3.        console.log('Uploaded thumbnail successfully removed');  
  4.     } else {  
  5.         return false;   
  6.     }  
  7. });  
其中:input-id为页面设定的input标签的ID

filesuccessremove 为对应的名称

此方法内可以写具体删除过程中的相关操作


场景2: 存在默认图片,页面加载完之后的删除



这个删除有是有对应的方法的:

方法1:删除预处理(删除之前想要做什么事)

[javascript] view plain copy
  1. $('#input-id').on('filepredelete'function(event, key) {  
  2.     console.log('Key = ' + key);  
  3. });  
方法2:删除后的处理(删除图片时想要做什么事)

[javascript] view plain copy
  1. $('#input-id').on('filedeleted'function(event, key) {  
  2.     console.log('Key = ' + key);  
  3. });  

对于那些未上传的图片删除功能应该没有什么特别想做的事情,因为他不会影响到系统上任何东西,个人也就没有特别研究


另外,目前发现一个问题,有预设图片显示在插件中,当选择新图片时,会把之前的预设图片删除掉,这个问题暂时没有具体研究

等有结果或者哪位知情博友有解决方案,欢迎一起分享。











转自 http://www.jb51.net/article/91962.htm

1. 页面部分代码:

?
1
2
3
4
5
6
7
<div class= "form-group" >
<label for = "inputEmail3" class= "col-xs-3 control-label" >项目LOGO</label>
<div class= "col-xs-7" >
<input id= "testlogo" type= "file" name= "icoFile" class= "file-loading" />
<input type= "text" name= "htestlogo" id= "htestlogo" onchange= "addFile(this)" >
</div>
</div>

说明: 其中onchange()为我业务需要, 上传完成后自动执行一个添加事件。 此方法可以去掉。

2. 获取初始化数据方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 初始化获取原有文件
$( function (){
$.ajax({
type : "post" ,
url : "/eim/project/testFileUpload.do" ,
dataType : "json" ,
success : function (data) {
layer.msg( '操作成功!' );
showPhotos(data);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
layer.msg( '操作失败!' );
}
});
});

说明:此处我返回是一个 对象数组:List<MemberUser>,可以理解为获取一个班中所有的学生,展示头像

3.初始化bootstrap-fileinput 组件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
function showPhotos(djson){
//后台返回json字符串转换为json对象
var reData = eval(djson);
// 预览图片json数据组
var preList = new Array();
for ( var i = 0; i < reData.length; i++) {
var array_element = reData[i];
// 此处指针对.txt判断,其余自行添加
if (array_element.fileIdFile.name.indexOf( "txt" )>0){
// 非图片类型的展示
preList[i]= "<div class='file-preview-other-frame'><div class='file-preview-other'><span class='file-icon-4x'><i class='fa fa-file-text-o text-info'></i></span></div></div>"
} else {
// 图片类型
preList[i]= "<img src=\"/eim/upload/getIMG.do?savePath=" +array_element.fileIdFile.filePath+ "&name=" +array_element.fileIdFile.name+ "\" class=\"file-preview-image\">" ;
}
}
var previewJson = preList;
// 与上面 预览图片json数据组 对应的config数据
var preConfigList = new Array();
for ( var i = 0; i < reData.length; i++) {
var array_element = reData[i];
var tjson = {caption: array_element.fileIdFile.fileName, // 展示的文件名
width: '120px' ,
url: '/eim/project/deleteFile.do' , // 删除url
key: array_element.id, // 删除是Ajax向后台传递的参数
extra: {id: 100}
};
preConfigList[i] = tjson;
}
// 具体参数自行查询
$( '#testlogo' ).fileinput({
uploadUrl: '/eim/upload/uploadFile.do' ,
uploadAsync: true ,
showCaption: true ,
showUpload: true , //是否显示上传按钮
showRemove: false , //是否显示删除按钮
showCaption: true , //是否显示输入框
showPreview: true ,
showCancel: true ,
dropZoneEnabled: false ,
maxFileCount: 10,
initialPreviewShowDelete: true ,
msgFilesTooMany: "选择上传的文件数量 超过允许的最大数值!" ,
initialPreview: previewJson,
previewFileIcon: '<i class="fa fa-file"></i>' ,
allowedPreviewTypes: [ 'image' ],
previewFileIconSettings: {
'docx' : '<i class="fa fa-file-word-o text-primary"></i>' ,
'xlsx' : '<i class="fa fa-file-excel-o text-success"></i>' ,
'pptx' : '<i class="fa fa-file-powerpoint-o text-danger"></i>' ,
'pdf' : '<i class="fa fa-file-pdf-o text-danger"></i>' ,
'zip' : '<i class="fa fa-file-archive-o text-muted"></i>' ,
'sql' : '<i class="fa fa-file-word-o text-primary"></i>' ,
},
initialPreviewConfig: preConfigList
}).off( 'filepreupload' ).on( 'filepreupload' , function () {
// alert(data.url);
}).on( "fileuploaded" , function (event, outData) {
//文件上传成功后返回的数据, 此处我只保存返回文件的id
var result = outData.response.id;
// 对应的input 赋值
$( '#htestlogo' ).val(result).change();
});
}

4. 后台java保存文件部分代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@RequestMapping(value= "/uploadFile" ,method=RequestMethod.POST)
@ResponseBody
public Object uploadFile(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//转型为MultipartHttpServletRequest
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)request;
//获取文件到map容器中
Map<String,MultipartFile> fileMap = multipartRequest.getFileMap();
//获取页面传递过来的路径参数
folderPath = request.getParameter( "folder" );
String rootPath = BaseConfig.uploadPath;
String filePath = rootPath + folderPath+ "/" ;
//文件上传并返回map容器,map存储了文件信息
FileModel fileModel = UploadifyUtils.uploadFiles(filePath,fileMap);
boolean flag = service.add(fileModel);
if (flag){
String result = fileModel.getId()+ ";" +fileModel.getFilePath()+ ";" +fileModel.getName()+ ";" +fileModel.getFilePath();
Map map = new HashMap<>();
map.put( "id" , fileModel.getId());
//返回文件保存ID
//response.getWriter().write(map);
return map;
}
return null ;
}

说明:该段代码为获取上传文件的部分信息, 如文件名,上传的路径 等,将文件信息保存到表中,对应对象为 FileModel 。

5.上传完成后重新刷新该组件即可。

最终展示效果 :

说明:此处指针对txt文件类型判断, 其余的doc,ppt里面有对应的展示图标,只须在判断是添加对应样式即可

附:根据路径过去/下载文件代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
* 文件下载
*
* @param savePath
* 保存目录
* @param name
* 文件原名
* @param file
* 保存时的名称 包含后缀
* @param request
* @param response
* @return
*/
public static String down(String savePath, String name, String fileName, HttpServletRequest request,
HttpServletResponse response) {
try {
String path = savePath + "/" + name;
File file = new File(path);
if (!file.exists()) {
// 不存在
request.setAttribute( "name" , fileName);
return "download_error" ; // 返回下载文件不存在
}
response.setContentType( "application/octet-stream" );
// 根据不同浏览器 设置response的Header
String userAgent = request.getHeader( "User-Agent" ).toLowerCase();
if (userAgent.indexOf( "msie" ) != -1) {
// ie浏览器
// System.out.println("ie浏览器");
response.addHeader( "Content-Disposition" , "attachment;filename=" + URLEncoder.encode(name, "utf-8" ));
} else {
response.addHeader( "Content-Disposition" ,
"attachment;filename=" + new String(name.getBytes( "utf-8" ), "ISO8859-1" ));
}
response.addHeader( "Content-Length" , "" + file.length());
// 以流的形式下载文件
InputStream fis = new BufferedInputStream( new FileInputStream(path));
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
//response.setContentType("image/*"); // 设置返回的文件类型
OutputStream toClient = response.getOutputStream();
OutputStream bos = new BufferedOutputStream(toClient);
//BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(bos));
bos.write(buffer);
//bw.close();
bos.close();
toClient.close();
return null ;
} catch (Exception e) {
e.printStackTrace();
//response.reset();
return "exception" ; // 返回异常页面
} finally {
/* if (toClient != null ) {
try {
toClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}*/
}
}

附:

UploadifyUtils.uploadFiles 部分代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static FileModel uploadFiles(String savePath,Map<String,MultipartFile> fiLeMap){
//上传文件
//附件模型对象
FileModel fm= new FileModel();
try {
File file = new File(savePath);
//判断文件夹是否存在,如果不存在则创建文件夹
makeDir(file);
if (fiLeMap!= null ){
for (Map.Entry<String, MultipartFile> entity:fiLeMap.entrySet()){
MultipartFile f = entity.getValue();
if (f!= null &&!f.isEmpty()){
String uuid=UploadifyUtils.getUUID(); //uuid作为保存时的文件名
String ext=UploadifyUtils.getFileExt(f.getOriginalFilename()); //获取文件后缀
//保存文件
File newFile = new File(savePath+ "/" +uuid+ "." +ext);
f.transferTo(newFile);
fm.setFileName(f.getOriginalFilename());
fm.setName(uuid+ "." +ext);
fm.setFilePath(savePath); //保存路径
fm.setExt(ext);
fm.setSize(f.getSize());
}
}
}
return fm;
} catch (Exception e) {
log.error(e);
return null ;
}
}

以上所述是小编给大家介绍的Bootstrap中的fileinput 多图片上传编辑,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

原文链接:http://blog.csdn.net/wuwenjinwuwenjin/article/details/49507595




https://blog.csdn.net/xumoqiu/article/details/53081352?locationNum=1&fps=1















https://ask.csdn.net/questions/354505?sort=id

bootstrap fileinput initialPreviewConfig 中参数问题 50C
var preList = new Array();  
var listImage = selectItem.FImage.split(",");

var listFUrl = selectItem.FUrl;
var previewJson = preList;  
// 与上面 预览图片json数据组 对应的config数据  
  var initPreviewConfig = new Array();  
 for ( var i = 1; i < listImage.length; i++) {
      var urlList = listImage[i].split(":");
      preList[i]= "<img src=\""+listFUrl+urlList[0]+"\" class=\"file-preview-image\">";  

     /* alert(urlList[1]);
      var config = new Object();
      config.caption = urlList[0];
      config.url='deleteAssetsImage.html';
      config.key=urlList[1];
      config.extra = {id: urlList[1]};
      initPreviewConfig.push(config);*/


      var array_element = urlList[0];  
      var tjson = {caption: array_element, // 展示的文件名  
                    width: '120px',   
                    url: 'deleteAssetsImage.html', // 删除url  
                    key: 100, // 删除是Ajax向后台传递的参数  
                    extra: function() { 
                        return {id: urlList[1]};
                    }
                    };  
      initPreviewConfig[i] = tjson;  
     }  
initFileInput("projectfile", "uploadZCImage.html",selectItem.FAssetsRegiId);

  $("#projectfile").fileinput('refresh', {
      initialPreview: preList,
      initialPreviewConfig: initPreviewConfig
  });


        后台 spring 
        @RequestMapping(value = "/deleteAssetsImage.html", method = RequestMethod.DELETE)
public void deleteAssetsImage(HttpServletRequest request,HttpServletResponse response,ModelMap model) {

    response.setCharacterEncoding("UTF-8");
    System.out.println("===========================");
    try {
        //getPara("key");
        boolean result  = false;
        String id = (String) request.getParameter("key");
        String id2 = (String) request.getParameter("id");
           System.out.println(id2+"==========================="+id);
        if(id!=null){
            result= assetsService.deleteAssetsImage(Integer.parseInt(id));

        }

        renderText(response, result);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } 

}

始终获取不到参数,用POST请求会报405请求错误,求解答







Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐