package com.ycwl.basic.utils; import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpUtil; import org.apache.commons.lang3.Strings; import java.util.HashMap; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.util.Date; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; public class WxMpUtil { private static final String GET_WXA_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacode?access_token=%s"; private static final String GET_WXA_CODE_UNLIMITED_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s"; private static final String GET_URL_LINK_URL = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=%s"; private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; private static final String STABLE_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/stable_token?grant_type=client_credential&appid=%s&secret=%s&force_refresh=false"; public static final String GET_USER_PHONE_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s"; private static final String MSG_SEC_CHECK_URL = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token=%s"; private static final Map tokens = new ConcurrentHashMap<>(); private static final Map expireTimes = new ConcurrentHashMap<>(); private static final ReentrantLock lock = new ReentrantLock(); private static String getAccessToken(String appId, String appSecret) { lock.lock(); try { if (expireTimes.containsKey(appId)) { Date expireTime = expireTimes.get(appId); if (expireTime.getTime() < System.currentTimeMillis()) { tokens.remove(appId); } } else { tokens.remove(appId); } return tokens.computeIfAbsent(appId, (k) -> { String token; if (!System.getProperty("os.name").toLowerCase().startsWith("win")) { String url = String.format(STABLE_ACCESS_TOKEN_URL, appId, appSecret); Map params = new HashMap<>(); params.put("grant_type", "client_credential"); params.put("appid", appId); params.put("secret", appSecret); params.put("force_refresh", false); String response = HttpUtil.post(url, JacksonUtil.toJSONString(params)); Map jsonObject = JacksonUtil.parseObject(response, Map.class); token = (String) jsonObject.get("access_token"); Date expireTime = new Date(System.currentTimeMillis() + ((Integer) jsonObject.get("expires_in")) * 1000 / 2); expireTimes.put(appId, expireTime); } else { String url = String.format(ACCESS_TOKEN_URL, appId, appSecret); String response = HttpUtil.get(url); Map jsonObject = JacksonUtil.parseObject(response, Map.class); token = (String) jsonObject.get("access_token"); Date expireTime = new Date(System.currentTimeMillis() + ((Integer) jsonObject.get("expires_in")) * 1000 / 2); expireTimes.put(appId, expireTime); } return token; }); } finally { lock.unlock(); } } public static void generateWXAQRCode(String appId, String appSecret, String envVersion, String path, String filePath) throws Exception { String url = String.format(GET_WXA_CODE_URL, getAccessToken(appId, appSecret)); Map json = new HashMap<>(); json.put("env_version", envVersion); json.put("path", path); json.put("width", 1000); try (HttpResponse response = HttpUtil.createPost(url).body(JacksonUtil.toJSONString(json)).header("Content-Type", "application/json").execute()) { if (response.getStatus() != 200) { throw new Exception("获取小程序二维码失败,原因为:" + response.body()); } InputStream inputStream = response.bodyStream(); try (FileOutputStream fos = new FileOutputStream(filePath)) { int len; byte[] buffer = new byte[1024]; while ((len = inputStream.read(buffer)) != -1) { fos.write(buffer, 0, len); } } } } public static void generateUnlimitedWXAQRCode(String appId, String appSecret, String path, String scene, File targetFile) throws Exception { String url = String.format(GET_WXA_CODE_UNLIMITED_URL, getAccessToken(appId, appSecret)); Map json = new HashMap<>(); json.put("page", path); json.put("scene", scene); json.put("check_path", false); try (HttpResponse response = HttpUtil.createPost(url).body(JacksonUtil.toJSONString(json)).header("Content-Type", "application/json").execute()) { if (response.getStatus() != 200) { throw new Exception("获取小程序二维码失败,原因为:" + response.body()); } InputStream inputStream = response.bodyStream(); try (FileOutputStream fos = new FileOutputStream(targetFile)) { int len; byte[] buffer = new byte[1024]; while ((len = inputStream.read(buffer)) != -1) { fos.write(buffer, 0, len); } } } } public static String generateUrlLink(String appId, String appSecret, String path, String query) throws Exception { String url = String.format(GET_URL_LINK_URL, getAccessToken(appId, appSecret)); Map json = new HashMap<>(); json.put("path", path); json.put("query", query); try (HttpResponse response = HttpUtil.createPost(url).body(JacksonUtil.toJSONString(json)).header("Content-Type", "application/json").execute()) { String responseStr = response.body(); Map jsonObject = JacksonUtil.parseObject(responseStr, Map.class); if ((Integer) jsonObject.get("errcode") != 0) { throw new Exception("获取url_link失败,原因为:" + (String) jsonObject.get("errmsg")); } return (String) jsonObject.get("url_link"); } } public static String getUserPhone(String appId, String appSecret, String code) throws Exception { String url = String.format(GET_USER_PHONE_URL, getAccessToken(appId, appSecret)); Map json = new HashMap<>(); json.put("code", code); try (HttpResponse response = HttpUtil.createPost(url).body(JacksonUtil.toJSONString(json)).header("Content-Type", "application/json").execute()) { String responseStr = response.body(); Map jsonObject = JacksonUtil.parseObject(responseStr, Map.class); if ((Integer) jsonObject.get("errcode") != 0) { throw new Exception("获取用户手机号失败,原因为:" + (String) jsonObject.get("errmsg")); } return (String) ((Map) jsonObject.get("phone_info")).get("phoneNumber"); } } public static boolean msgSecCheck(String appId, String appSecret, String content, String openId, int scene) { String url = String.format(MSG_SEC_CHECK_URL, getAccessToken(appId, appSecret)); Map json = new HashMap<>(); json.put("content", content); json.put("version", 2); json.put("scene", scene); json.put("openid", openId); String response = HttpUtil.post(url, JacksonUtil.toJSONString(json)); Map jsonObject = JacksonUtil.parseObject(response, Map.class); Object errcode = jsonObject.get("errcode"); boolean success = errcode != null && (Integer) errcode == 0; if (!success) { // 接口调用失败,认为检测成功。 return true; } Map result = JacksonUtil.getObject(response, "result", Map.class); if (result == null) { return false; } String suggest = result.getOrDefault("suggest", "").toString(); return Strings.CI.equals(suggest, "pass"); } public static void main(String[] args) throws Exception { generateWXAQRCode("wxe7ff26af70bfc37c", "5252fbbc68513bc77b7cc0052b9f9695", "trial", "pages/home/index?scenicId=3930324797233434624&morphId=22", "zt_p_t.jpg"); } }