如果要使用微信公众平台的网页开发,首先要生成签名,其算法也在官方的wiki说明了,网上也有PHP版本,在这里写一下java的生成版本:
1.因为保密需要,把关键参数隐去了,但签名与公众号接入差不多,只是参数个数变了,下面是参考代码
package cn.xdf.wlyy.controller;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Date;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import cn.xdf.wlyy.util.HttpUtils;
import cn.xdf.wlyy.util.IdUtils;
import com.alibaba.fastjson.JSONObject;
@Controller
@RequestMapping(value = "/test")
public class TestController {
private static String jsToken = null;
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
private static String byteToHexStr(byte mByte) {
char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
String s = new String(tempArr);
return s;
}
@RequestMapping(value = "/testpage")
public ModelAndView page(ModelAndView mav) {
String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
String accessTokenResult = HttpUtils.get(accessTokenUrl);
JSONObject accessJsonObject = JSONObject.parseObject(accessTokenResult);
String accessToken = accessJsonObject.getString("access_token");
String jsTokenUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
String jsTokenResult = HttpUtils.get(jsTokenUrl.replace("ACCESS_TOKEN", accessToken));
JSONObject jsTokenJsonObject = JSONObject.parseObject(jsTokenResult);
if (jsTokenJsonObject != null) {
int errcode = jsTokenJsonObject.getInteger("errcode");
if (errcode == 0) {
jsToken = jsTokenJsonObject.getString("ticket");
}
}
String url = "http://xxx.vicp.cc/wechatserver/test/testpage";//因为要使用微信客户微访问本地环境,这里面使用了花生壳做内网映射
String timestamp = String.valueOf(new Date().getTime() / 1000);
String noncestr = IdUtils.getId();
String jsapi_ticket = jsToken;
String str1 = "noncestr=" + noncestr;
String str2 = "jsapi_ticket=" + jsapi_ticket;
String str3 = "timestamp=" + timestamp;
String str4 = "url=" + url;
String[] paramArr = new String[] { str1, str2, str3, str4 };
Arrays.sort(paramArr);
// 将排序后的结果拼接成一个字符串
String content = paramArr[0].concat("&").concat(paramArr[1]).concat("&").concat(paramArr[2]).concat("&").concat(paramArr[3]);
String signature = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
// 对接后的字符串进行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
signature = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
/*appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
*/
mav.addObject("appId", "wxxxxxxxxxxxxxxxxxxxx");
mav.addObject("timestamp", timestamp);
mav.addObject("nonceStr", noncestr);
mav.addObject("signature", signature);
mav.setViewName("testPage");
return mav;
}
}
2.而在页面中,是直接访问1中的controller,跳转到这个页面,然后直接把appId/timestamp/nonceStr/signatrue等参数返回给页面,让页面调用,页面如下:
<!DOCTYPE html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<meta name="description" content="description about your site" />
<meta name="keywords" content="" />
<meta name="author" content="ZTApps" />
<script src="<%=basePath%>/static/js/jquery-1.11.2.min.js"></script>
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<title>测试页面</title>
</head>
<body>
</body>
<script>
$(function() {
var appId = '${appId}';
var timestamp = ${timestamp};
var nonceStr = '${nonceStr}';
var signature = '${signature}';
wx.config({
debug : true,
appId : appId,
timestamp : timestamp,
nonceStr : nonceStr,
signature : signature,
jsApiList : ['getLocation']
});
wx.ready(function(){
wx.getLocation({
type: 'gcj02', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
success: function (res) {
var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。
var speed = res.speed; // 速度,以米/每秒计
var accuracy = res.accuracy; // 位置精度
alert("纬度:" + latitude);
alert("经度:" + longitude);
alert("速度:" + speed);
alert("accuracy:" + accuracy);
}
});
});
});
</script>
</html>
上面主要是想验证签名这个参数是否生成的正确,并通过调用地址位置的接口wx.getLocation来测试是否获取到了位置。
(因为对浏览器内置的js定位很苦恼,使用android手机,在提示不允许使用位置后,下次还会有提示消息,而允许后下次就不会再有提示信息了;而用ios只会提示一次,允许就一直允许,不允许就一直不允许了,没有反悔的机会。目前还没有很好的解决方案)