最近碰到了这么一个需求,说是在前端页面调用手机本地的相机,扫描二维码这么一个需求,对于我一个后端来说,
这实在是难,难于上青天,但是决不能说一个不字.我说可以使用微信的扫码工具吗,这样可以方便一点,...(起码有个思路)
看着微信文档,一步一步坑下去.不对,是走下去.
这里我们用测试是公众号,方便测试.
首先配置自己的appID和appsecret,这里的测试帐号直接就给出了
第二步: 验证服务器,这个很简单,按照文档的规则验证就好了
第三步: 直接使用二级域名,不能添加http://前缀,或者是/XXX你自己写的接口
这里还有个问题就是下载一个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 +"×tamp=" + 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个坑总结出来的,希望大家都可以完成功能,
这样就可以开心的扫一扫啦,我先去扫一下了
有问题可以一起沟通,欢迎加我微信沟通,共同学习:AA19941205
放几个连接,大家可以参考下
微信签名工具
微信公众平台, config:invalid signature一直爆这个错误,求教如何解决?
原文地址:https://www.cnblogs.com/guyanzy/p/10363494.html
时间: 2024-10-10 01:43:03