主要功能:调用微信图片选择接口,用户确定之后将图片上传到七牛云,然后将返回的图片地址保存到本地数据库对应字段

踩的坑

  • 微信JSDDK 1.1.0和1.2.0的差异
  • 安卓手机和IOS的差异

主要表现在wx.chooseImagewx.uploadImage,还有选择图片之后获取到如: wxlocalresource://imageid123456789987654321 这样的图片地址,IOS无法预览,或者wx.uploadImage接口在IOS上只能上传一张图片。

微信官方文档

七牛云fetch接口

实现的思路

  • 通过wx.chooseImage接口让用户选择图片,选择之后生成预览
  • 通过wx.uploadImage接口将图片上传到微信服务器做临时素材
  • 通过七牛云fetch接口去下载微信服务器上的图片

代码实现

引入权限验证

// config权限验证
function wxconfig(url){
    $.post('/weixin/configvalid', {'url':url.toString()}, function(data){
        wx.config({
            debug: false,
            appId: data.appId,
            timestamp: data.timestamp,
            nonceStr: data.nonceStr,
            signature: data.signature,
           /* jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage']*/
            jsApiList: [
                        'checkJsApi',
                        'onMenuShareTimeline',
                        'onMenuShareAppMessage',
                        'onMenuShareQQ',
                        'onMenuShareWeibo',
                        'onMenuShareQZone',
                        'hideMenuItems',
                        'showMenuItems',
                        'hideAllNonBaseMenuItem',
                        'showAllNonBaseMenuItem',
                        'translateVoice',
                        'startRecord',
                        'stopRecord',
                        'onVoiceRecordEnd',
                        'playVoice',
                        'onVoicePlayEnd',
                        'pauseVoice',
                        'stopVoice',
                        'uploadVoice',
                        'downloadVoice',
                        'chooseImage',
                        'previewImage',
                        'uploadImage',
                        'downloadImage',
                        'getNetworkType',
                        'openLocation',
                        'getLocation',
                        'hideOptionMenu',
                        'showOptionMenu',
                        'closeWindow',
                        'scanQRCode',
                        'chooseWXPay',
                        'openProductSpecificView',
                        'addCard',
                        'chooseCard',
                        'openCard',
                        'openAddress',
                        'getLocalImgData'
                    ]
        });
    });
}

导包 (这里我们用微信JSJDK 1.2.0)

<script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>

选择图片,上传图片参考官方demo(我是遇到了一大箩筐问题之后才看到这个救命的demo)

// 5 图片接口
  // 5.1 拍照、本地选图
  var images = {
    localId: [],
    serverId: []
  };
  document.querySelector('#chooseImage').onclick = function () {
    wx.chooseImage({
      success: function (res) {
        images.localId = res.localIds;
        alert('已选择 ' + res.localIds.length + ' 张图片');
      }
    });
  };
// 5.3 上传图片
  document.querySelector('#uploadImage').onclick = function () {
    if (images.localId.length == 0) {
      alert('请先使用 chooseImage 接口选择图片');
      return;
    }
    var i = 0, length = images.localId.length;
    images.serverId = [];
    function upload() {
      wx.uploadImage({
        localId: images.localId[i],
        success: function (res) {
          i++;
          alert('已上传:' + i + '/' + length);
          images.serverId.push(res.serverId);
          if (i < length) {
            upload();
          }
        },
        fail: function (res) {
          alert(JSON.stringify(res));
        }
      });
    }
    upload();
  };

这个上传的例子可以解决图片只能上传一张的问题,我们就基于这个例子改进我们的代码。

wxconfig(window.location);

// 5 图片接口
// 5.1 拍照、本地选图
var images = {
  localId: [],
  serverId: []
};
var arrayImgs = new Array();
document.querySelector('#uploaderInput').onclick = function () {
  wx.chooseImage({
    success: function (res) {
      images.localId = res.localIds;
      //生成预览 区分一下ios跟其他系统
      var localIds  = res.localIds;
      if(window.__wxjs_is_wkwebview){
        //alert(localIds[0])

        for (id in localIds) {
          wx.getLocalImgData({
            localId: localIds[id],
            success: function (res) {
              var localData = res.localData;
              localData = localData.replace('jgp', 'jpeg');
              var tmpl = '<img class="weui-uploader__file weui-uploader__file_status" src="'+localData+'" data-src="'+localIds[id]+'"/>';
              $("#uploaderFiles").append(tmpl)
            },
            fail:function(res){
              alert(res.errMsg);
            }
          });
        }
      }else{
        //遍历数组
        for (id in localIds){   
          var tmpl = '<img class="weui-uploader__file weui-uploader__file_status" src="#url#" data-src="#url#"/>';
          $("#uploaderFiles").append($(tmpl.replace(/#url#/ig, localIds[id])));

        } 
      }
    }
  });
};
// 5.3 上传图片
document.querySelector('#upload_img1').onclick = function () {
  if (images.localId.length == 0) {
    alert('请先选择图片');
    return;
  }
  var i = 0, length = images.localId.length;
  images.serverId = [];
  function upload() {
    wx.uploadImage({
      localId: images.localId[i],
      success: function (res) {
        arrayImgs[i] = res.serverId
        console.log(typeof(arrayImgs))
        i++;
        //alert('已上传:' + i + '/' + length);
        images.serverId.push(res.serverId);
        if (i < length) {
          upload();
        }else{
          // 循环结束
          topost(arrayImgs)
        }
      },
      fail: function (res) {
        alert(JSON.stringify(res));
      }
    });
  }
  upload();
};

最后向后台服务器发送请求

function topost(obj){
   var resImgurl = obj.join(",")
   $.ajax({
     url: '/qiniuImg',
     data: {
       "resImgurl":resImgurl,
       "content":"测试"
     },
     type: 'post',
     dataType: 'json',
     cache: false,
     success: function(data){
       console.log(data)
       if(data.re){
         console.log("成功写入数据库,进行页面跳转!")
         alert(data.msg)
         location.replace('/index');
       }else{
         alert(data.msg)
       }
     }
   }); 
 }

后台获取图片

String resImgurl = getPara("resImgurl");

// 获取图片信息
List<String> imgurl =  new ArrayList<String>();
int i = 0;int j = 1;

String[] media_list = resImgurl.split(",");

for (String media_id : media_list) {
  String key = QianNiuUpload.fetchTmpFile(media_id, "");
  String url = QianNiuUpload.domain + key;
  imgurl.add(url);
}

.... 
将图片的url 写入数据库

QianNiuUpload.java

public class QianNiuUpload {
    //设置好账号的ACCESS_KEY和SECRET_KEY
    public static String ACCESS_KEY = "xxxxxx";
    public static String SECRET_KEY = "xxxxxx";
    //要上传的空间
    public static String bucketname = "xxxxxx";

    public static String domain = "http://xxxxxxx.com/"; // 空间的域名

    //上传到七牛后保存的文件名
    public static String key = "随意,这个例子我们没用到";
    //上传文件的路径
    public static String FilePath = "随意,这个例子我们没用到";

    //密钥配置
    public static Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);

    //第二种方式: 自动识别要上传的空间(bucket)的存储区域是华东、华北、华南。
    public static Zone z = Zone.autoZone();
    public static Configuration c = new Configuration(z);

    //创建上传对象
    private static UploadManager uploadManager = new UploadManager(c);

    //简单上传,使用默认策略,只需要设置上传的空间名就可以了
    public static String getUpToken() {
        return auth.uploadToken(bucketname);
    }

    public static void upload() throws IOException {
        try {
            //调用put方法上传
            Response res = uploadManager.put(FilePath, key, getUpToken());
            //打印返回的信息
            System.out.println(res.bodyString());
        } catch (QiniuException e) {
            Response r = e.response;
            // 请求失败时打印的异常的信息
            System.out.println(r.toString());
            try {
                //响应的文本信息
                System.out.println(r.bodyString());
            } catch (QiniuException e1) {
                //ignore
            }
        }
    }

    //定义两个成员变量常量
    //获取临时素材(视频不能使用https协议)
    public static final String GET_TMP_MATERIAL = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s";
    //获取临时素材(视频)
    public static final String GET_TMP_MATERIAL_VIDEO = "http://api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s";

     //获取微信服务器中生成的媒体文件
     //由于视频使用的是http协议,而图片、语音使用http协议,故此处需要传递media_id和type

    public static String fetchTmpFile(String media_id, String type){
           try {
                String token = AccessTokenApi.getAccessToken().getAccessToken();
                String url = null;

                //视频是http协议
                if("video".equalsIgnoreCase(type)){
                 url = String.format(GET_TMP_MATERIAL_VIDEO, token, media_id);
                }else{
                 url = String.format(GET_TMP_MATERIAL, token, media_id);;
                }
                URL Nurl = new URL(url);
                //构造一个带指定Zone对象的配置类
                Configuration cfg = new Configuration(Zone.autoZone());  

                Auth me = Auth.create(ACCESS_KEY,SECRET_KEY);
                BucketManager bucketManager = new BucketManager(me, cfg);
               // bucketManager.fetch("外源图片地址", "要上传的七牛目标资源文件夹", "文件名");
                // 这边的文件名如果省略 七牛会随机给个名字
                FetchRet fetchRet = bucketManager.fetch(url,bucketname);

                //System.out.println(fetchRet.hash);
                System.out.println(fetchRet.key);
                //System.out.println(fetchRet.mimeType);
                //System.out.println(fetchRet.fsize);
                return fetchRet.key;
              } catch (Exception e) {
               e.printStackTrace();
              }
        return null;
    }  
}

java 后台七牛返回的上传后的文件名

七牛云存储空间可以看到图片已经成功上传了