微信公众号开发--微信JS-SDK扫一扫功能

首先请阅读微信JS-SDK说明文档,了解微信JS的相关说明。
根据官方的使用步骤,关键的有以下几步

  1. 绑定域名(很关键
  2. 引入JS文件(很简单)
  3. 通过config接口注入权限验证配置(很重要
  4. 通过ready接口处理成功验证(还没用到)
  5. 通过error接口处理失败验证(还没用到)

绑定域名

绑定域名
如果域名绑定有误,会出现如下错误提示
错误的域名配置示例:

`http://gwchsk.imwork.net/wechat/order/test.html`

域名配置错误的提示信息:
{“errMsg”:”config:invalid url domain”}

这里写图片描述

所以,域名配置的时候一定要注意
1. 域名不要以http:开头
2. 域名不要配置到具体的页面
配置成功的提示如下

这里写图片描述

引入JS文件

一行代码就可以了

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

通过config接口注入权限验证配置

这一步非常重要,也是最关键的一步,这一部分
先看官方的示例

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,见附录1
    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});

这里需要从服务器端网页面传递的参数有timestamp、nonceStr和signature而appId和jsApiList都是固定的,这里直接写在页面中。

首先,编写服务器端代码,生成timestampnonceStrsignature
在生成timestamp、nonceStr和signature的时候有两个参数需要获取
一个是access_token,另一个是jsapi_ticket

access_token的获取需要AppIdAppSecret,获取地址如下,发送GET请求

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

通过HttpClient发送http请求就可以获取到access_token

得到access_token之后,采用http GET方式请求获得jsapi_ticket

https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

注意,access_token和jsapi_ticket得有效期为7200秒,开发者必须在自己的服务全局缓存

获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。

签名算法

签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。

签名算法的实现

最难的就是签名算法的实现部分,幸好微信给了demo,网上好多人都在找,这里我把签名算法的实现贴出来,代码来自微信demo
这里写图片描述
下载地址
java代码如下,做了一点点修改

package com.gwc.wechat.utils.wechat;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class WxJSUtil {
    public static void main(String[] args) {

        // 注意 URL 一定要动态获取,不能 hardcode
        String url = "http://gwchsk.imwork.net/wechat/order/test.html";
        Map<String, String> ret = sign(url);
        for (Map.Entry entry : ret.entrySet()) {
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
    };

    public static Map<String, String> sign(String url) {
        Map<String, String> ret = new HashMap<String, String>();
        //这里的jsapi_ticket是获取的jsapi_ticket。
        String jsapi_ticket = JSAPITicketTool.getTicket();
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        String string1;
        String signature = "";

        //注意这里参数名必须全部小写,且必须有序
        string1 = "jsapi_ticket=" + jsapi_ticket +
                  "&noncestr=" + nonce_str +
                  "&timestamp=" + timestamp +
                  "&url=" + url;
       // System.out.println(string1);

        try
        {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        catch (UnsupportedEncodingException e)
        {
            e.printStackTrace();
        }

        ret.put("url", url);
        ret.put("jsapi_ticket", jsapi_ticket);
        ret.put("nonceStr", nonce_str);
        ret.put("timestamp", timestamp);
        ret.put("signature", signature);

        return ret;
    }

    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash)
        {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    private static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }

    private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
}

Controller的代码

@Controller
@RequestMapping(value = "/order")
public class OrderController {
@RequestMapping(value = "/test.html", method = RequestMethod.GET)
    public String testPage(Model model) {

        String url = Constant.AppURL + "/order/test.html";
        Map<String, String> ret = WxJSUtil.sign(url);
         for (Map.Entry entry : ret.entrySet()) {
                System.out.println(entry.getKey() + "=" + entry.getValue());
                model.addAttribute(entry.getKey().toString(), entry.getValue());
            }
        return "jqueryMobile";
    }
}

在Controller中将如下参数写进了jsp页面

    timestamp=1449132293
    nonceStr=fb4eaa58-6d53-40a8-a8fa-7033e9768a8a
    signature=7ad32da3f82cb36492de935a60727d3053d33f4b

其次编写jsp页面的代码
在jsp页面中需要将wx.config重的参数进行配置

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,见附录1
    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});

在页面中读值

    <input id="timestamp" type="hidden" value="${timestamp}" />
    <input id="noncestr" type="hidden" value="${nonceStr}" />
    <input id="signature" type="hidden" value="${signature}" />

然后赋值

    <script type="text/javascript">
        $(function() {
            var timestamp = $("#timestamp").val();//时间戳
            var nonceStr = $("#noncestr").val();//随机串
            var signature = $("#signature").val();//签名
            wx.config({
                debug : true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
                appId : 'wx622ca8545e5c354b', // 必填,公众号的唯一标识
                timestamp : timestamp, // 必填,生成签名的时间戳
                nonceStr : nonceStr, // 必填,生成签名的随机串
                signature : signature,// 必填,签名,见附录1
                jsApiList : [ 'scanQRCode' ]
            // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
            });
        });
    </script>

写一个按钮和输入框,将扫描的结果放进输入框

<input id="id_securityCode_input">
<button id="scanQRCode">扫码</button>

给按钮绑定事件,并执行微信扫码

$("#scanQRCode").click(function() {
            wx.scanQRCode({
                // 默认为0,扫描结果由微信处理,1则直接返回扫描结果
                needResult : 1,
                desc : 'scanQRCode desc',
                success : function(res) {
                    //扫码后获取结果参数赋值给Input
                    var url = res.resultStr;
                    //商品条形码,取","后面的
                    if(url.indexOf(",")>=0){
                        var tempArray = url.split(',');
                        var tempNum = tempArray[1];
                        $("#id_securityCode_input").val(tempNum);
                    }else{
                        $("#id_securityCode_input").val(url);
                    }
                }
            });
        });

运行结果如图
扫一包抽纸

抽纸

扫描结果

放进input

扫网址

这里写图片描述

这里写图片描述

微信JS-SDK中的扫一扫就基本实现了。

参考文献

微信JS-SDK说明文档
一篇博客

是要输入验证码吗?我已经设置了再部分区域不用输入验证码了。求大神回答 模拟登陆的代码如下: # -*- coding: utf-8 -*- import requests import base64 import re import urllib import rsa import json import binascii import string from weibo import Client import random import time import logging, logging.handlers ''' code = "5f9f84b2aa3198032416963c84c2d182" app_key = "4055744185" app_secret = "838ec8be666e6116c4e483ed14e5fea4" redirect_uri = "https://api.weibo.com/oauth2/default.html" user_name = '412062385@qq.com' pwd = 'googlesina' ''' class SinaCrawler: def __init__(self, max_page): self.session = None self.MAX_PAGE = max_page token = {u'access_token': u'2.00pE39sBn1UT7E61e7174d95TdYVED', u'remind_in': u'157679999', u'uid': u'1720813027', u'expires_at': 1575304674} self.client = Client(app_key, app_secret, redirect_uri, token) self.f = open("data", "w") def __del__(self): self.f.close() def userlogin(self,username,password): session = requests.Session() url_prelogin = 'http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=&rsakt=mod&client=ssologin.js(v1.4.18)&_=1430736851146' url_login = 'http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.8)' #get servertime,nonce, pubkey,rsakv resp = session.get(url_prelogin) print resp.content p = re.compile('{.*}') json_data = re.search(p, resp.content).group() print json_data data = eval(json_data) servertime = data['servertime'] print 'servertime:',servertime nonce = data['nonce'] pubkey = data['pubkey'] rsakv = data['rsakv'] # calculate su su = base64.b64encode(urllib.quote(username)) #calculate sp rsaPublickey= int(pubkey,16) key = rsa.PublicKey(rsaPublickey,65537) message = str(servertime) +'\t' + str(nonce) + '\n' + str(password) sp = binascii.b2a_hex(rsa.encrypt(message,key)) postdata = { 'entry': 'weibo', 'gateway': '1', 'from': '', 'savestate': '7', 'userticket': '1', 'ssosimplelogin': '1', 'vsnf': '1', 'vsnval': '', 'su': su, 'service': 'miniblog', 'servertime': servertime, 'nonce': nonce, 'pwencode': 'rsa2', 'sp': sp, 'encoding': 'UTF-8', 'url': 'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack', 'returntype': 'META', 'rsakv' : rsakv, } resp = session.post(url_login,data = postdata) # print resp.headers login_url = re.findall('replace\(\"(.*)\"\)',resp.content) print 'login_url,[0]',login_url,login_url[0] respo = session.get(login_url[0]) print respo.content self.session = session if __name__ == '__main__': sina_crawler = SinaCrawler(50) sina_crawler.userlogin('lih211@sina.com', 'ta3344521')
<?php date_default_timezone_set("Asia/Shanghai"); //配置每天的活动时间段 $nowtime = time(); $starttimestr = date('H:i:s',time()); $ntime= date('H:i:s',time()); if ($ntime<"9:00:00") {$endtimestr = "9:00:00"; } elseif ($ntime>="9:00:00" and $ntime<"18:00:00") {$endtimestr = "18:00:00";} elseif ($ntime>"18:00:00") {$endtimestr="9:00:00";} if (date('w',time())<>4){ $endtimestr="2014-10-30 9:00:00"; $endtimestr="9:00:00";} $endtime =strtotime($endtimestr); if (date('w',time())<>4){ $endtimestr="9:00:00";} ?> <script language="JavaScript" type="text/javascript"> var EndTime=<?php echo "$endtime*1000";?>; var NowTime = new Date(); var dTime = NowTime.getTime()-<?php echo "$nowtime*1000";?>; var runtimes = 0; function GetRTime(){ var NowTime = new Date(); var dTimeNew = NowTime.getTime()-<?php echo "$nowtime*1000";?>; var dTimesM = Math.abs(Math.floor((dTimeNew-runtimes*1000-dTime)/1000)); if (dTimesM>1) { window.location.reload(); } var nMS = EndTime - NowTime.getTime()+dTime; var nH=Math.floor(nMS/(1000*60*60)) % 24; var nM=Math.floor(nMS/(1000*60)) % 60; var nS=Math.floor(nMS/1000) % 60; document.getElementById("RemainH").innerHTML=nH; document.getElementById("RemainM").innerHTML=nM; document.getElementById("RemainS").innerHTML=nS; runtimes++; setTimeout("GetRTime()",1000); } window.onload=GetRTime; </script> <center style="line-height:65px;"> <?php IF (date('w',time())>4){ if ($ntime>"9:00:00"){ $dday=7-date('w',time())+4-1;} else {$dday=7-date('w',time())+4;} } else IF (date('w',time())<4){ if ($ntime>"9:00:00"){ $dday=4-date('w',time())-1;} else {$dday=4-date('w',time());} } else{ $dday=0;} if($endtimestr=="9:00:00") {echo "<div style='width:1080px;color:#9e001c; font-size:32px'><strong>交流抢购经验请加入南阳家电网会员QQ群:310332256<br/>距离周四9点活动开始还剩".$dday."天</strong><strong id='RemainH'>XX</strong>:<strong id='RemainM'>XX</strong>:<strong id='RemainS'>XX</strong></div>";} elseif ($endtimestr>"18:00:00") {echo "<div style='width:1080px;color:#9e001c; font-size:32px'><strong>交流抢购经验请加入南阳家电网会员QQ群:310332256<br/>今天的抢购活动结束,请等待下个星期四的到来</strong><strong id='RemainH'>XX</strong>:<strong id='RemainM'>XX</strong>:<strong id='RemainS'>XX</strong></div>";} elseif (($endtimestr=="18:00:00")) {echo "<div style='width:1080px;color:#9e001c; font-size:32px'><strong>交流抢购经验请加入南阳家电网会员QQ群:310332256<br/>活动剩余时间</strong><strong id='RemainH'>XX</strong>:<strong id='RemainM'>XX</strong>:<strong id='RemainS'>XX</strong></div>";} ?></center>
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页