- 浏览: 115521 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
ron.luo:
干货,必须得顶。
JAXB使用经验总结 -
csdn_zuoqiang:
能否看下DWR的配置情况?谢谢
结合webservice实现dwr推送 -
友友水:
。。。。不好意思,无心之失,删不掉前一条评论
JAXB使用经验总结 -
友友水:
[/flash][/flash][/flash][/flash ...
JAXB使用经验总结 -
lihong11:
大哥,加加注释好不?看不懂唉
小玩dwr实现服务器推送
微信卡券的使用,是在之前的微信jsapi基础上,再加上一次卡券的单独验签,
这里对上篇微信JSSDK的使用稍作修改:
1. 微信的accessToken的获取有时间限制,之前是将token的读取放在一个单独的服务上, 单控
2.基于开个别的服务比较繁琐,现在使用redis缓存,来控制访问频率,至于并发,由锁来控制
代码如下:
package com.mazing.commons.wx; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.core.type.TypeReference; import com.mazing.commons.cache.redis.Redis; import com.mazing.commons.cache.redis.RedisLock; import com.mazing.commons.server.context.MainframeBeanFactory; import com.mazing.commons.utils.HttpClientUtils; import com.mazing.commons.utils.JsonUtils; import com.mazing.commons.utils.LogUtil; import com.mazing.commons.utils.cfg.EncryptionPropertyPlaceholderConfigurer; /** * access token 改为缓存读取方式,失效再读取 * * @author sky * */ public class KFwxAccessTokenReader { private static final Logger logger = LoggerFactory.getLogger(KFwxAccessTokenReader.class); /** * 获取间隔 */ private static final int INTERVAL = 2 * 60 ; // access token 在 7200秒过期, private static int TOKEN_TIMEOUT = 7200 - INTERVAL; private static String appid = null; private static String secret = null; /** * access token */ public String wxAccessToken = ""; /** * jsapi_ticket */ public String wxJsapiTicket = ""; /** * 卡券api_ticket */ public String wxCardApiTicket = ""; private static Redis redis; static { readConfig(); //clearCache(); } public static Map<String, String> readAccessToken() { Map<String, String> map = new HashMap<>(); String atKey = getJsAccessTokenCacheKey(); String accessToken = redis().get(atKey); String jsapiTicket = ""; String cardApiTicket = ""; if (StringUtils.isBlank(accessToken)) { accessToken = readToken(); jsapiTicket = readTicket(accessToken); cardApiTicket = readCardTicket(accessToken); logger.info("kf#wx#accessToken | cache为空,通过接口重新获取数据 | accessToken: {}, jsapiTicket: {},cardApiTicket: {}", LogUtil.hidePassport(accessToken), LogUtil.hidePassport(jsapiTicket), LogUtil.hidePassport(cardApiTicket)); } else { jsapiTicket = redis().get(getJsapiTicketCacheKey()); cardApiTicket = redis().get(getCardApiTicketCacheKey()); logger.info("kf#wx#accessToken | cache不为空, 获取缓存数据 | accessToken: {}, jsapiTicket: {},cardApiTicket: {}", LogUtil.hidePassport(accessToken), LogUtil.hidePassport(jsapiTicket), LogUtil.hidePassport(cardApiTicket)); } map.put(WeixinAccessToken.KF_ACCESS_TOKEN, accessToken); map.put(WeixinAccessToken.KF_JSAPI_TICKET, jsapiTicket); map.put(WeixinAccessToken.KF_CARD_API_TICKET, cardApiTicket); return map; } private static String getJsAccessTokenCacheKey() { return "KF_wxAccessTokenKey"; } /** * jsapi_ticket cache key * * @return */ private static String getJsapiTicketCacheKey() { return "KF_wxJSapiTicketKey"; } /** * 卡券 api_ticket cache key * * @return */ private static String getCardApiTicketCacheKey() { return "KF_wxCardApiTicketKey"; } public static void clearCache() { redis().del(getJsAccessTokenCacheKey()); redis().del(getJsapiTicketCacheKey()); redis().del(getCardApiTicketCacheKey()); logger.info("清除微信卡券相关缓存...."); } private static Redis redis() { if (null == redis) redis = (Redis) MainframeBeanFactory.getBean("redis"); return redis; } /** * 读取配置,只读一次 * * @throws Exception */ public static void readConfig() { appid = (String) EncryptionPropertyPlaceholderConfigurer.getConfig().get("kf_appid"); secret = (String) EncryptionPropertyPlaceholderConfigurer.getConfig().get("kf_appsecret"); } /** * 读取 access token */ private static String readToken() { RedisLock lock = new RedisLock(redis, "KFWxAccessTokenKey"); String wxAccessToken = ""; if (lock.lock()) { Map<String, String> params = new HashMap<>(4); params.put("grant_type", "client_credential"); params.put("appid", appid); params.put("secret", secret); String json = HttpClientUtils.doGet("https://api.weixin.qq.com/cgi-bin/token", 10000, params); if (StringUtils.isBlank(json)) { logger.error("读取微信 access token 错误"); } Map<String, Object> map = JsonUtils.parseObject(json.trim(), new TypeReference<Map<String, Object>>() { }); if (map.containsKey("access_token")) { wxAccessToken = (String) map.get("access_token"); logger.info("读取微信 access token 成功"); if (map.containsKey("expires_in")) { int expiresIn = ((Number) map.get("expires_in")).intValue(); logger.info("过期时间 (s):" + expiresIn); TOKEN_TIMEOUT = expiresIn - INTERVAL; // 缓存,并设置过期时间 redis().set(getJsAccessTokenCacheKey(), wxAccessToken, TOKEN_TIMEOUT); } } else { logger.error("读取微信 access token 错误:" + json); } lock.unlock(); } return wxAccessToken; } /** * 读取 jsapi_ticket */ private static String readTicket(String wxAccessToken) { String wxJsapiTicket = ""; Map<String, String> params = new HashMap<>(4); params.put("access_token", wxAccessToken); params.put("type", "jsapi"); String json = HttpClientUtils.doGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket", 10000, params); Map<String, Object> map = JsonUtils.parseObject(json.trim(), new TypeReference<Map<String, Object>>() { }); int errcode = -1; if (map.get("errcode") != null) { errcode = ((Number) map.get("errcode")).intValue(); logger.info("读取微信 jsapi_ticket 结果,errcode: {}, errmsg: {}", errcode, map.get("errmsg")); if (errcode == 0) { wxJsapiTicket = (String) map.get("ticket"); // set to cache redis().set(getJsapiTicketCacheKey(), wxJsapiTicket); logger.info("读取微信 jsapi_ticket 成功!"); } } else { logger.error("读取微信 jsapi_ticket 错误:" + json); } return wxJsapiTicket; } /** * 获取卡券 api_ticket */ private static String readCardTicket(String wxAccessToken) { String wxCardApiTicket = ""; Map<String, String> params = new HashMap<>(4); params.put("access_token", wxAccessToken); params.put("type", "wx_card"); String json = HttpClientUtils.doGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket", 10000, params); Map<String, Object> map = JsonUtils.parseObject(json.trim(), new TypeReference<Map<String, Object>>() { }); int errcode = -1; if (map.get("errcode") != null) { errcode = ((Number) map.get("errcode")).intValue(); logger.info("读取微信 卡券 api_ticket 结果,errcode: {}, errmsg: {}", errcode, map.get("errmsg")); if (errcode == 0) { wxCardApiTicket = (String) map.get("ticket"); // set to cache redis().set(getCardApiTicketCacheKey(), wxCardApiTicket); logger.info("读取微信 卡券 api_ticket 成功! ticket: {}", LogUtil.hidePassport(wxCardApiTicket)); } } else { logger.error("读取微信 卡券 api_ticket 错误:" + json); } return wxCardApiTicket; } }
util类
package com.mazing.mobile.web.kaifun; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mazing.CommonConstants; import com.mazing.commons.utils.JsonUtils; import com.mazing.commons.utils.LogUtil; import com.mazing.commons.utils.cfg.EncryptionPropertyPlaceholderConfigurer; import com.mazing.commons.utils.encrypt.EncryptUtil; import com.mazing.commons.wx.KFwxAccessTokenReader; import com.mazing.commons.wx.WeixinAccessToken; import com.mazing.core.web.ResultCode; import com.mazing.core.web.exception.ServiceException; /** * 对接公众号的微信平台 工具类(验签参数获取) * * @author sky 2016-05-57 * */ public class KaiFunWXUtil { private static final Logger logger = LoggerFactory.getLogger(KaiFunWXUtil.class); /** * 微信分享的attr */ public static final String WX_CONFIG_ATTR = "wxConfig"; /** * 开饭 微信appid */ private static String KF_WX_APPID = null; // 原始值 public static String KF_WX_CARDID = null; /** * 检查当前的请求是否是 https 的,如果不是则重定向成为https<br> * 如果执行了重定向,返回true */ public static boolean redirectFullUrl2Https(HttpServletRequest request, HttpServletResponse response) throws IOException { String params = request.getQueryString(); String url = request.getRequestURL().toString(); String scheme = request.getHeader("x-forwarded-proto"); boolean need2https = (url.startsWith("http://") // 如果是http的请求 && (StringUtils.isBlank(scheme) || !("https".equals(scheme))));// nginx上报的不是https协议 // 重定向请求为https,并返回true if (need2https) { url = url.replaceFirst("http://", "https://"); if (params != null) url += "?" + params; response.sendRedirect(url); return true; } return false; } /** * 返回当前页面完整的 URL,包括“?”后面的参数 * * @param request * @return */ public static String getFullUrl(HttpServletRequest request) { String params = request.getQueryString(); String url = request.getRequestURL().toString(); // nginx 的 upstream配置使用的是 http,导致外部是https的请求,来到代码却是http // nginx 会带上scheme参数(443端口才设置) String scheme = request.getHeader("x-forwarded-proto"); if (StringUtils.isNotBlank(scheme) && "https".equals(scheme)) url = url.replaceFirst("http://", "https://"); if (params != null) { url += "?" + params; } return url; } public static void main(String[] args) { String url = "http://xxx.com?callback=http://123.com"; System.out.println(url.replaceFirst("http", "https")); } /** * 微信公众号的appid * * @return */ private static String getWxMpAppId() { if (KF_WX_APPID == null) { KF_WX_APPID = (String) EncryptionPropertyPlaceholderConfigurer.getConfig().get("kf_appid"); } return KF_WX_APPID; } private static String getWxMpCardId() { if (KF_WX_CARDID == null) { KF_WX_CARDID = (String) EncryptionPropertyPlaceholderConfigurer.getConfig().get("kf_cardId"); } return KF_WX_CARDID; } /** * 微信分享的 config * * @param url 当前页面完整的地址,包括参数 * @return */ public static String getWxMpConfig(String url) { String noncestr = RandomStringUtils.random(16, CommonConstants.LETTER_NUMBER_CHARS); long timestamp = System.currentTimeMillis() / 1000; // 秒 String appId = getWxMpAppId(); Map<String, String> amap = KFwxAccessTokenReader.readAccessToken(); String jsapiTicket = amap.get(WeixinAccessToken.KF_JSAPI_TICKET); logger.info("mobile#share#getWxMpConfig | 设置微信分享配置 |url: {}, KF_JSAPI_TICKET: {}", url, LogUtil.hidePassport(jsapiTicket)); String sourceStr = "jsapi_ticket=" + jsapiTicket + "&noncestr=" + noncestr + "×tamp=" + timestamp + "&url=" + url; String signature = EncryptUtil.getSHA1(sourceStr).toLowerCase(); String[] jsApiList = new String[] { // "checkJsApi", // "onMenuShareTimeline", // "onMenuShareAppMessage",// "onMenuShareQQ",// "onMenuShareWeibo", // "onMenuShareQZone",// "hideAllNonBaseMenuItem",// "addCard",// "showAllNonBaseMenuItem" }; Map<String, Object> map = new HashMap<>(8); map.put("nonceStr", noncestr); map.put("timestamp", timestamp); map.put("appId", appId); map.put("signature", signature); map.put("debug", false); map.put("jsApiList", jsApiList); return JsonUtils.toJSONString(map); } /** * 获取卡券的签名 * * @return */ public static void setCardSignature(HttpServletRequest request) { long timestamp = System.currentTimeMillis() / 1000; // 秒 String cardId = getWxMpCardId(); String timeStr = timestamp + ""; Map<String, String> map = KFwxAccessTokenReader.readAccessToken(); String apiTicket = map.get(WeixinAccessToken.KF_CARD_API_TICKET); if (StringUtils.isBlank(apiTicket)) { throw new ServiceException(ResultCode.FAILURE, "系统繁忙, 请稍后再试"); } logger.info("kaifun#wx#signature | 验签参数 | cardId: {}, timestamp: {}, apiTicket: {}", cardId, timeStr, LogUtil.hidePassport(apiTicket)); List<String> list = new ArrayList<>(); list.add(timeStr); list.add(cardId); list.add(apiTicket); Collections.sort(list); String sourceStr = ""; for (Object obj : list) { sourceStr += obj; } String signature = EncryptUtil.getSHA1(sourceStr).toLowerCase(); //logger.info("kaifun#wx#signature | 验签参数排序后 | sourceStr: {}, signature: {}", sourceStr, signature); Map<String, Object> ext = new HashMap<>(); ext.put("timestamp", timeStr); ext.put("signature", signature); request.setAttribute("ext", JsonUtils.toJSONString(ext)); request.setAttribute("_cardid", KF_WX_CARDID); } /** * 设置微信分享JSSDK 需要的config配置信息<br> * * 凡是需要设置分享操作菜单(分享至朋友圈、QQ、微博, 或者屏蔽分享功能,只保留设置字体、刷新 等 菜单) 相关的页面, 都需要调用该方法进行config设置 * * @param model * @param request * @author sky 2016-04-19 */ public static void setWxJsConfig(HttpServletRequest request) { // 微信相关的内容 String url = getFullUrl(request); request.setAttribute(WX_CONFIG_ATTR, getWxMpConfig(url)); setCardSignature(request); } }
controller下发
package com.mazing.mobile.web.kaifun; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/open/wx/card") public class KFCardController { @RequestMapping("obtain/index") public String searchIndex(Model model, HttpServletRequest request) { // 微信相关的内容 KaiFunWXUtil.setWxJsConfig(request); return "/open/kaifun/obtain_index"; } }
jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> <script type="text/javascript"> // 微信分享的配置 wx.config(<c:out value="${wxConfig}" escapeXml="false"/>); wx.error(function(res) { //alert(JSON.stringify(res)); }); /** http://www.xiaomeiti.com/note/3561 **/ function WeixinShare(shareData) { this.shareData = shareData; if (wx && wx.checkJsApi) { this.shareType = "api"; this.initByAPI(); } else { this.shareType = "bridge"; this.initByBridge(); } } WeixinShare.prototype.initByAPI = function() { var me = this; wx.ready(function() { document.querySelector('#addCard').onclick = function () { wx.addCard({ cardList: [ { cardId: '${_cardid}', cardExt: '<c:out value="${ext}" escapeXml="false"/>' } ], success: function (res) { alert('已添加卡券:' + JSON.stringify(res.cardList)); } }); }; /* */ var shareData = { title : me.getParam("title"), desc : me.getParam("desc"), link : me.getParam("link"), imgUrl : me.getParam("imgUrl"), trigger : function(res) { /* this.title = me.getParam("title"); this.desc = me.getParam("desc"); this.link = me.getParam("link"); this.imgUrl = me.getParam("imgUrl"); */ } }; wx.onMenuShareAppMessage(shareData); var shareData2 = { title : me.getParam("title"), desc : me.getParam("desc"), link : me.getParam("link"), imgUrl : me.getParam("imgUrl"), trigger : function(res) { } }; var timelineTitle = me.getParam("timelineTitle"); if (timelineTitle) { shareData2.title = timelineTitle; } wx.onMenuShareTimeline(shareData2);//分享朋友圈 wx.onMenuShareQQ(shareData);//分享至QQ wx.onMenuShareWeibo(shareData);//分享到微博 wx.onMenuShareQZone(shareData);//分享到QZone //这里调用show all,是因为其他页面可能会调用了hide all(貌似是全局生效) 后跳转至 需要show all的页面 //wx.showAllNonBaseMenuItem({ // success : function() { // //MazingEnv.log('已显示所有非基本菜单项'); // } //}); }); }; WeixinShare.prototype.initByBridge = function() { var me = this; document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() { window.alert('Bridge triggered.'); WeixinJSBridge.on('menu:share:appmessage', function(argv) { me.shareFriend() }); WeixinJSBridge.on('menu:share:timeline', function(argv) { me.shareTimeline() }); }, false); }; WeixinShare.prototype.getParam = function(name) { var val = this.shareData[name]; if (typeof val == "function") { return val(); } return val; }; WeixinShare.prototype.shareFriend = function() { WeixinJSBridge.invoke('sendAppMessage', { appid : this.getParam("appid"), img_url : this.getParam("imgUrl"), img_width : 120, img_height : 120, link : this.getParam("link"), title : this.getParam("title"), desc : this.getParam("desc") }, function(res) { _report('send_msg', res.err_msg); }); }; WeixinShare.prototype.shareTimeline = function() { WeixinJSBridge.invoke('shareTimeline', { appid : this.getParam("appid"), img_url : this.getParam("imgUrl"), img_width : 120, img_height : 120, link : this.getParam("link"), title : this.getParam("title"), desc : this.getParam("desc") }, function(res) { _report('timeline', res.err_msg); }); }; var wxApi = new WeixinShare(shareData); </script>
发表评论
-
http简易工具类
2018-09-21 09:20 456http简易工具类, 方便http调用 -
hibernate延迟加载 与 web应用 独立缓存架构的冲突
2013-04-26 11:03 1135延迟加载(Lazy Loading)是 ... -
jquery验证框架使用
2013-03-27 16:57 13241.使用jquery的表单验证框架,需要导入jquery的库文 ... -
结合webservice实现dwr推送
2012-08-22 13:26 5323情景: 客户端需要实时提醒服务,比如某个日程已过期的提醒, ... -
copy到粘贴板
2012-05-22 11:39 1183直接上代码,实现了IE和火狐下的copy content ... -
webService使用总结
2012-04-28 15:08 1270webService 是什么就不解释了,webservice有 ... -
小玩dwr实现服务器推送
2012-01-19 17:01 5607最近项目有需要用到‘推’,就是服务器端自动把消息推给客户端,就 ... -
jquery之事件error小提醒
2011-12-13 15:27 1418今天用到jquery的事件中的error方法,发现当标签img ... -
小想法
2011-10-17 16:48 0刚才有个想法,不知道是由什么联想而来,最近淘宝大战,看了些文章 ... -
原来这个如此容易 ---- 点击弹出确认框
2011-10-12 15:51 1302今天无意识的看到了点击按钮弹出确认框的 javascri ... -
groovy 小应用
2011-09-30 10:25 1184昨天使用groovy脚本生成大量的sql,实在是爽! 现 ... -
JAXB使用经验总结
2011-09-27 11:13 9242使用JAXB首先要知道它是干什么的 当然,切入正题 ... -
Jquery资料链接(供学习)
2011-08-08 17:16 697提供些资料链接,以备查找 http://jquery.com ... -
dwr使用小结
2011-08-05 15:32 1118很久没上来冒泡了 ,把dwr的使用经验搁上来,以后备用。 ... -
实践中filter的配置
2011-04-26 09:23 895配置一个权限filter,拦截一切没有登录却想访问只有登录后才 ... -
JSTL问题解决之-->报找不到C标签
2011-03-30 13:51 3086当jsp页面显示报找不到C:标签时的解决办法 在li ... -
jsp之自定义标签
2011-03-29 11:09 884http://javakeith.iteye.com/blog ... -
jsp之session对象
2011-03-29 11:06 880http://javakeith.iteye.com/blo ... -
jsp内置对象
2011-03-29 11:04 1007感谢兄弟的总结 http://javakeith.iteye. ... -
JSTL自定义标签过程
2011-03-29 10:39 7311要定义自己的标签,首先写个java类,extends TagS ...
相关推荐
该微信Jssdk调用的demo采用三层架构,并使用数据库来缓存全局jsapi_ticket,避免调用超出次数,内仅含微信分享给朋友以及分享至朋友圈两个接口的调用。内含数据库sql文件以及使用文档,代码中也有详细的注释,简单易懂...
微信JSSDK是微信为微信网页开发提供的一套API接口,可以让网页支持微信分享、微信支付等功能,增强用户的互动体验。下面将详细说明如何在Vue中使用微信JSSDK,通过实例代码来介绍配置过程中的关键步骤,以及需要注意...
微信开发入门教程 jssdk,通过config接口注入权限验证配置java+jsp微信开发教程,功能:扫描二维码,拍照、本地选图,图片预览,上传图片,下载图片,获取当前网络状态,查看地理位置,获取当前地理位置打开地图,...
//微信上传下载媒体文件 // 这里不能加上s,不然保存不了amr文件 $url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token={$access_token}&media;_id={$media_id}"; ffmpeg下载地址 ...
由于微信jssdk文档经常升级变动,不保证本实例能正常运行,只供参考。 本实例只支持PHP运行,其它语言可以作参考。
微信jssdk支付代码包,微信最新发布的微信支付jssdk功能。
用于记录接入微信JS-SDK的坑,以后方便查询 第一次接入公众号微信支付、分享、定位等等的坑的时候,心里是迷茫而又恐惧。因为,听说坑特别多,后来发现自己的亲身体验到了这一点。 支付的坑 1、当前URL未注册 问题:...
用户长按录音,松手后直接结束录音,结束录音后,用户可以选择重新录音、播放刚才的录音,上传录音(这里的上传录音指上传到自己服务器,上传步骤是,前端调用wx.uploadVoice,后台再到微信服务器下载音频文件,上传...
微信JSSDK(JavaScript SDK)是微信为开发者提供的一个强大工具集,主要用于在网页中集成微信的功能,如分享、支付、扫码等。PHP版的JSSDK则为PHP后端开发者提供了与微信服务器交互的接口,以便获取和验证微信用户的...
11、微信卡券 (微信认证) 12、微信支付(服务号必须通过微信认证) 作者:Javen205 链接:http://www.jianshu.com/p/bb88f7520b9e 來源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明...
微信JSSDK调用扫一扫功能别一维码二维码。适用各种微信内页面需要调用扫一扫功能的项目,需要认证的服务号作授权设置。
微信jssdk拍照
自己对企业微信jssdk做的一个封装,集成了vConsole和weui,可以方便的获取当前页面的入口环境信息: isWechat //是否微信浏览器 isLoading //是否在loading状态 vConsole //vConsole对象 context //当前页面...
微信JSSDK(JavaScript Software Development Kit)是微信官方推出的一款用于网页端的开发工具包,主要目的是方便开发者在网页上实现微信相关的功能,比如分享、支付、多媒体处理等。通过集成JSSDK,开发者可以更好...
微信获取jssdk例子JAVA例子生成sign签名(MD5格式) 校验sign
该代码已修改为thinkphp控制器,可以直接放在前台进行使用,其他框架请自行参照相关规则进行修改
官方没有asp的demo,弄了个asp版的微信jssdk
微信的分享功能,分享的时候有图片,自己做的一个demo,以后用到时候可以拿出来观看,适合初学者,自己亲测可以实现,有一个坑的地方自己的微信公众号是否有分享权限,没有怎么试都是失败的
微信JSSDK是微信为开发者提供的一套JavaScript接口库,允许开发者在网页中调用微信的功能,如分享、扫一扫、支付等,增强用户体验。 微信JSSDK的使用首先需要注册成为微信开发者,并获取到AppID和AppSecret。AppID...