官方文档地址
https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html

1、先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

2、H5或Web项目下:

调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.6.0.js

3、Vue项目下:
3-1、安装

cnpm install weixin-jsapi --save

4、后台代码:

//以下为缓存使用的key值
/** 获取到的凭证 */
private static final String WX_ACCESS_TOKEN_KEY = "wxAccessTokenKey";
/** 凭证有效时间,单位:秒 */
private static final String WX_EXPIRES_IN_KEY = "wxExpiresInKey";
/** 获取凭证时的时间 */
private static final String WX_TOKEN_TIME_KEY = "wxTokenTimeKey";

/** 获取到的ticket */
private static final String WX_TICKET_KEY = "wxTicketKey";
/** ticket有效时间,单位:秒 */
private static final String WX_TICKET_EXPIRES_IN_KEY = "wxTicketExpiresInKey";
/** 获取ticket时的时间 */
private static final String WX_TICKET_TIME_KEY = "wxTicketTimeKey";

/**
 * 获取对应的access_token
 * @author lan
 * @since 2020-5-6
 * @url https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx10557a0b4df259ef&secret=fed31df017dc2b9db5b4530f9405ca60
 * @return {"access_token":"ACCESS_TOKEN","expires_in":7200}
 * @return {"errcode":40164,"errmsg":"invalid ip 192.168.0.1 ipv6
 *  :ffff:192.168.0.1, not in whitelist hint: [gtGupa07444814]"}
 */
private Map<String, Object> getAccessToken() {
	String appId = "申请的APPID";//平台配置的AppId
	String appSecret = "申请的AppSecret";//平台配置的AppSecret
	
	Map<String, Object> result = new HashMap<String, Object>();
	try {
		// 从缓存中读取
		if (null != redisService.getCodeVal(WX_ACCESS_TOKEN_KEY) && null != redisService.getCodeVal(WX_EXPIRES_IN_KEY) && !"".equals(redisService.getCodeVal(WX_ACCESS_TOKEN_KEY)) && !"".equals(redisService.getCodeVal(WX_EXPIRES_IN_KEY))) {
			long expirsIn = Long.valueOf(redisService.getCodeVal(WX_EXPIRES_IN_KEY).toString());
			long tokenTime = Long.valueOf(redisService.getCodeVal(WX_TOKEN_TIME_KEY).toString());
			long currentTime = new Date().getTime() / 1000;
			if ((currentTime - tokenTime) < expirsIn) {
				String accessToken = redisService.getCodeVal(WX_ACCESS_TOKEN_KEY).toString();
				if (!StringUtils.isBlank(accessToken)) {
					System.out.println("access_token为缓存取值:" + accessToken);
					result.put("success", true);
					result.put("accessToken", accessToken);
					return result;
				} else {
					System.out.println("access_token为缓存取值为空,立即接口取值");
				}
			}
		}

		if (!StringUtils.isBlank(appId) && !StringUtils.isBlank(appSecret)
				&& !StringUtils.isBlank(AccessTokenUrl)) {
			System.out.println("access_token为接口取值");
			long currentTime = new Date().getTime() / 1000;
			redisService.saveCode(WX_TOKEN_TIME_KEY, currentTime + "", 7200L);

			StringBuffer sb = new StringBuffer("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential");
			sb.append("&appid=").append(appId).append("&secret=").append(appSecret);
			String res = httpGet(sb.toString());
			if (!StringUtils.isBlank(res)) {
				JSONObject obj = JSONObject.parseObject(res);
				if (obj != null) {
					if (obj.get("access_token") != null) {
						result.put("success", true);
						result.put("accessToken", obj.get("access_token").toString());

						// 加入缓存
						redisService.saveCode(WX_ACCESS_TOKEN_KEY,obj.get("access_token").toString(), 7200L);
						redisService.saveCode(WX_EXPIRES_IN_KEY, obj.get("expires_in").toString(), 7200L);
					} else {
						result.put("success", false);
						result.put("accessToken", obj.get("errmsg"));
					}
				} else {
					result.put("success", false);
					result.put("accessToken", "操作失败");
				}
			} else {
				result.put("success", false);
				result.put("accessToken", "操作失败");
			}
		} else {
			result.put("success", false);
			result.put("accessToken", "操作失败");
		}
		return result;
	} catch (Exception e) {
		System.out.println("操作失败" + e);
		result.put("success", false);
		result.put("message", e.getMessage());
		return result;
	}
}

/**
 * 获取对应的jsapi_ticket
 * @author lan
 * @since 2020-5-6
 * @url https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
 * @return { "errcode":0, "errmsg":"ok","ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
 *         "expires_in":7200 }
 * @return {"errcode":40164,"errmsg":"invalid ip 192.168.0.1 ipv6
 *         ::ffff:192.168.0.1, not in whitelist hint: [gtGupa07444814]"}
 */
private String getJsapiTicket(String accessToken) {
	System.out.println("执行getJsapiTicket");
	try {
		// 从缓存中读取
		if (null != redisService.getCodeVal(WX_TICKET_KEY) && null != redisService.getCodeVal(WX_TICKET_EXPIRES_IN_KEY) && !"".equals(redisService.getCodeVal(WX_TICKET_KEY)) && !"".equals(redisService.getCodeVal(WX_TICKET_EXPIRES_IN_KEY))) {
			long expirsIn = Long.valueOf(redisService.getCodeVal(WX_TICKET_EXPIRES_IN_KEY).toString());
			long tokenTime = Long.valueOf(redisService.getCodeVal(WX_TICKET_TIME_KEY).toString());
			long currentTime = new Date().getTime() / 1000;
			if ((currentTime - tokenTime) < expirsIn) {
				String ticket = redisService.getCodeVal(WX_TICKET_KEY).toString();
				if (!StringUtils.isBlank(ticket)) {
					System.out.println("ticket为缓存取值:" + ticket);
					return ticket;
				} else {
					System.out.println("ticket为缓存取值为空,立即接口取值");
				}
			}
		}

		if (!StringUtils.isBlank(accessToken)) {
			System.out.println("ticket为接口取值");
			long currentTime = new Date().getTime() / 1000;
			redisService.saveCode(WX_TICKET_TIME_KEY, currentTime + "", 7200L);

			StringBuffer sb = new StringBuffer("https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card");
			sb.append("&access_token=").append(accessToken);
			String res = httpGet(sb.toString());
			if (!StringUtils.isBlank(res)) {
				JSONObject obj = JSONObject.parseObject(res);
				if (obj != null) {
					if (obj.get("ticket") != null && "0".equals(obj.get("errcode").toString())) {
						// 加入缓存
						redisService.saveCode(WX_TICKET_KEY, obj.get("ticket").toString(), 7200L);
						redisService.saveCode(WX_TICKET_EXPIRES_IN_KEY, obj.get("expires_in").toString(), 7200L);
						return obj.get("ticket").toString();
					} else {
						return null;
					}
				} else {
					return null;
				}
			} else {
				return null;
			}
		} else {
			return null;
		}
	} catch (Exception e) {
		System.out.println("操作失败" + e);
		return null;
	}
}

//提供一个供项目调用的接口
public ApiResult<Object> getJssdkSign(@RequestBody String jsonStr) {
	Map<String, Object> map = new LinkedHashMap<>();
	try {
		JSONObject jsonObject = JSON.parseObject(jsonStr);
		Map<String, Object> accessTokenMap = storeOrderService.getAccessToken();
		if (!Boolean.valueOf(accessTokenMap.get("success").toString())) {
			return ApiResult.fail(ApiCode.FAIL);
		} else {
			String appId = systemConfigService.getData(SystemConfigConstants.WECHAT_APPID);//平台配置的AppId
			String jsapiTicket = storeOrderService.getJsapiTicket(accessTokenMap.get("accessToken").toString());
			if (!StringUtil.isBlank(jsapiTicket)) {
				Map<String, String> ret = CreateWxSignUtil.getWxSign(jsapiTicket, jsonObject.getString("url").toString());
				map.put("appId", "wxff65c98dac9c8a2b");
				map.put("jsApiList",new String[] { "scanQRCode" });
				map.put("nonceStr", ret.get("nonceStr"));
				map.put("signature", ret.get("signature"));
				map.put("timestamp", ret.get("timestamp"));
				map.put("url", ret.get("url"));
			}
		}
	} catch (Exception e) {
		System.out.println("操作失败" + e);
	}
	return ApiResult.ok(map);
}

工具类

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

public class CreateWxSignUtil {
    public static Map<String, String> getWxSign(String jsapi_ticket, String url) {
        Map<String, String> ret = new HashMap<String, String>();
        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;
        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("jsapiTicket", 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);
    }
}

5、前端
5-1、使用

import wx from "weixin-jsapi";

5-2、配置

//自定义一个POST请求
export function getJssdkSign(data) {
  return request.post("http:127.0.0.1:8080/projectName/getJssdkSign", data);
}

//微信扫一扫调用sdk核心配置
let url = location.href.split("#")[0];//这里【url参数一定是去参的动态的当前页网址】
let params = {};
params.url = url;

getJssdkSign(params).then(res => {
  wx.config({
	// 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
	debug: false,
	// 必填,公众号的唯一标识
	appId: res.data.appId,
	// 必填,生成签名的时间戳
	timestamp: res.data.timestamp,
	// 必填,生成签名的随机串
	nonceStr: res.data.nonceStr,
	// 必填,签名
	signature: res.data.signature,
	// 必填,需要使用的JS接口列表,所有JS接口列表
	jsApiList: ["scanQRCode","checkJsApi", ......]
  });
  
  wx.ready(function(){
  // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
  });
  
  wx.error(function(res){
  // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
  });
});

//调起微信扫一扫
openQRCode: function() {
  let that = this;
  wx.scanQRCode({
	needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
	//scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
	success: function(res) {
	  let result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
	  if (result != null && result != "" && result != undefined) {
		//扫码结果
		//业务逻辑处理......
	  }
	}
  });
}

6、注意事项:
6-1、网上有说使用 “cnpm install weixin-js-sdk --save”,但我使用时出现-wx:undefined,后改用3-1即可,据了解微信提供了Vue环境下直接引用,未深究。

6-2、当出现 “config:invalid signature” 时,检查签名是否正确,可用官方提供的验签工具验证:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

6-3、签名时必须使用jsapi_ticket生成,生成签名时所需的URL必须为不包含#号的动态的本网页地址。

6-4、测试时需要使用服务器部署项目,使用nginx指向本地ip进行调试。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐