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

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

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

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

首先配置自己的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 +"&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一直爆这个错误,求教如何解决?
 

调用微信的扫一扫功能详解说明---(java 排坑版)的更多相关文章

  1. Android通过外部浏览器调用微信H5支付,Android+PHP详解

    看了好多关于讲解微信H5支付开发的文章,大多数都是通过微信内部浏览器来调用支付接口(其实就是公众号支付),可能是因为H5支付接口刚开放不久吧. 微信官方体验链接:http://wxpay.wxutil ...

  2. JAVA调用微信接口实现页面分享功能(分享到朋友圈显示图片,分享给朋友)

    钉钉提供的内网穿透之HTTP穿透:https://www.cnblogs.com/pxblog/p/13862376.html 网页分享到微信中如何显示标题图,如果自定义标题图,描述,显示效果如下 官 ...

  3. JAVA生成(可执行)Jar包的全面详解说明 [打包][SpringBoot][Eclipse][IDEA][Maven][Gradle][分离][可执行]

    辛苦所得,转载还请注明: https://www.cnblogs.com/applerosa/p/9739007.html  得空整理了关于java 开发中,所有打包方式的 一个操作方法, 有基于ID ...

  4. 调用微信扫一扫功能,踩坑'invalid signature'

    在vue项目中,调用微信扫一扫功能,在安卓系统下完全正常,ios系统下却报错'invalid signature'的错误,这可能令许多小伙伴困惑,经过查询大量博客相关资料,才找到了解决的方法. 原因: ...

  5. .Net微信网页开发之使用微信JS-SDK调用微信扫一扫功能

    前言: 之前有个项目需要调用微信扫描二维码的功能,通过调用微信扫码二维码功能,然后去获取到系统中生成的二维码信息.正好微信JS-SDK提供了调用微信扫一扫的功能接口,下面让我们来看看是如何实现的吧. ...

  6. asp.net调用微信扫一扫功能

    1.页面引用http://res.wx.qq.com/open/js/jweixin-1.0.0.js 2.前台代码 function shaomiao() { wx.config({ debug: ...

  7. java实现微信扫一扫详解

    java实现微信扫一扫详解 一.微信JS-SDK参数配置及查找 JS安全域名配置(查找:微信公众号里-公众号设置-功能设置页) 注:1.安全域名外网必须可以访问的到  2.域名不能有下划线  3.要将 ...

  8. C#开发微信门户及应用(15)-微信菜单增加扫一扫、发图片、发地理位置功能

    前面介绍了很多篇关于使用C#开发微信门户及应用的文章,基本上把当时微信能做的接口都封装差不多了,微信框架也积累了不少模块和用户,最近发现微信公众平台增加了不少内容,特别是在自定义菜单里面增加了扫一扫. ...

  9. 微信JSSDK使用步骤(用于在微信浏览器中自定义分享,分享到朋友圈,拍照,扫一扫等功能)

    一.使用JSSDK需要一个公众号(需要认证!): (1).把自己项目的服务器地址输入. (2).把MP_verify_m7Qp93BAuIGDWRVO.txt  文件下载下来,放到该服务器域名指向的根 ...

随机推荐

  1. pyqt4手动编写资源文件

    资源文件resource.qrc为XML格式,格式较简单,可以手动编辑: <!DOCTYPE RCC><RCC version="1.0"> <qre ...

  2. python基础类型—集合

    一,集合. 集合是无序的,不重复的数据集合,它里面的元素是可哈希的(不可变类型),但是集合本身是不可哈希(所以集合做不了字典的键)的.以下是集合最重要的两点: 去重,把一个列表变成集合,就自动去重了. ...

  3. 使用redis接管session

    class RedisSession { // 默认配置名称(使用load_config加载) private $_default_config_path = 'package/cache/redis ...

  4. 查看oracle数据库是否为归档模式

    查看oracle数据库是否为归档模式   [1]   1.select name,log_mode from v$database;   NAME LOG_MODE   --------------- ...

  5. 把html页面转化成图片——html2canvas

    test.html <div class="fx_zhezhao"></div> <div class="myImg"> & ...

  6. swust oj 1069

    图的按录入顺序广度优先搜索 5000(ms) 10000(kb) 2347 / 4868 Tags: 广度优先 图的广度优先搜索类似于树的按层次遍历,即从某个结点开始,先访问该结 点,然后访问该结点的 ...

  7. Codeforces 1090D - Similar Arrays - [思维题][构造题][2018-2019 Russia Open High School Programming Contest Problem D]

    题目链接:https://codeforces.com/contest/1090/problem/D Vasya had an array of n integers, each element of ...

  8. 理解linux 密码存储

    1. 传统上,linux把加密(哈希)的密码保存在/etc/passwd文件中,passwd文件的格式如下: smithj:x:561:561:Joe Smith:/home/smithj:/bin/ ...

  9. WebMagic

    一.WebMagic的四个组件 1.Downloader Downloader负责从互联网上下载页面,默认使用apache HttpClient作为下载工具 2.PageProcessor 负责解析页 ...

  10. ios dispatch_async使用

    一般这样使用: dispatch_async(dispatch_get_global_queue(0, 0),^{ //进入另一个线程 dispatch_async(dispatch_get_main ...