到现在为止,在新公司呆了也有几个月了,很莫名的自己从Android开发,变成了web app的开发,所以写一下关于自己这一
两个月对于微信公众号的开发心得,说到底,微信公众号的前台除去要调用微信的接口,也就单纯的H5开发而已,看看微信的网页
开发文档就知道,想要用微信的接口必须先注册一个公众号,公司就用服务号,个人就用订阅号,当然,如果只是想测试或者玩一
玩,又想用服务号的接口(比如说硬件接口),那我们可以注册一个测试号(在开发者工具中就可以找到了),下面就说一下具体
流程。
一:成为开发者
如果想开发微信公众号网页,我们必须使自己的公众号成为开发者,在基本配置中,启动服务器配置:你会发现要填写的有服务器地址(url),token,还有解密密匙,
解密密匙我们不管,消息加密选择明文就可以了。而服务器我是用servlet写的,比较简单,反正又不是写项目,能不用框架就不用,代码如下:
TokenServlet .java代码:WeixinUtil.java
public class TokenServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
public void init() throws ServletException {
// TODO Auto-generated method stub
SignatureThread thread = new SignatureThread();
new Thread(thread)..start();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
PrintWriter out = response.getWriter();
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
if(SignUtil.checkSignature(signature, timestamp, nonce)){
out.print(echostr);
System.out.println("微信服务验证成功!");
}
out.close();
out = null;
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
this.doGet(request, response);
}
}
SignUtil.java代码
// 与接口配置信息中的Token要一致
private static String token = "";
/**
* 验证签名
*
* @param signature
* @param timestamp
* @param nonce
* @return
*/
public static boolean checkSignature(String signature, String timestamp, String nonce) {
String[] arr = new String[] { token, timestamp, nonce };
// 将token、timestamp、nonce三个参数进行字典序排序
Arrays.sort(arr);
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
MessageDigest md = null;
String tmpStr = null;
try {
md = MessageDigest.getInstance("SHA-1");
// 将三个参数字符串拼接成一个字符串进行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
content = null;
// 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
}
/**
* 将字节数组转换为十六进制字符串
*
* @param byteArray
* @return
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
/**
* 将字节转换为十六进制字符串
*
* @param mByte
* @return
*/
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;
}
}
最后,很重要的一点要说明:上述项目要放在公网上行,端口也要用80端口。
二:wx.config配置
当我们查看微信开发文档时,注意到微信接口调用有几个步骤,首先wx.config和wx.ready这两个是必可少的,后者还好说,前面
简直坑的不要不要的,代码如下:
<script type="text/javascript" src="js/jsweixin-1.2.0.js"></script> <script type="text/javascript"> wx.config({ beta: true, // 开启内测接口调用,注入wx.invoke方法 debug: true, // 开启调试模式 appId: '', // 第三方app唯一标识 timestamp: , // 生成签名的时间戳 nonceStr: '', // 生成签名的随机串 signature: '',// 签名 // 需要使用的jsapi列表 jsApiList: [ 'getLocation' ] });
wx.ready(function(){ wx.checkJsApi({ jsApiList:['getLocation'], success:function(res){ alert(JSON.stringify(res)); wx.getLocation({ type:'wgs84', success:function(res){ alert("location:("+res.latitude+","+res.longitude+")"); } }) } }); })
这段代码是调用了微信的定位接口,APPID要注意是正式版的ID还是测试号的,在开发前我们注意要填写IP白名单和JS接口安全域名,否则,是没
有使用权限的,IP地址是多少可以通过获取access_token接口来看返回的IP获取,可以通过至于签名的获取方式由以下代码实现:
三:获取签名
WeixinUtil.java代码:
public class WeixinUtil {
/**
*
* @param appid
* @param appsecret
* @return
*/
public static AccessToken getAccessToken(String appid, String appsecret) {
String get_token_url = "https://api.weixin.qq.com/cgi-bin/token?"
+ "grant_type=client_credential&appid=APPID&"
+ "secret=APPSECRET";
String line = new String();
AccessToken accessToken = null ;
BufferedReader reader ;
try {
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(get_token_url);
HttpResponse response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity httpEntity = response.getEntity();
reader = new BufferedReader(new InputStreamReader(httpEntity.getContent()));
if ((line = reader.readLine()) != null) {
accessToken = AccessToken.getAccessToken(line);
}
}
} catch (Exception e) {
// TODO: handle exception
}
return accessToken;
}
/**
* sapi_ticket
*
* @param appid
* @param appsecret
* @return
*/
public static JsapiTicket getJsapiTicket(String accessToken) {
String jsapi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessToken+"&type=jsapi";
System.out.println(jsapi_ticket_url);
JsapiTicket jsapiticket = null;
BufferedReader reader ;
String line = new String();
if(accessToken != null){
try {
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(jsapi_ticket_url);
HttpResponse response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity httpEntity = response.getEntity();
reader = new BufferedReader(new InputStreamReader(httpEntity.getContent()));
if ((line = reader.readLine()) != null) {
System.out.println(line);
jsapiticket = JsapiTicket.getTicket(line);
}
}
}catch(Exception e){
}
}
return jsapiticket;
}
public static Signature getSignature(JsapiTicket ticket) {
String noncestr = UUID.randomUUID().toString().replace("-", "").substring(0, 16);//
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
// String urlLocation="http://yzy1992.duapp.com/location.html";//微信定位
// String urlDevice="http://yzy1992.duapp.com/loginPager.html";//设备触发
// String urlUerInfo="http://yzy1992.duapp.com/getUserInfo.html";
String url = "";
String jsapi_ticket = ticket.getTicket();
Signature signature = new Signature();
String signatureStr = "jsapi_ticket="+jsapi_ticket+"&noncestr="+noncestr+"×tamp="+timestamp+"&url="+url;
signatureStr = SHA1(signatureStr);
signature.setNoncestr(noncestr);
signature.setJsapi_ticket(jsapi_ticket);
signature.setSignature(signatureStr);
signature.setTimestamp(timestamp);
signature.setUrl(url);
return signature;
}
public static String SHA1(String signature) {
try {
MessageDigest digest = java.security.MessageDigest.getInstance("SHA-1");
digest.update(signature.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
}
SignatureThread.java代码
public SignatureThread() {
}
public void run() {
while (true) {
try {
accessToken = WeixinUtil.getAccessToken(appId, appSecret);
CallbackManager manager = null ;
if (null != accessToken) {
System.out.println("获取access_token成功,有效时长"+ accessToken.getExpiresIn()+"秒 token:"+ accessToken.getToken());
try{
ticket = WeixinUtil.getJsapiTicket(accessToken.getToken());
if(ticket!=null){
System.out.println("获取jsapiTicket成功,有效时长"+ ticket.getExpiresIn()+"秒 ticket:"+ ticket.getTicket());
signature = WeixinUtil.getSignature(ticket);
System.out.println("Signature为:"+signature.getSignature()+"/n"
+ "Noncestr为:" + signature.getNoncestr() + "/n"
+ "timestamp为:" + signature.getTimestamp());
if(manager == null){
manager = CallbackManager.getInstance();
}
manager.onGetSignature(signature);
}
}catch(Exception e){
// 如果jsapiTicket为null,60秒后再获取
Thread.sleep(60 * 1000);
}
// 休眠7000秒
Thread.sleep((accessToken.getExpiresIn() - 200) * 1000);
} else {
// 如果access_token为null,60秒后再获取
Thread.sleep(60 * 1000);
}
} catch (InterruptedException e) {
try {
Thread.sleep(60 * 1000);
} catch (InterruptedException e1) {
System.out.println(e1);
}
System.out.println(e);
}
}
}
}
注:通过微信接口回调的数据都是使用Gson存放到bean实体类中,而线程中的signature.class中的数据通过回调函数和ajax以jsonp的数据类型给到
前台(处理跨域传递数据的问题)