Web端调用微信sdk扫一扫功能
常见问题
- 没有调用成功摄像头?
/*
* 我们使用的是wxsdk,那自然是只有在微信中才能打开喽。你要是在浏览器上打开那怎么调用摄像头(很蠢,自己一开始是在浏览器上测试的)
* 另外看一下自己是否成功的鉴权了。如果密钥没错的话那就没问题
* 另外注意参数的大小写问题哦
*/
准备工作
- 微信公众号订阅号即可 绑定自己的域名(JS接口安全域名),添加IP白名单、获取AppSecret
- 在Java后端写一些Utils去向微信发送请求,以达到鉴权获取 ticket
后端代码
public static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";// 获取access_token
public static final String TICKET_URL = " https://api.weixin.qq.com/cgi-bin/ticket/getticket";// 拿到token以后获取ticket
获取签名的接口
package com.ruoyi.system.service.impl;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.Constants;
import com.ruoyi.common.utils.SendToWxUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Component("JsApiService")
@Transactional
public class JsApiService {
@Autowired
private RedisCache redisCache;
/**
* 获取签名
*
* @param url
* @return
*/
public Map<String, String> sign(String url) {
Map<String, String> resultMap = new HashMap<>(16);
//这里的jsapi_ticket是获取的jsapi_ticket。
//String ticket = this.getJsApiTicket();
String ticket = null;
Object object = redisCache.getCacheObject("ticket");
if (object != null) {
ticket = object.toString();
} else {
HashMap<String, String> resMap = SendToWxUtils.getTicket();
ticket = resMap.get("ticket");
redisCache.setCacheObject("ticket", ticket);
redisCache.expire("ticket", 2, TimeUnit.HOURS);
}
System.err.println("###########读取ticket:" + ticket);
//这里签名中的nonceStr要与前端页面config中的nonceStr保持一致,所以这里获取并生成签名之后,还要将其原值传到前端
String nonceStr = createNonceStr();
//nonceStr
String timestamp = createTimestamp();
String string1;
String signature = "";
//注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + ticket +
"&noncestr=" + nonceStr +
"×tamp=" + timestamp +
"&url=" + url;
System.out.println("string1:" + 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();
}
resultMap.put("url", url);
resultMap.put("jsapi_ticket", ticket);
resultMap.put("nonceStr", nonceStr);
resultMap.put("timestamp", timestamp);
resultMap.put("signature", signature);
resultMap.put("appId", Constants.APPID);
System.err.println("###########打印resultMap:" + resultMap.get("jsapi_ticket") + "," + resultMap.get("url"));
return resultMap;
}
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 createNonceStr() {
return UUID.randomUUID().toString();
}
private static String createTimestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}
后端向微信发送请求获取Token、等参数的Utils
package com.ruoyi.common.utils;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.redis.RedisCache;
import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
public class SendToWxUtils {
@Resource
RedisCache redisCache;
public static String getAccessToken() {
String param = String.format("appid=%s&secret=%s&grant_type=%s", Constants.APPID, Constants.SECRET, Constants.GRANT_TYPE);
String res = sendGet(Constants.TOKEN_URL, param);
JSONObject obj = JSONObject.parseObject(res);
String accessToken = obj.getString("access_token");
System.err.println("accessToken-->" + accessToken);
return obj.getString("access_token");
}
public static HashMap<String, String> getTicket() {
String accessToken = getAccessToken();
String param = String.format("access_token=%s&type=jsapi", accessToken);
String res = sendGet(Constants.TICKET_URL, param);
JSONObject parsed = JSONObject.parseObject(res);
String ticket = parsed.getString("ticket");
HashMap<String, String> resMap = new HashMap<>();
resMap.put("ticket", ticket);
return resMap;
}
public static String sendGet(String url, String param) {
StringBuilder result = new StringBuilder();
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
URL realUrl = new URL(urlNameString);
URLConnection connection = realUrl.openConnection();
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
} catch (ConnectException e) {
System.err.println("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param + e);
} catch (SocketTimeoutException e) {
System.err.println("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param + e);
} catch (IOException e) {
System.err.println("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param + e);
} catch (Exception e) {
System.err.println("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param + e);
} finally {
try {
if (in != null) {
in.close();
}
} catch (Exception ex) {
System.err.println("调用in.close Exception, url=" + url + ",param=" + param + ex);
}
}
return result.toString();
}
public static void main(String[] args) {
String param = String.format("appid=%s&secret=%s&grant_type=%s", Constants.APPID, Constants.SECRET, Constants.GRANT_TYPE);
String res = sendGet(Constants.TOKEN_URL, param);
JSONObject obj = JSONObject.parseObject(res);
String accessToken = obj.getString("access_token");
String param2 = String.format("access_token=%s&type=jsapi", accessToken);
String res2 = sendGet(Constants.TICKET_URL, param2);
JSONObject parsed = JSONObject.parseObject(res2);
String ticket = parsed.getString("ticket");
System.err.println(accessToken);
System.err.println(ticket);
}
}
一些静态常量
package com.ruoyi.common.utils;
public class Constants {
public static final String GRANT_TYPE = "client_credential";
public static final String APPID = "你自己的APPID ";
public static final String SECRET = "你自己的SECRET ";
public static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
public static final String TICKET_URL = " https://api.weixin.qq.com/cgi-bin/ticket/getticket";
}
前端调用接口
@PostMapping("/getSign")
public AjaxResult getSign(@RequestBody String url) {
Map<String, String> sign = jsApiService.sign(url);
return AjaxResult.success(sign);
}
前端代码
这里我使用的是Vue,先安装 weixin-js-sdk,pip install即可。
考虑到Android和IOS适配我们需要写一个Config.js
/*
* 判断是否IOS环境
* */
//自己封装的请求方法
import wx from "weixin-js-sdk";
import { getSign } from '@/api/system/tab'
export function isIOS() {
let isIphone = navigator.userAgent.includes("iPhone");
let isIpad = navigator.userAgent.includes("iPad");
return isIphone || isIpad;
}
/*
* 获取微信签名,注入权限验证配置
* 这里我用到的是微信扫一扫功能。所以jsApiList: ['checkJsApi', 'scanQRCode']就写了这么多
* 具体用到的什么功能向里边添加即可
* 可以参考Weixin官网提供的一些接口 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html
*/
export function requestWxStr() {
getSign({ url: window.location.href.split('#')[0] }).then(res => {
console.log('获取签名信息成功', res)
wx.config({
debug: false,
appId: res.data.appId,
timestamp: res.data.timestamp,
nonceStr: res.data.nonceStr,
signature: res.data.signature,
jsApiList: ['checkJsApi', 'scanQRCode']
})
}).catch(error => {
console.log('获取签名信息失败', error)
})
wx.ready(() => {
wx.checkJsApi({
jsApiList: ['scanQRCode'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
success: function(res) {
alert("扫一扫准备就绪")
}
})
})
}
在Vue组件中使用,这里我用到的是微信扫一扫功能
import wx from 'weixin-js-sdk'
methods: {
init() {
if (!isIOS()) {
requestWxStr()
}
},
scanBarCode(row, col) {
var that = this
this.scanData.rowNumber = row
this.scanData.columnNumber = col
wx.scanQRCode({
needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
scanType: ['barCode'], // 可以指定扫二维码还是一维码,默认二者都有
success: function(res) {
const parts = res.resultStr.split(',')
// 提取条形码值
that.scanData.content = parts[1]
that.isOpen = true
},
error: function(res) {
alert('识别error')
}
}
)
},
然后就没有然后了,就搞定了。注意需要发布到线上才能测试,可以打印一些log测试。alert(xxx);