微信小程序+springboot+mybatis 前端图片随表单一起上传以及获取服务器图片的方法

小程序前端

初步实现上传图片

任务目标为,在微信小程序前端实现图片上传和预览功能,能单独删除已上传的图片。正常情况下,这一任务需要两步完成。

  1. 设置参数,使用wx.uploadFile向文件服务器/云储存 上传图片;上传成功后服务器返回图片保存的路径/URL
  2. 将返回的路径/URL放入表单中提交
    也就说,每一张图片的添加和删除,都需要调用一次后端接口,给后端的压力较大。现改为前端图片的上传和删除只在前端发生,将需要上传的图片地址保存在前端数组中,“上传”和“删除”变成单纯对字符串数组的操作,在最后上传表单内容时,将存储图片的数组一同上传即可。
data: {
      

    links_type:'',
    cameraList:[],
    imgList: [],//存储图片临时地址
    uploadcurrent: 0,
    uploadImgList: [],//存储图片成功上传后,后端返回的服务器上图片存储位置
    

    },
//关于调用视频和图片
 // 点击添加选择
  chooseSource: function () {
    var _this = this;
    wx.showActionSheet({
      itemList: ["拍照", "从相册中选择"],
      itemColor: "#000000",
      success: function (res) {
        if (!res.cancel) {
          if (res.tapIndex == 0) {
            _this.imgWShow("camera") //拍照
          } else if (res.tapIndex == 1) {
            _this.imgWShow("album") //相册
          }
        }
      }
    })
  },
   
  // 点击调用手机相册/拍照
  imgWShow: function (type) {
    var _this = this;
    let len = 0;
    if (_this.data.imgList != null) {
      len = _this.data.imgList.length
    }
    wx.chooseImage({
      count: 10 - len,
      sizeType: ['original', 'compressed'], 
      sourceType: [type],
      success: function (res) {
        wx.showToast({
          title: '正在上传...',
          icon: "loading",
          mask: true,
          duration: 1000
        })
        var imgList = res.tempFilePaths
        let tempFilePathsImg = _this.data.imgList
        var tempFilePathsImgs = tempFilePathsImg.concat(imgList)
         
           _this.setData({
          imgList: tempFilePathsImgs //将图片的临时地址存储到全局变量imgList中
        })
        //,()=>_this.uploadimagFile() 本来是在这个地方执行上传后端操作的
      },
      fail: function () {
        wx.showToast({
          title: '图片上传失败',
          icon: 'none'
        })
        return;
      }
    })
  },
    // 预览图片
    previewImg: function (e) {
      let index = e.target.dataset.index;
      let _this = this;
      wx.previewImage({
        current: _this.data.imgList[index],
        urls: _this.data.imgList
      })
    },

  /**
   * 点击删除图片 也就是从imglist中删除对应图片临时地址
   */
  deleteImg: function (e) {
    var _this = this;
    var imgList = _this.data.imgList;
    var current=_this.data.uploadcurrent;
    var index = e.currentTarget.dataset.index; //获取当前点击图片下标
    wx.showModal({
      title: '提示',
      content: '确认要删除该图片吗?',
      success: function (res) {
        if (res.confirm) {
          imgList.splice(index, 1);
          current=current-1;
        } else if (res.cancel) {
          return false
        }
        _this.setData({
          imgList,
          uploadcurrent:current
        })
      }
    })
  },
  
// 图片上传服务
 uploadimagFile(){
    const that=this;
    let imgListData = that.data.imgList;
    let current=that.data.uploadcurrent;
    console.log(imgListData)
    for(let i=0;i<imgListData.length;i++){//循环遍历整个imglist,因为uploadFile方法只能一次上传一张图片
      console.log(imgListData[i])
            wx.uploadFile({
              url: getApp().globalData.serverBaseUrl+'/Applets/wechatImg',//后端对应接口
              filePath:imgListData[i],
              name:'image',
              success(res) {
                console.log("返回的信息",res.data.url)
              //let imgPath_url=JSON.parse(res.data).data.path+JSON.parse(res.data).data.img
              let imgPath_url=JSON.parse(res.data).url
              console.log(imgPath_url)
              current=imgListData.length
               that.data.uploadImgList=that.data.uploadImgList.concat(imgPath_url)
               //wx.setStorageSync('imgPath', that.data.uploadImgList)
                console.log(that.data.uploadImgList)
                that.setData({
                  uploadImgList:that.data.uploadImgList,//将后端返回的图片地址存入uploadImgList
               
                  //imgList:'',
                })
                wx.showToast({
                  title: '上传数据成功',
                  icon: 'success',
                  duration: 500,
                  success: function () {
                    // setTimeout(() => {
                    //   wx.navigateBack()
                    // }, 300)
                  }
                })
              },
              fail: function (res) {
                console.log('接口调用失败');
                console.log(res);
              }
            })
    }
  },



/**
   * 上传表单的方法的部分代码
   */
        console.log('form发生了submit事件,携带数据为:', e.detail.value);
        var that=this;
        var shoptoken=that.data.token;
        console.log(shoptoken);
        this.uploadimagFile();//在这里调用上传图片的方法
   
        console.log(that.data.uploadImgList);
        console.log(that.data.videoPath_links)
        setTimeout(()=>
        {
          wx.request({
          
            url:getApp().globalData.serverBaseUrl+'/Applets/setShopKeeper',
            //url:getApp().globalData.serverBaseUrl+'/Applets/login',
            header: {'content-type': 'application/x-www-form-urlencoded'},
            method: 'POST',
            data: {
              'shopposition': e.detail.value.shopposition,
              'shopname': e.detail.value.shopname,
              'realname': e.detail.value.realname,
              'mobile': e.detail.value.mobile,
              'maincontent': e.detail.value.maincontent,
              'flow': e.detail.value.flow,
              'token':shoptoken,
              'photo':that.data.uploadImgList,//将服务器端图片地址随表单一起上传
            },
            success: function (res) {
              if(res.data.code == 200){
                wx.showModal({
                  title: '提示',
                  content: res.data.msg,
                  showCancel: true,
                  success: function (res) {
                  }
                })
                // wx.navigateBack({
                  
                // })
              }else{
                wx.showModal({
                  title: '提示',
                  content: res.data.msg,
                  showCancel: false,
                  success: function (res) {
                  }
                })
              }
              
            },
            fail:function(res){
              console.log(res);
            }
          })
        }, 500)
      
    

效果展示:
点击相机按钮选择图片

在这里插入图片描述
上传表单时要注意,wx.request是异步发生的,逻辑上需要图片先上传到后端,后端返回图片存储地址,再将地址存入前端变量中,最后表单上传到后端,但wx.request是异步发生的,也就说有可能uploadimagFile()并没有完全执行完,表单就上传到后端,导致最后图片能全都上传到后端,但数据库中表单内图片地址不全。
一开始尝试如上面代码那样使用setTimeout,即在uploadimagFile()与wx.request间增加一个延迟来解决以上问题,很明显,这种解决方法并不稳定,在网络不那么理想或者图片较多的情况下,request方法发生时经常图片上传仍没有完成,而加大延迟会明显影响用户体验。

解决wx.request异步问题

回调

最简单的解决方案,就是把需要使用异步数据的函数写在回调里,例如:

   wx.request({
     url: 'url', // 这里填写的接口地址
     data: { }, //这里填写需要传输的数据
     method: 'POST',  // 这里也可以是'GET'
     header: {
        'content-type': 'application/json', // 默认值
        'session': ‘sessionid’  //这里一般可能用不到,通过session来确认用户身份,比较安全的用法
      },
     success:function(res) {
         console.log(res.data)
         //这里再次发送请求
         wx.request({
            url: 'url', // 这里填写的接口地址
            data: { }, //这里填写需要传输的数据
            method: 'POST',  // 这里也可以是'GET'
            header: {
                'content-type': 'application/json', // 默认值
                'session': ‘sessionid’  //这里一般可能用不到,通过session来确认用户身份,比较安全的用法
              },
            success:function(res) {
             console.log(res.data)
          }
        })
  }
})   

看起来很容易理解,两个异步函数嵌套起来,似乎感觉还不是很乱,但如果4个5个呢?

Promise+ASYNC\AWAIT

添加微信小程序对es6与es7的支持
在这里插入图片描述
在需要使用Promise+ASYNC\AWAIT的JS下导入
在这里插入图片描述
然后我们就能正常使用Promise以及ASYNC\AWAIT了。

首先,修改我们的uploadimagFile()方法:

uploadimagFile(){
  const that=this;
  return new Promise((resolve,reject)=>{//在这里使用return
  let imgListData = that.data.imgList;
  //let current=that.data.uploadcurrent;
  console.log(imgListData)
  //console.log("current当前",current)
  for(let i=0;i<imgListData.length;i++){
    console.log(imgListData[i])
          wx.uploadFile({
            url: getApp().globalData.serverBaseUrl+'/Applets/wechatImg',
            filePath:imgListData[i],
            name:'image',
            success(res) {
              console.log("返回的信息",res.data)
            let imgPath_url=JSON.parse(res.data).url
            console.log(imgPath_url)
             that.data.uploadImgList=that.data.uploadImgList.concat(imgPath_url)
              console.log(that.data.uploadImgList)
              that.setData({
                uploadImgList:that.data.uploadImgList,
                //uploadcurrent:current,
                //imgList:'',
              })
              wx.showToast({
                title: '上传数据成功',
                icon: 'success',
                duration: 500,
                success: function () {
                  // setTimeout(() => {
                  //   wx.navigateBack()
                  // }, 300)
                }
              })

              if(that.data.uploadImgList.length==imgListData.length)//检测是否所有图片都上传完了
              {console.log("开始回调");
                resolve(that.data.uploadImgList);}
            },
            fail: function (res) {
              console.log('接口调用失败');
              console.log(res);
              reject(res);
            }
          })
  }
})
},

要注意的是,resolve()不能直接在success function中直接发生,因为我们在这里使用for循环来一张一张图片上传,若不设置一个结束条件,那么在第一张图片上传成功,success方法调用时,就会直接resolve,导致下一步(表单上传)不等所有图片上传完就开始。

submit方法的修改(部分代码),注意async和await的搭配使用:

formSubmit:async function(e){//在function前添加async
      if (e.detail.value.shopposition == '') {
        wx.showModal({
          title: '提示',
          content: '地址不能为空',
          showCancel: false,
          success: function (res) {
          }
        })
      } 
      
      else {
        console.log('form发生了submit事件,携带数据为:', e.detail.value);
        var that=this;
        var shoptoken=that.data.token;
        console.log(shoptoken);
        if(that.data.imgList!=''&&that.data.imgList!=null)//注意先判断图片地址是否为空
        {await this.uploadimagFile();} //使用await
        console.log(that.data.uploadImgList);
           wx.request({
       //省略
          })
      }
    },

版权声明:本文为weixin_43616676原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。