• 调用微信的扫一扫功能详解说明---(java 排坑版)


    最近碰到了这么一个需求,说是在前端页面调用手机本地的相机,扫描二维码这么一个需求,对于我一个后端来说,

    这实在是难,难于上青天,但是决不能说一个不字.我说可以使用微信的扫码工具吗,这样可以方便一点,...(起码有个思路)

    看着微信文档,一步一步坑下去.不对,是走下去.

    这里我们用测试是公众号,方便测试.

    首先配置自己的appID和appsecret,这里的测试帐号直接就给出了

    image

    第二步: 验证服务器,这个很简单,按照文档的规则验证就好了

    image

    第三步: 直接使用二级域名,不能添加http://前缀,或者是/XXX你自己写的接口(亲测)

    image

    这里还有个问题就是下载一个XXXXX.txt文件放在项目的根目录下,这个txt文件在公众号里面设置js安全域名下面可以下载

    第四步: 生成微信签名,这个很坑,要小心生成,这里面我使用的是google的guava做缓存,结合网上大佬的一个案例,仅限参考

    public static Map<String, Object> sign(String url) throws Exception {
    String ticket = getTicketToken(WeChatConstant.TICKET_TOKEN);
    Map<String, Object> ret = new HashMap<String, Object>();
    String nonce_str = create_nonce_str();
    String timestamp = create_timestamp();
    String string1;
    String signature = "";
    //注意这里参数名必须全部小写,且必须有序
    string1 = "jsapi_ticket=" + 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());
    System.out.println(signature+"=====================");
    }catch (NoSuchAlgorithmException e){
    e.printStackTrace();
    }catch (UnsupportedEncodingException e)
    {
    e.printStackTrace();
    }
    ret.put("url", url);
    ret.put("nonceStr", nonce_str);
    ret.put("timestamp", timestamp);
    ret.put("signature", signature);
    ret.put("jsapi_ticket", ticket);
    ret.put("appId", WeChatConstant.APPID);
    return ret;
    }
    /**
    * 缓存其accessToken 和 ticketToken 的值
    *
    * @param key
    * @return
    * @throws Exception
    */
    public static String getTicketToken(String key) throws Exception{
    if (Objects.isNull(cache) || getCacheAccessToken(key).equals(WeChatConstant.TICKET_TOKEN)){
    Gson gson = new Gson();
    cache = CacheBuilder.newBuilder().expireAfterWrite(7100,TimeUnit.SECONDS).build();
    String accessToken = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+WeChatConstant.APPID +"&secret="+WeChatConstant.SECRET;
    String httpResult = getHttpResult(accessToken);
    AccessToken aT = gson.fromJson(httpResult, AccessToken.class);
    String signUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+aT.getAccess_token()+"&type=jsapi";
    String resultSign = getHttpResult(signUrl);
    TicketToken ticket = gson.fromJson(resultSign, TicketToken.class);
    cache.put(WeChatConstant.TICKET_TOKEN,ticket.getTicket());
    return ticket.getTicket();
    }else{
    return getCacheAccessToken(key);
    }
    }

    /**
    * token失效,返回key值
    *
    * @param key
    * @return
    * @throws ExecutionException
    */
    private static String getCacheAccessToken(String key) throws ExecutionException {
    return cache.get(key, () -> {
    return key;
    });
    }

    /**
    * 随机加密
    * @param hash
    * @return
    */
    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 getHttpResult(String url) {
    String result = "";
    HttpGet httpRequest = new HttpGet(url);
    try {
    HttpResponse httpResponse = HttpClients.createDefault().execute(httpRequest);
    if (httpResponse.getStatusLine().getStatusCode() == 200) {
    result = EntityUtils.toString(httpResponse.getEntity());
    }
    } catch (ClientProtocolException e) {
    e.printStackTrace();
    result = e.getMessage().toString();
    } catch (IOException e) {
    e.printStackTrace();
    result = e.getMessage().toString();
    }
    return result;
    }
    /**
    * 产生随机串--由程序自己随机产生
    * @return
    */
    private static String create_nonce_str() {
    return UUID.randomUUID().toString();
    }
    /**
    * 由程序自己获取当前时间
    * @return
    */
    private static String create_timestamp() {
    return Long.toString(System.currentTimeMillis() / 1000);
    }

    第五步:返回数据给前端校验

    /**
    * 调用扫一扫 验证用户信息
    *
    * @param request
    * @return
    */
    @GetMapping("/signature")
    public WeChatEntity signature(HttpServletRequest request) throws Exception {
    Map<String, Object> resMap = new HashMap<String, Object>();
    resMap = SignatureUtil.sign(request.getRequestURL().);
    request.setAttribute("nonceStr", resMap.get("nonceStr"));
    request.setAttribute("timestamp", resMap.get("timestamp"));
    request.setAttribute("signature", resMap.get("signature"));
    request.setAttribute("appId", resMap.get("appId"));
    request.setAttribute("url", resMap.get("url"));
    request.setAttribute("jsapi_ticket",resMap.get("jsapi_ticket"));
    WeChatEntity weChatEntity = new WeChatEntity(
    resMap.get("appId").toString(),
    resMap.get("timestamp").toString(),
    resMap.get("nonceStr").toString(),
    resMap.get("signature").toString());
    return weChatEntity;
    }

    这里有个坑的地方就是url的设定,这是你请求当前页面的url,可以在前端使用

    location.href.split('#')[0]打印出来.看看是否符合.

     
    至此后端程序告一段落,下面就是前端程序了

    1.导入依赖

    <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
     

    html代码:

    <input type="button" value="扫一扫" id="scanQRCode">
     

    js代码:

    $(function() {
    $.get("/signature", function(data){
    alert(location.href.split('#')[0]);
    // alert(data.appId
    // +"======"+ data.timestamp
    // +"======"+data.nonceStr
    // +"======"+data.signature);
    //上面是查看传来的数据是否符合要求
    wx.config({
    // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    debug: false,
    // 必填,公众号的唯一标识
    appId: data.appId,
    // 必填,生成签名的时间戳
    timestamp: "" + data.timestamp,
    // 必填,生成签名的随机串
    nonceStr: data.nonceStr,
    // 必填,签名
    signature: data.signature,
    // 必填,需要使用的JS接口列表
    jsApiList: ['checkJsApi', 'scanQRCode']
    });
    });
    wx.error(function(res) {
    alert("出错了:" + res.errMsg); //这个地方的好处就是wx.config配置错误,会弹出窗口哪里错误,然后根据微信文档查询即可。
    });
    wx.ready(function() {
    wx.checkJsApi({
    jsApiList: ['scanQRCode'],
    success: function(res) {

    }
    });
    //点击按钮扫描二维码
    document.querySelector('#scanQRCode').onclick = function() {
    wx.scanQRCode({
    needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
    scanType: ["qrCode"], // 可以指定扫二维码还是一维码,默认二者都有
    success: function(res) {
    var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果

    alert("扫描结果:" + result);
    window.location.href = result; //因为我这边是扫描后有个链接,然后跳转到该页面
    }
    });
    };

    });
    });

    以上就是网上一些大佬还有结合 详细说明的官方文档,花费了一下午时间,踩了N个坑总结出来的,希望大家都可以完成功能,这样就可以开心的扫一扫啦,我先去扫一下了

     

    有问题可以一起沟通,交流哈

     

    放几个连接,大家可以参考下

    微信签名工具
    微信公众平台, config:invalid signature一直爆这个错误,求教如何解决?
     
    平凡是我的一个标签
  • 相关阅读:
    leetcode-----16. 最接近的三数之和
    leetcode-----15. 三数之和
    leetcode-----14. 最长公共前缀
    leetcode-----13. 罗马数字转整数
    leetcode-----12. 整数转罗马数字
    leetcode-----11. 盛最多水的容器
    leetcode-----10. 正则表达式匹配
    leetcode-----9. 回文数
    leetcode-----8. 字符串转换整数 (atoi)
    leetcode-----7. 整数反转
  • 原文地址:https://www.cnblogs.com/guyanzy/p/10363494.html
Copyright © 2020-2023  润新知