步骤一:绑定域名

先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

备注:登录后可在“开发者中心”查看对应的接口权限。

步骤二:引入JS文件

在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.4.0.js

如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.4.0.js (支持https)。

步骤三:后台获取参数传到前端配置

获取微信基础access_token(该token与微信支付的网页特授access_token不同),根据该token获取jsapi_ticket,在用该ticket生成signature(关键),

//获取基础支持中access_token,access_token的有效期目前为2个小时,需定时刷新,必须在自己的服务全局缓存access_token

String param="grant_type=client_credential&appid="+ PayConfUtil.APP_ID+"&secret="+PayConfUtil.SECRET;

String Json= HttpUtil.sendGet(PayConfUtil.token_url,param);

JSONObject json= JSON.parseObject(Json);

String access_token=json.getString("access_token");

HttpSession session=request.getSession();

session.setAttribute("access_token",access_token);

//获取jsapi_ticket是公众号用于调用微信JS接口的临时票据有效期目前为2个小时,需定时刷新,必须在自己的服务全局缓存jsapi_ticket

String param2="access_token="+access_token+"&type=jsapi";

String Json2=HttpUtil.sendGet(PayConfUtil.getticket_url,param2);

JSONObject json2= JSON.parseObject(Json2);

String ticket=json2.getString("ticket");

//JS-SDK使用权限签名算法

String noncestr= WXPayUtil.generateNonceStr();

String timestamp=WXPayUtil.getCurrentTimestamp()+"";

String url="http://wechat.muentech.cn/wx/Camera/wxLoginFace";

String ASCII="jsapi_ticket="+ticket+"&noncestr="+noncestr+"&timestamp="+timestamp+"&url="+url;

String signature=WXPayUtil.shaEncode(ASCII);

//返回前端数据

Map<String,String> paraMap=new HashMap<String, String>();

paraMap.put("appId", PayConfUtil.APP_ID);

paraMap.put("timestamp",timestamp);

paraMap.put("nonceStr",noncestr);

paraMap.put("signature",signature);

步骤四:通过config接口注入权限验证配置

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用

wx.config({

debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。

appId: appId, // 必填,公众号的唯一标识

timestamp:timestamp , // 必填,生成签名的时间戳

nonceStr: nonceStr, // 必填,生成签名的随机串

signature:signature ,// 必填,签名

jsApiList: ['checkJsApi','chooseImage','previewImage','uploadImage','downloadImage','getLocalImgData'] // 必填,需要使用的JS接口列表

});

步骤五:调用微信图像接口,将图片上传到微信服务器

var images = {

localId: null,

serverId: null

};

$("#imghead").click(function(){

wx.chooseImage({

count: 1, // 默认9

sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有

sourceType: ['camera','album'], // 可以指定来源是相册还是相机,默认二者都有

success: function (res) {

images.localId = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片

var img=document.getElementById("imghead");

img.src=images.localId[0];

images.serverId=null;

wx.uploadImage({

localId: images.localId[0], // 需要上传的图片的本地ID,由chooseImage接口获得

isShowProgressTips: 1, // 默认为1,显示进度提示

success: function (res) {

images.serverId = res.serverId; // 返回图片的服务器端ID

$.ajax({

url: "/wx/sendImg",

type: "POST",

data: {media_id: images.serverId},

success: function (data) {

if(data=="SUCCESS"){

alert("修改头像成功")

}

},

error:function () {

alert("error")

}

})

}

})

}

});

});

步骤六:从微信服务器获取图片网络流,发送网络流到阿里oss

@RequestMapping(value = "/sendImg",method = RequestMethod.POST)

@ResponseBody

public String sendImg(String media_id){

OSSClient ossClient = AliyunOssClientUtil.getOSSClient();

HttpSession session=request.getSession();

String access_token=(String) session.getAttribute("access_token");

System.out.println("access_token="+access_token);

System.out.println("media_id="+media_id);

//拼接请求地址

String requestUrl=PayConfUtil.media_url+"?access_token="+access_token+"&media_id="+media_id;

try {

//上传网络流

long time=System.currentTimeMillis();

URL url=new URL(requestUrl);

InputStream inputStream=url.openStream();

//获取报文长度

HttpURLConnection connection=(HttpURLConnection) url.openConnection();

connection.setDoInput(true);

connection.setRequestMethod("GET");

connection.setConnectTimeout(30000);

connection.setReadTimeout(30000);

String fileExt=connection.getHeaderField("Content-Type").substring(connection.getHeaderField("Content-Type").lastIndexOf("/")+1);

long ContentLength=connection.getContentLength();

String fileName="touxiang"+time+"."+fileExt;

try {

AliyunOssClientUtil.uploadFileOSS(inputStream,fileName,ossClient,ContentLength);

inputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

String pictureUrl = "https://" + OSSClientConstants.BACKET_NAME + "." + OSSClientConstants.ENDPOINT

+ File.separator + OSSClientConstants.FOLDER + fileName;

System.out.println(pictureUrl);

connection.disconnect();

return "SUCCESS";

}catch (Exception e){

e.printStackTrace();

System.out.println("下载图片失败");

return "FALL";

}

}

import com.aliyun.oss.OSSClient;

import com.aliyun.oss.model.ObjectMetadata;

import java.io.IOException;

import java.io.InputStream;

import lombok.extern.slf4j.Slf4j;

import org.apache.log4j.Logger;

/**

* @author jack

*/

@Slf4j

public class AliyunOssClientUtil {

// 阿里云API的内或外网域名

private static String ENDPOINT;

// 阿里云API的密钥Access Key ID

private static String ACCESS_KEY_ID;

// 阿里云API的密钥Access Key Secret

private static String ACCESS_KEY_SECRET;

// 阿里云API的bucket名称

private static String BACKET_NAME;

// 阿里云API的文件夹名称

private static String FOLDER;

// 阿里云API的文件夹名称

// 初始化属性

static {

ENDPOINT = OSSClientConstants.ENDPOINT;

ACCESS_KEY_ID = OSSClientConstants.ACCESS_KEY_ID;

ACCESS_KEY_SECRET = OSSClientConstants.ACCESS_KEY_SECRET;

BACKET_NAME = OSSClientConstants.BACKET_NAME;

FOLDER = OSSClientConstants.FOLDER;

}

private static Logger logger = Logger.getLogger(AliyunOssClientUtil.class);

public static OSSClient getOSSClient() {

return new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

}

private static String getContentType(String fileName) {

// 文件的后缀名

String fileExtension = fileName.substring(fileName.lastIndexOf("."));

if (".bmp".equalsIgnoreCase(fileExtension)) {

return "image/bmp";

}

if (".gif".equalsIgnoreCase(fileExtension)) {

return "image/gif";

}

if ( ".jpg".equalsIgnoreCase(fileExtension)

|| ".png".equalsIgnoreCase(fileExtension)) {

return "image/jpeg";

}

if (".jpeg".equalsIgnoreCase(fileExtension) ){

return "image/jpg";

}

if (".html".equalsIgnoreCase(fileExtension)) {

return "text/html";

}

if (".txt".equalsIgnoreCase(fileExtension)) {

return "text/plain";

}

if (".vsd".equalsIgnoreCase(fileExtension)) {

return "application/vnd.visio";

}

if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {

return "application/vnd.ms-powerpoint";

}

if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {

return "application/msword";

}

if (".xml".equalsIgnoreCase(fileExtension)) {

return "text/xml";

}

// 默认返回类型

return "image/jpeg";

}

/**

* 上传到OSS服务器 如果同名文件会覆盖服务器上的

*

* @param instream 文件流

* @param fileName 文件名称 包括后缀名

* @return 出错返回"" ,唯一MD5数字签名

*/

public static void uploadFileOSS(InputStream instream, String fileName, OSSClient ossClient,Long ContentLength) {

try {

// 创建上传Object的Metadata

ObjectMetadata objectMetadata = new ObjectMetadata();

objectMetadata.setContentLength(ContentLength);

objectMetadata.setCacheControl("no-cache");

objectMetadata.setHeader("Pragma", "no-cache");

objectMetadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf("."))));

objectMetadata.setContentDisposition("inline;filename=" + fileName);

// 上传文件

ossClient.putObject(BACKET_NAME, FOLDER + fileName, instream, objectMetadata);

ossClient.shutdown();

} catch (Exception e) {

log.error(e.getMessage(), e);

} finally {

try {

if (instream != null) {

instream.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

本次学习的地方

1.inStream.available()读取文件流长度不不完整,这个方法从本地文件读取数据时一般不会出现问题,但是通过网路传输就会出现图片传输不完整的情况,因为网络通讯是间断性的一串字节往往分几批进行发送。本地程序调用available()方法有时得到0,这可能是对方还没有响应,也可能是对方已经响应了,但是数据还没有送达本地。

2.微信服务器返回的图片为jpeg格式,需将该图片转为jpg格式才可在浏览器中预览,否则一直是下载(没搞懂)

3.openStream和openConnection的区别:

openStream()方法的实现也是调用了 openConnection生成一个 URLConnection 对象,然后再通过这个对象调用的 getInputStream()方法的

openStream 是取 stream 的内容,而 openConnection 可以得到一些内容之外的东西,比如 modification date 和 http header

openStream就是把openConnection和getInputStream连起来调用了

微信js-sdk说明文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

阿里oss开发文档:https://www.alibabacloud.com/help/zh/doc-detail/31883.htm

10-29 18:49