/**
* @description: 微信接口
**/
@Component
@Slf4j
@RefreshScope
public class WeChatTemplate {
@Value("${wx.appid:wxxxxxxcfaa}")
private String appid;
@Value("${wx.secret:2xxxx98fb5f1axxxx99c4xx0}")
private String secret;
@Value("${wx.message.templateId}")
private String templateId;
@Value("${wx.message.url}")
private String url;
@Autowired
private RedisTemplate redisTemplate;
public static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
public static final String USERS_URL = "https://api.weixin.qq.com/cgi-bin/user/get";
public static final String MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";
public static final String USER_INFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info";
public static final String OPRNID_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";
public static final String ACCESS_TOKEN_CACHE = "wx:token";
public String getOpenId(String code) {
Map<String, Object> params = new HashMap<>(8);
params.put("appid", appid);
params.put("secret", secret);
params.put("code", code);
params.put("grant_type", "authorization_code");
String access = HttpUtil.get(OPRNID_URL, params);
log.debug("wx access_token {}", access);
return (String) JSON.parseObject(access).get("openid");
}
public String getAccessToken() {
String token = (String) redisTemplate.opsForValue().get(ACCESS_TOKEN_CACHE);
if (token != null) {
return token;
}
String result = HttpUtil.get(ACCESS_TOKEN_URL, Map.of("grant_type", "client_credential",
"appid", appid,
"secret", secret));
token = (String) JSON.parseObject(result).get("access_token");
if (ObjectUtil.isNull(token)) {
throw new FrameworkException(JSON.parseObject(result).get("errcode").toString());
}
redisTemplate.opsForValue().set(ACCESS_TOKEN_CACHE, token, Long.valueOf(JSON.parseObject(result).get("expires_in").toString()) - 10, TimeUnit.SECONDS);
return token;
}
public WxUsers getWxUsers(String nextOpenId) {
String accessToken = getAccessToken();
Map<String, Object> param = Map.of("access_token", accessToken);
if (StringUtils.isNotEmpty(nextOpenId)) {
param.put("next_openid", nextOpenId);
}
String result = HttpUtil.get(USERS_URL, param);
return JSON.parseObject(result, WxUsers.class);
}
public WxUserInfo getWxUserInfo(String openId) {
String accessToken = getAccessToken();
Map<String, Object> param = Map.of("access_token", accessToken, "openid", openId, "lang", "zh_CN");
String result = HttpUtil.get(USER_INFO_URL, param);
log.debug(result);
return JSON.parseObject(result, WxUserInfo.class);
}
public void pushMessage(String openId, Map data) {
String accessToken = getAccessToken();
Map<String, Object> param = new HashMap<>();
param.put("touser", openId);
param.put("template_id", templateId);
param.put("url", url + (String) data.get("id"));
param.put("data", data);
String result = HttpUtil.post(MESSAGE_URL + accessToken, JSON.toJSONString(param));
log.debug(result);
}
@Async
public void pushMessageAllUsers(Map data) {
log.info("发送开播提醒开始!");
WxUsers wxUsers = getWxUsers(null);
List<String> openIds = wxUsers.getData().get("openid");
if (StringUtils.isEmpty(wxUsers.getErrcode())) {
int total = wxUsers.getTotal();
String nextOpenId = wxUsers.getNextOpenid();
if (total > 10000) {
while (total > 10000) {
WxUsers users = getWxUsers(nextOpenId);
openIds.addAll(wxUsers.getData().get("openid"));
nextOpenId = users.getNextOpenid();
total = total - 10000;
}
}
}
if (CollectionUtils.isNotEmpty(openIds)) {
openIds.parallelStream().forEach(openId -> {
pushMessage(openId, data);
});
}
log.info("发送开播提醒结束!");
}
public static final String TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
public Map jsSDKConfig(String webUrl) {
String result = HttpUtil.get(TICKET_URL, Map.of("access_token", getAccessToken(), "type", "jsapi"));
String ticket = (String) JSON.parseObject(result).get("ticket");
Map<String, String> ret = new HashMap<String, String>();
String nonceStr = createNonceStr();
String timestamp = createTimestamp();
String data;
String signature = "";
// 注意这里参数名必须全部小写,且必须有序
data = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + webUrl;
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(data.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
} catch (Exception e) {
}
ret.put("jsapi_ticket", ticket);
ret.put("nonceStr", nonceStr);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
ret.put("appid", appid);
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 createNonceStr() {
return UUID.randomUUID().toString();
}
// 生成时间戳
private static String createTimestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}