• bootstrap fileinput 使用记录


    第一次使用bootstrap fileinput碰到了许多坑,做下记录

    需求

    1. 本次使用bootstrap fileinput文件上传组件,主要用来上传和预览图片。作为一个后台管理功能,为某个表的某个字段,设置1对n的图片记录
    2. 网上搜索相关文章大多是一个简单的上传功能,对图片文件预览显示,前后端交互并没多少详细描述

    实现功能

    1. 后台界面例子


    2. 在新增和编辑里,需要添加图片上传显示需求,在这里我设置的字段名以_img结尾的图片都会在编辑新增里显示bootstrap fileinput组件


    3. 点击选择,选择文件后会变成一下情况

    多出个上传按钮,图片也会多几个按钮,我选择了删除和放大图片的按钮,还可以显示图片单独上传按钮,这里我把它去掉了,统一在下方点击上传时,全部上传。这里重点说下,我选择的异步上传方式,选择多个图片,上传后台组件采用的是多个图片轮询一张一张上传
    4. 点击放大按钮

    5. 点击删除按钮,会调用删除方法,点击上传按钮,显示如下:

    6. 若本来就保存了图片,在点击修改的时候,我需要回显图片,显示如下

    在没有继续上传图片的时候,它不会显示上传按钮,图片左下角小图标会有所变化
    7. 点击保存后

    8. 以上为需要实现的具体需求,下面分析代码

    问题和解决方案

    前端

    1. 此处只列出关键代码
      html:
    <#elseif modifyField["field_name"]?ends_with("_img")?string == "true">
        <div class="form-group">
            <label class="control-label">${modifyField["field_description"]}:</label>
            <!-- 用来作为form表单提交上传图片返回id的集合,这里我采用`,`隔开的字符串形式保存 -->
            <input type="text" hidden id="${modifyField["field_name"]}" name="${modifyField["field_name"]}" value=""/>
            <!-- 用来初始化上传组件 -->
            <input type="file" name="file" id="${modifyField["field_name"]}_uploadfile" multiple="multiple" class="file-loading" />
        </div>
    <#else>
    

    js:

    /**
     * 销毁图片上传组件
     * @param initUrl
     */
    function destroyUploadImg(){
        //这里我用jquery找到我约定的上传组件,使用_uploadfile结尾,并遍历销毁
        $("#dlg input[id$='_uploadfile']").each(function(index,html){
            var upfile = $(html);
            upfile.fileinput("destroy");
        });
    }
    
    /**
     * 初始化fileinput组件
     */
    var getFileInput = function(){
        //初始化方法,同样找到约定组件遍历
        $("#dlg input[id$='_uploadfile']").each(function(index,html){
            var upfile = $(html);
    
            var imgId = upfile.attr("id").substring(0,upfile.attr("id").lastIndexOf("_"))
            var val = $("#"+imgId).val();
            var preImageList = val.split(",");
    
            var initialPreview = [];
            var initialPreviewConfig = [];
            for (var i = 0; i < preImageList.length; i++) {
                if(preImageList[i] === "") {
                    preImageList.splice(i,1);
                    continue
                }
                initialPreview.push("${request.contextPath}/showPic?image_id=" + preImageList[i] + "&count=" + Math.random())
    
                var previewConfig = new Object();
                previewConfig.url = "${request.contextPath}/deleteImg.do";
                previewConfig.key = preImageList[i];
    
                var imageId = preImageList[i];
                previewConfig.extra = {"image_id": imageId,"pRow":JSON.stringify(pRow),"currPageId":${curr_page_id},"updateCol":imgId};//上传的额外参数,会作为post请求参数提交
                initialPreviewConfig.push(previewConfig);
            }
            if(upfile.length > 0) {
                //元素存在时执行的代码
                upfile.fileinput({
                    theme: 'fa',
                    allowedFileExtensions: ['jpg', 'png', 'gif'],//接收的文件后缀
                    //        maxFileSize:0,
                    language: 'zh', //设置语言
                    uploadUrl: "${request.contextPath}/uploadImg.do", //上传的地址
                    uploadAsync: true, //默认异步上传
                    uploadExtraData:{"currPageId":${curr_page_id},"pRow":JSON.stringify(pRow),"colName":imgId},//上传额外的post请求参数
    //                showUpload: false, //是否显示上传按钮
                    showRemove : false, //显示移除按钮
                    showPreview : true, //是否显示预览
                    showCaption: false,//是否显示标题
                    browseClass: "btn btn-primary", //按钮样式
                    dropZoneEnabled: true,//是否显示拖拽区域
                    maxFileCount: 10, //表示允许同时上传的最大文件个数
                    enctype: 'multipart/form-data',
                    validateInitialCount:true,
                    overwriteInitial: false,//是否在上传下一个文件的时候覆盖前一个
                    initialPreviewAsData: true,//实现初始化预览
                    removeFromPreviewOnError:true,//碰到上传错误的文件,不显示在框内
                    layoutTemplates:{
                        actionUpload:''    //设置为空可去掉上传按钮
                        //actionDelete:''  //设置为空可去掉删除按钮
                    },
                    initialPreview: initialPreview,//初始化预览文件的地址集合
                    initialPreviewConfig:initialPreviewConfig//初始化预览文件配置
                }).on('filepreupload', function(event, data, previewId, index) {     //上传中
                    var form = data.form, files = data.files, extra = data.extra,
                            response = data.response, reader = data.reader;
                    console.log('文件正在上传');
                }).on("fileuploaded", function (event, data, previewId, index) {    //一个文件上传成功
                    console.log('文件上传成功!');
                    if(data.response['result'] === "success"){
                        var imageId = data.response['imageId'];
                        preImageList.push(imageId);
                        var preImageStr = preImageList.join(",");
                        $("#"+imgId).val(preImageStr);
                    }else{
                        return false;
                    }
                }).on('fileerror', function(event, data, msg) {  //一个文件上传失败
                    console.log('文件上传失败!');
                }).on('filesuccessremove', function(event, id) {
                    console.log('文件删除');
                }).on('filedeleteerror', function(event, id) {
                    console.log('文件删除错误');
                }).on('filedeleted', function(event, key,data) {
                    //删除返回结果
                    $("#"+imgId).val(data.responseJSON["imageIdStr"]);
                    $('#dg').datagrid('reload');
                });
            }
        });
    };
    

    明白怎么回事,使用起来还是蛮简单的,就简单的两个创建和销毁方法,注释写的也蛮详细了,除了业务逻辑,组件的必要注释都在了
    2. 重点的地方
    - 文件上传只要填写上传地址和额外参数
    - 在fileuploaded方法中做上传完毕的业务逻辑
    - 文件删除只需要在预览配置里加上删除的地址和额外参数,新增的不管有没有上传的文件,删除的仅仅是前端
    - 在filedeleted方法中做删除完毕的业务逻辑

    后端

    1. 先上代码段
     /**
     * 显示图片
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping(value = {"/showPic.do", "showPic"})
    public ResponseEntity<byte[]> showPic(HttpServletRequest request) throws Exception {
        HashMap<String, Object> hashMap = this.getHashMap(request);
        String imageId = (String) hashMap.get("image_id");
        Map<String, Object> imgConditions = new HashMap<>();
        imgConditions.put("image_id", imageId);
        Map<String, Object> imgInfo = tableService.getRecord(Arrays.asList("image_path", "uuid", "image_type"), TableConstant.TB_IMG, imgConditions);
        String imageType = (String) imgInfo.get("image_type");
        String fullPath = imgInfo.get("image_path") + (String) imgInfo.get("uuid") + "." + imageType;
    
        FileInputStream inputStream = new FileInputStream(fullPath);
        int available = inputStream.available();
        byte[] data = new byte[available];
        inputStream.read(data);
        inputStream.close();
        HttpHeaders he = new HttpHeaders();
        he.setContentType(MediaType.valueOf("image/" + imageType));
        log.info("imageId:" + imageId + "读取");
        return new ResponseEntity<>(data, he, HttpStatus.OK);
    }
    
    
    /**
     * 上传图片
     * @param file
     * @return
     */
    @RequestMapping(value = "/uploadImg.do")
    public @ResponseBody
    Map<String, Object> upload(HttpServletRequest request,@RequestParam("file") MultipartFile file) {
        HashMap<String, Object> hashMap = this.getHashMap(request);
        String originalFilename = file.getOriginalFilename();
        Map<String, Object> pRowMap = JSON.parseObject(hashMap.get("pRow").toString(), Map.class);
        String colName = (String) hashMap.get("colName");
        Map<String, Object> result = new HashMap<>();
        result.put("result", "fail");
        if (StringUtils.isNotEmpty(originalFilename)) {
            String[] splitFileName = originalFilename.split("\.");
            String uuid = UUIDUtil.getUUID();
            Map<String, Object> rowMap = new HashMap<>();
    
            if (!StringUtils.isEmpty(originalFilename)) {
                splitFileName = originalFilename.split("\.");
                String refPageId = (String) hashMap.get("currPageId");
                Map<String, Object> pageCondition2 = new HashMap<>();
                pageCondition2.put("page_id", refPageId);
                pageCondition2.put("del_flag", 0);
                Map<String, Object> refPageInfo = tableService.getRecord(Arrays.asList("tb_name", "primary_key"), TableConstant.TB_PAGE, pageCondition2);
    
                String tbName = (String) refPageInfo.get("tb_name");
                String[] tbNameSpl = tbName.split("_");
                String middlePath = tbNameSpl[tbNameSpl.length - 1];
                String filePath = sysconfig.getProperties().get("image.path") +
                        "/" + middlePath +
                        "/" + DateUtil.format2str("yyyyMMdd") +
                        "/";
                rowMap.put("image_type", splitFileName[splitFileName.length - 1]);
                rowMap.put("image_path", filePath);
                rowMap.put("uuid", uuid);
                rowMap.put("image_name", originalFilename);
                rowMap.put("page_id", refPageId);
                Long incr = redisService.incr(sysconfig.getProperties().get("sys.id") + "_primary_key_" + refPageInfo.get("tb_name") + "_" + refPageInfo.get("primary_key"), 1);
                rowMap.put("image_id", incr);
                rowMap.put("col_name", colName);
    
                String primaryKey = (String) refPageInfo.get("primary_key");
                String pk = String.valueOf(pRowMap.get(primaryKey));
                rowMap.put("ref_value", pk);
                int ret = 0;
                try {
    
                    ret = tableService.addRecord(TableConstant.TB_IMG, rowMap);
                } catch (Exception e) {
                    String message = e.getMessage();
                    if (message.contains("Duplicate entry")) {
                        log.info("主键冲突,redis刷新主键");
                        List<Map<String, Object>> recordsBySQL = tableService.getRecordsBySQL(String.format("select %s from %s order by %s desc limit 1", "image_id", TableConstant.TB_IMG, "image_id"));
                        for (Map<String, Object> objectMap : recordsBySQL) {
                            redisService.set(sysconfig.getProperties().get("sys.id") + "_primary_key_" + TableConstant.TB_IMG + "_" + "image_id", String.valueOf(Integer.parseInt(objectMap.get("image_id").toString())));
                        }
                        incr = redisService.incr(sysconfig.getProperties().get("sys.id") + "_primary_key_" + TableConstant.TB_IMG + "_" + "image_id", 1);
                        rowMap.put("image_id", incr);
                        ret = tableService.addRecord(TableConstant.TB_IMG, rowMap);
                    }
                }
    
                if (ret > 0) {
                    log.info(String.format("插入图片记录imageId:%s成功", incr));
                    try {
                        boolean b = FileUtil.uploadFile(file.getBytes(), filePath, uuid + "." + splitFileName[1]);
                        if (b) {
                            log.info(String.format("插入图片imageId:%s成功", incr));
                            result.put("result", "success");
                            result.put("imageId", incr);
                        } else {
                            log.info(String.format("插入图片imageId:%s失败", incr));
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    log.info(String.format("插入图片记录imageId:%s失败", incr));
                }
            }
    
            return result;
        }
    
        return result;
    }
    
    
    /**
     * 图片删除
     */
    @RequestMapping(value = "deleteImg.do")
    @ResponseBody
    public Map<String, Object> deleteImg(HttpServletRequest request) {
        Map<String, Object> data = new HashMap<>();
        HashMap<String, Object> hashMap = this.getHashMap(request);
        String imageId = (String) hashMap.get("image_id");
        String pageId = (String) hashMap.get("currPageId");
        String updateCol = (String) hashMap.get("updateCol");
        Map<String, Object> pRowMap = JSON.parseObject(hashMap.get("pRow").toString(), Map.class);
    
        List<Map<String, Object>> records = tableService.getRecordsBySQL(String.format("select image_id,image_path,uuid,image_type from t_uls_image where image_id=%s", imageId));
        String imageIdStr = "";
        for (Map<String, Object> record : records) {
            String imagePath = (String) record.get("image_path");
            String uuid = (String) record.get("uuid");
            String imageType = (String) record.get("image_type");
            String path = imagePath + "/" + uuid + "." + imageType;
            File file = new File(path);
            if (file.exists()) {
                boolean delete = file.delete();
                if (delete) {
                    log.info(String.format("图片imageId:%s删除成功", imageId));
    
                    // 查找哪张表
                    Map<String, Object> tableCondition = new HashMap<>();
                    tableCondition.put("page_id", pageId);
                    Map<String, Object> pageInfo = tableService.getRecord(Arrays.asList("tb_name", "primary_key"), TableConstant.TB_PAGE, tableCondition);
    
                    String tbName = (String) pageInfo.get("tb_name");
                    String primaryKey = (String) pageInfo.get("primary_key");
                    String pk = String.valueOf(pRowMap.get(primaryKey));
                    List<Map<String, Object>> recordsBySQL = tableService.getRecordsBySQL(String.format("select %s from %s where %s='%s'", updateCol, tbName, primaryKey, pk));
                    for (Map<String, Object> objectMap : recordsBySQL) {
                        String o = String.valueOf(objectMap.get(updateCol));
                        String[] split = o.split(",");
                        List<String> strings = new ArrayList<>(Arrays.asList(split));
                        if(strings.contains(imageId)){
                            strings.remove(imageId);
                        }
                        imageIdStr = StringUtils.join(strings, ",");
                    }
                    tableService.updateRecordsBySQL(String.format("update %s set %s='%s' where %s='%s'", tbName, updateCol, imageIdStr, primaryKey, pk));
                } else {
                    log.info(String.format("图片imageId:%s删除失败", imageId));
                }
            }
        }
        data.put("data", "success");
        data.put("imageIdStr", imageIdStr);
        return data;
    }
    
    1. 后端和代码架构相关了,大致参考下,遇到的问题有
      • 已上传的图片有多张的情况,显示不正确,也就是同时请求后端显示图片的时候可能报各种异常,包括不知道哪来的NULLPointException
      • 之后发现,还是代码架构的问题,继承类把HttpServletRequest request封装成了全局变量,并从中取出了hashmap参数封装。导致在并发的时候,hashmap被覆盖
    2. 后端主要为框架设计的逻辑,和业务结合,根据实际情况编写,主要三大块,上传,读取,删除,问题不大

    注意事项

    1. 上传和删除操作,后端返回的一定要是json数据,否则会解析错误,就算后台上传成功,前台也显示失败

    参考API http://plugins.krajee.com/file-input

    补充

    1. 后续需要实现上传图片后没提交表单,立即删除。组件只提供了删除回调函数。但我需要将上传文件绑定删除地址以便调用后台删除方法
    2. 参考
  • 相关阅读:
    DB-MySQL:MySQL 函数
    DB-MySQL:目录
    文学-人物:王阳明
    院校:伦敦大学学院
    文学-人物:曹操
    文学-人物:诸葛亮
    x2go
    PHP+jQuery 注册模块开发
    java中Runtime类详细介绍
    java中Runtime类详细介绍
  • 原文地址:https://www.cnblogs.com/sky-chen/p/9563727.html
Copyright © 2020-2023  润新知