微信JSSDK 使用

获取微信JSAPI_TICKET


package com.mazing.wx;

import com.fasterxml.jackson.core.type.TypeReference;
import com.mazing.CommonConstants;
import com.mazing.commons.utils.HttpClientUtils;
import com.mazing.commons.utils.JsonUtils;
import com.mazing.commons.utils.cfg.DesPropertiesEncoder;
import com.mazing.core.remote.config.Config;
import com.mazing.core.web.RestResult;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 读取微信 access token 的线程
*
*/
public class WxAccessTokenReaderThread extends Thread {

private static final Logger logger = LoggerFactory.getLogger(WxAccessTokenReaderThread.class);

private boolean running = true;

/**
* 获取间隔
*/
private static final int INTERVAL = 2 * 60 * 1000;

// access token 在 7200秒过期,
private long TOKEN_TIMEOUT = 7200 * 1000L - INTERVAL;

private long lastReadTime = 0L;

private String appid = null;

private String secret = null;

/**
* access token
*/
static volatile String wxAccessToken = "";

/**
* jsapi_ticket
*/
static volatile String wxJsapiTicket = "";

public WxAccessTokenReaderThread() {
super("WxAccessTokenReaderThread");
}

public void stopRunning() {
running = false;
interrupt();
}

@Override
public void run() {
logger.info("WxAccessTokenReaderThread started ...");
if (!readConfig()) {
logger.error("读取配置错误,线程结束,请配置 group=weixin_mp 的内容。 ");
running = false;
}
while (running) {
long now = System.currentTimeMillis();
if (now - lastReadTime >= TOKEN_TIMEOUT) {
try {
readToken();
readTicket();

lastReadTime = now;
} catch (Exception e) {
logger.error("读取微信 access token / jsapi ticket 错误", e);
}
}
try {
sleep(INTERVAL);
} catch (InterruptedException e) {
break;
}
}
logger.info("WxAccessTokenReaderThread stopped ...");
}

/**
* 读取配置,只读一次
* @throws Exception
*/
public boolean readConfig() {
String json = HttpClientUtils.doGet(CommonConstants.CONFIG_DOMAIN + "/api/base/allConfigs");
// logger.info("wx#readConfig | http response | result: {}", json.substring(0, 10) + "***");
RestResult<List<Config>> result = JsonUtils.parseObject(json, new TypeReference<RestResult<List<Config>>>() {
});

if (!(result.isSuccess())) {
logger.warn("wx#readConfig#Failure | Failure Request | result: {}", json);
return false;
}

final String groupCode = "weixin_mp";
DesPropertiesEncoder decoder = new DesPropertiesEncoder();
int found = 0;
for (Config config : result.getObject()) {
if (groupCode.equals(config.getGroupCode())) {
if ("appid".equalsIgnoreCase(config.getConfigKey())) {
appid = decoder.decode(config.getConfigValue());
found++;
}
else if ("secret".equalsIgnoreCase(config.getConfigKey())) {
secret = decoder.decode(config.getConfigValue());
found++;
}
}
if (found >= 2) break;
}
return found >= 2;
}
/**
* 读取 access token
*/
private void readToken() {
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 * 1000L - INTERVAL;
if (TOKEN_TIMEOUT < 1000) {
TOKEN_TIMEOUT = 10 * 60 * 1000L - INTERVAL;
}
}

}
else {
logger.error("读取微信 access token 错误:" + json);
}
}

/**
* 读取 jsapi_ticket
*/
private void readTicket() {
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");
logger.info("读取微信 jsapi_ticket 成功!");
}
}
else {
logger.error("读取微信 jsapi_ticket 错误:" + json);
}
}
}






package com.mazing.commons.wx;

import com.mazing.cfg.GlobalSetting;
import com.mazing.commons.utils.HttpClientUtils;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* 获取微信 access token。
* 文档见:http://mp.weixin.qq.com/wiki/15/54ce45d8d30b6bf6758f68d2e95bc627.html
* 接口:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
* 每天最多 2000 次
* @
*/
public class AccessTokenCollector extends Thread {

private static final Logger logger = LoggerFactory.getLogger(AccessTokenCollector.class);
// true:不需要读取wx token(线程直接结束)
private final boolean skip = Boolean.parseBoolean(GlobalSetting.getSysCongfig("noTokenWX"));

private boolean stopped = false;

/**
* 间隔
*/
private static final int INTERVAL = 2 * 60 * 1000;

// 读取 access token 的地址
public static final String URL = "http://123.40.50.60:20090/";

public AccessTokenCollector() {
super("accessTokenCollector");
}

public void stopRunning() {
this.stopped = true;
interrupt();
}

@Override
public void run() {
if (skip) {
logger.info("mobile#wx#AccessTokenCollector | 不需要读取微信公众号Token信息");
return;
}

logger.info("mobile#wx#AccessTokenCollector | 读取微信公众号 token 线程启动 ...");
while (!stopped) {

try {
String str = HttpClientUtils.doGet(URL);
str = StringUtils.trimToEmpty(str);
if (StringUtils.isNotEmpty(str)) {
String[] array = str.split("\\|");
WeixinAccessToken.ACCESS_TOKEN = array[0];
WeixinAccessToken.JSAPI_TICKET = array[1];
logger.info("mobile#wx#AccessTokenCollector | 读取微信公众号 token 成功");
} else {
logger.error("mobile#wx#AccessTokenCollector | 读取微信公众号 token 出错,没有结果");
}
} catch (Exception e) {
logger.error("mobile#wx#AccessTokenCollector | 出错", e);
}

try {
Thread.sleep(INTERVAL);
} catch (InterruptedException e) {
// ignore
break;
}
}
logger.info("mobile#wx#AccessTokenCollector | 读取微信公众号 token 线程结束 ...");
}
}




微信JSSDK签名 数据


package com.mazing.mobile.web.utils;

import java.io.IOException;
import java.util.HashMap;
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.cfg.DesPropertiesEncoder;
import com.mazing.commons.utils.encrypt.EncryptUtil;
import com.mazing.commons.wx.WeixinAccessToken;
import com.mazing.core.remote.config.ConfigGroupConstants;
import com.mazing.core.remote.config.ConfigRemoteService;

/**
* 微信分享的工具类
*
*
*/
public class WeiXinHelper {
private static final Logger logger = LoggerFactory.getLogger(WeiXinHelper.class);

/**
* 微信分享的attr
*/
public static final String WX_CONFIG_ATTR = "wxConfig";

/**
* 微信appid
*/
private static String WX_APPID = null;

// /**
// * 用户的请求是否是https的(进入到nginx的是否是https)(nginx upstream是http)
// */
// public static boolean httpsFromNginx(HttpServletRequest request) {
// String url = request.getRequestURL().toString();
// String scheme = request.getHeader("x-forwarded-proto");
// return (url.startsWith("https://") || (StringUtils.isNotBlank(scheme)) && "https".equals(scheme));
// }

/**
* 检查当前的请求是否是 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 (WX_APPID == null) {
String encryptedId = ConfigRemoteService.getConfig(ConfigGroupConstants.WEIXIN_WP, "appid");
if (encryptedId != null) {
try {
DesPropertiesEncoder decoder = new DesPropertiesEncoder();
WX_APPID = decoder.decode(encryptedId);
} catch (Exception e) {
logger.error("mobile#share#getWxMpAppId | 解密 appid 出错", e);
}
} else {
logger.error("mobile#share#getWxMpAppId | 没有配置 group_code: {} config_key: {} !!", ConfigGroupConstants.WEIXIN_WP, "appid");
}
}
return WX_APPID;
}

/**
* 微信分享的 config
*
* @param url 当前页面完整的地址,包括参数
* @return
*/
public static String getWxMpConfig(String url) {
String noncestr = RandomStringUtils.random(16, CommonConstants.LETTER_NUMBER_CHARS);
long timestamp = System.currentTimeMillis() / 1000; // 秒
logger.info("mobile#share#getWxMpConfig | 设置微信分享配置 |url: {}", url);
String appId = getWxMpAppId();
String sourceStr = "jsapi_ticket=" + WeixinAccessToken.JSAPI_TICKET + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url="
+ url;

String signature = EncryptUtil.getSHA1(sourceStr).toLowerCase();
String[] jsApiList = new String[] { //
"checkJsApi", //
"onMenuShareTimeline", //
"onMenuShareAppMessage",//
"onMenuShareQQ",//
"onMenuShareWeibo", //
"onMenuShareQZone",//
"hideAllNonBaseMenuItem",//
"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);
}

/**
* 设置微信分享JSSDK 需要的config配置信息<br>
*
* 凡是需要设置分享操作菜单(分享至朋友圈、QQ、微博, 或者屏蔽分享功能,只保留设置字体、刷新 等 菜单) 相关的页面, 都需要调用该方法进行config设置
*
* @param request
*
*/
public static void setWxJsConfig(HttpServletRequest request) {
// 微信相关的内容
String url = WeiXinHelper.getFullUrl(request);

request.setAttribute(WeiXinHelper.WX_CONFIG_ATTR, WeiXinHelper.getWxMpConfig(url));
}

}





页面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() {

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>




隐藏微信的分享功能


<%@ 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));
});

wx.ready(function() {
// 1 判断当前版本是否支持指定 JS 接口,支持批量判断
wx.checkJsApi({
jsApiList : [ 'hideAllNonBaseMenuItem' ],
success : function(res) {
MazingEnv.log('当前版本支持wx JS接口');
}
});

// 8.3 批量隐藏菜单项
/*
wx.hideMenuItems({
menuList: [
'menuItem:readMode', // 阅读模式
'menuItem:share:timeline', // 分享到朋友圈
'menuItem:copyUrl' // 复制链接
],
success: function (res) {
alert('已隐藏“阅读模式”,“分享到朋友圈”,“复制链接”等按钮');
},
fail: function (res) {
alert(JSON.stringify(res));
}
});
*/

// 8.5 隐藏所有非基本菜单项
wx.hideAllNonBaseMenuItem({
success : function() {
MazingEnv.log('已隐藏所有非基本菜单项');
}
});

});
</script>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值