WeChatUtil.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. package com.ylx.massage.utils;
  2. /**
  3. * @author jianlong
  4. * @date 2024-06-04 10:13
  5. */
  6. import cn.hutool.http.HttpUtil;
  7. import cn.hutool.json.JSONUtil;
  8. import com.alibaba.fastjson2.JSONObject;
  9. import com.ylx.common.config.WechatAccountConfig;
  10. import com.ylx.common.constant.MassageConstants;
  11. import com.ylx.common.core.redis.RedisCache;
  12. import com.ylx.common.exception.ServiceException;
  13. import lombok.extern.slf4j.Slf4j;
  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.stereotype.Component;
  16. import org.w3c.dom.Node;
  17. import org.w3c.dom.NodeList;
  18. import javax.annotation.Resource;
  19. import javax.xml.parsers.DocumentBuilder;
  20. import javax.xml.parsers.DocumentBuilderFactory;
  21. import javax.xml.transform.OutputKeys;
  22. import javax.xml.transform.Transformer;
  23. import javax.xml.transform.TransformerFactory;
  24. import javax.xml.transform.dom.DOMSource;
  25. import javax.xml.transform.stream.StreamResult;
  26. import java.io.ByteArrayInputStream;
  27. import java.io.InputStream;
  28. import java.io.StringWriter;
  29. import java.io.UnsupportedEncodingException;
  30. import java.net.URLEncoder;
  31. import java.util.HashMap;
  32. import java.util.Map;
  33. import java.util.concurrent.TimeUnit;
  34. /**
  35. * 微信登录工具类
  36. */
  37. @Component
  38. @Slf4j
  39. public class WeChatUtil {
  40. private final static String ERROR_CODE = "errcode";
  41. @Resource
  42. private WechatAccountConfig wxPayProperties;
  43. @Autowired
  44. private RedisCache redisCache;
  45. /**
  46. * 获取微信授权code
  47. *
  48. * @param state state信息
  49. * @return 返回微信授权code的URL
  50. */
  51. public String getCode(String state) {
  52. try {
  53. StringBuffer url = new StringBuffer();
  54. url.append(wxPayProperties.getGetCodeUrl())
  55. .append("?appid=")
  56. .append(wxPayProperties.getMpAppId())
  57. .append("&redirect_uri=")
  58. .append(URLEncoder.encode(wxPayProperties.getRedirectUrl(), "UTF-8"))
  59. // .append(URLEncoder.encode("https://test.baoxianzhanggui.com/fragrance/#/pages/my/wxLogin", "UTF-8"))
  60. .append("&response_type=code&scope=snsapi_userinfo&state=")
  61. .append("STATE")
  62. .append("#wechat_redirect");
  63. return url.toString();
  64. } catch (UnsupportedEncodingException e) {
  65. throw new ServiceException("URL格式化异常");
  66. }
  67. }
  68. /**
  69. * 获取微信AccessToken
  70. *
  71. * @param code 用户code
  72. * @return 返回包含微信AccessToken的Map
  73. */
  74. public Map<?, ?> getAccessToken(String code) {
  75. StringBuffer url = new StringBuffer();
  76. url.append(wxPayProperties.getAccessTokenUrl())
  77. .append("?appid=").append(wxPayProperties.getMpAppId())
  78. .append("&secret=").append(wxPayProperties.getMpAppSecret())
  79. .append("&code=").append(code)
  80. .append("&grant_type=authorization_code");
  81. String rs = HttpUtil.get(url.toString());
  82. Map<?, ?> map = JSONObject.parseObject(rs, Map.class);
  83. if (null == map.get(ERROR_CODE)) {
  84. return map;
  85. } else {
  86. log.error("getAccessToken-获取access_token出错:{}", map);
  87. throw new ServiceException("获取access_token出错");
  88. }
  89. }
  90. /**
  91. * 获取微信AccessToken
  92. *
  93. * @return 返回包含微信AccessToken的Map
  94. */
  95. public String getToken() {
  96. if (redisCache.getCacheObject(MassageConstants.ACCESS_TOKEN_KEY + wxPayProperties.getMpAppId()) != null) {
  97. return redisCache.getCacheObject(MassageConstants.ACCESS_TOKEN_KEY + wxPayProperties.getMpAppId());
  98. }
  99. StringBuffer url = new StringBuffer();
  100. url.append("https://api.weixin.qq.com/cgi-bin/token")
  101. .append("?grant_type=").append("client_credential")
  102. .append("&appid=").append(wxPayProperties.getMpAppId())
  103. .append("&secret=").append(wxPayProperties.getMpAppSecret());
  104. String rs = HttpUtil.get(url.toString());
  105. Map<?, ?> map = JSONObject.parseObject(rs, Map.class);
  106. if (null == map.get(ERROR_CODE)) {
  107. redisCache.setCacheObject(MassageConstants.ACCESS_TOKEN_KEY + wxPayProperties.getMpAppId(), map.get("access_token").toString(), 1, TimeUnit.HOURS);
  108. return map.get("access_token").toString();
  109. } else {
  110. log.error("getToken-获取access_token出错:{}", map);
  111. throw new ServiceException("getToken-获取access_token出错");
  112. }
  113. }
  114. /**
  115. * 获取jsticke
  116. */
  117. public String getJsapiTicket(String token) {
  118. //todo 缓存公众号全局token凭证
  119. StringBuffer url = new StringBuffer();
  120. url.append("https://api.weixin.qq.com/cgi-bin/ticket/getticket")
  121. .append("?access_token=").append(token)
  122. .append("&type=").append("jsapi");
  123. String rs = HttpUtil.get(url.toString());
  124. Map<?, ?> map = JSONObject.parseObject(rs, Map.class);
  125. if ("ok".equals(map.get("errmsg"))) {
  126. return map.get("ticket").toString();
  127. } else {
  128. log.error("获取jsticke出错:{}", map);
  129. throw new ServiceException("获取jsticke出错");
  130. }
  131. }
  132. /**
  133. * 刷新AccessToken
  134. *
  135. * @param refreshToken 用户刷新token
  136. * @return 返回包含刷新后的微信AccessToken的Map
  137. */
  138. public Map<?, ?> refreshToken(String refreshToken) {
  139. StringBuffer url = new StringBuffer();
  140. url.append("https://api.weixin.qq.com/sns/oauth2/refresh_token")
  141. .append("?appid=").append(wxPayProperties.getMpAppId())
  142. .append("&grant_type=refresh_token&refresh_token=").append(refreshToken);
  143. String rs = HttpUtil.get(url.toString());
  144. Map<?, ?> map = JSONObject.parseObject(rs, Map.class);
  145. if (null == map.get(ERROR_CODE)) {
  146. return map;
  147. } else {
  148. log.error("刷新access_token出错:{}", map);
  149. throw new ServiceException("刷新access_token出错");
  150. }
  151. }
  152. /**
  153. * 获取用户信息
  154. *
  155. * @param accessToken 微信AccessToken
  156. * @param openid 用户的openid
  157. * @return 返回包含用户信息的JSON字符串
  158. */
  159. public String getUserInfo(String accessToken, String openid) {
  160. StringBuffer url = new StringBuffer();
  161. url.append("https://api.weixin.qq.com/sns/userinfo")
  162. .append("?access_token=").append(accessToken)
  163. .append("&openid=").append(openid)
  164. .append("&lang=zh_CN");
  165. return HttpUtil.get(url.toString());
  166. }
  167. /**
  168. * 生成公众号码ticket
  169. *
  170. * @param token access_token
  171. * @return 返回包含微信公众号码ticket的Map
  172. */
  173. public Map<?, ?> getTicket(String token, String openId) {
  174. String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + token;
  175. String param = "{\"action_name\": \"QR_LIMIT_STR_SCENE\",\"action_info\": {\"scene\": {\"scene_str\": \"" + openId + "\"}}}";
  176. String rs = HttpUtil.post(url, param);
  177. Map<?, ?> map = JSONObject.parseObject(rs, Map.class);
  178. // String ticket = map.get("ticket").toString();
  179. //
  180. // String encode = null;
  181. // try {
  182. // encode = URLEncoder.encode(ticket, "UTF-8");
  183. // } catch (UnsupportedEncodingException e) {
  184. // throw new RuntimeException(e);
  185. // }
  186. //
  187. // String url1 = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket="+ encode;
  188. //
  189. // String s = HttpUtil.get(url1);
  190. //
  191. //
  192. //
  193. //
  194. // Map<?, ?> rsmap = JSONObject.parseObject(s, Map.class);
  195. // return rsmap;
  196. return map;
  197. }
  198. /**
  199. * 生成公众号码ticket
  200. *
  201. * @param token access_token
  202. * @return 返回包含微信公众号码ticket的Map
  203. */
  204. public Map<?, ?> menuUtil(String token) {
  205. String url = " https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + token;
  206. String param = "{\"button\":[{\"type\":\"view\",\"name\":\"立即下单\",\"url\":\"https://test.baoxianzhanggui.com/fragrance/\"},{\"name\":\"更多\",\"sub_button\":[{\"type\":\"view\",\"name\":\"搜索\",\"url\":\"https://test.baoxianzhanggui.com/fragrance/\"},{\"type\":\"click\",\"name\":\"赞一下我们\",\"key\":\"V1001_GOOD\"}]}]}";
  207. String rs = HttpUtil.post(url, param);
  208. Map<?, ?> map = JSONObject.parseObject(rs, Map.class);
  209. return map;
  210. }
  211. /**
  212. * 公众号消息通知
  213. *
  214. * @param token access_token
  215. * @return 返回包含微信公众号码ticket的Map
  216. */
  217. public Map<?, ?> notification(String openid, cn.hutool.json.JSONObject data) {
  218. String token = this.getToken();
  219. String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + token;
  220. cn.hutool.json.JSONObject param1 = JSONUtil.createObj();
  221. param1.put("touser", openid);
  222. param1.put("template_id", wxPayProperties.getTemplateId1());
  223. param1.put("url", "https://test.baoxianzhanggui.com/fragrance/");
  224. param1.put("data", data);
  225. String result = HttpUtil.post(url, param1.toString());
  226. System.out.println(result);
  227. log.info("notification-消息通知请求参数:{}", param1.toString());
  228. Map<?, ?> map = JSONObject.parseObject(result, Map.class);
  229. log.info("notification-消息通知返回参数:{}", map);
  230. return map;
  231. }
  232. /**
  233. * XML格式字符串转换为Map
  234. *
  235. * @param strXML XML字符串
  236. * @return XML数据转换后的Map
  237. * @throws Exception
  238. */
  239. public static Map<String, String> xmlToMap(String strXML) throws Exception {
  240. try {
  241. Map<String, String> data = new HashMap<>();
  242. DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
  243. DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
  244. InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
  245. org.w3c.dom.Document doc = documentBuilder.parse(stream);
  246. doc.getDocumentElement().normalize();
  247. NodeList nodeList = doc.getDocumentElement().getChildNodes();
  248. for (int idx = 0; idx < nodeList.getLength(); ++idx) {
  249. Node node = nodeList.item(idx);
  250. if (node.getNodeType() == Node.ELEMENT_NODE) {
  251. org.w3c.dom.Element element = (org.w3c.dom.Element) node;
  252. data.put(element.getNodeName(), element.getTextContent());
  253. }
  254. }
  255. try {
  256. stream.close();
  257. } catch (Exception ex) {
  258. // do nothing
  259. }
  260. return data;
  261. } catch (Exception ex) {
  262. log.error("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
  263. throw ex;
  264. }
  265. }
  266. /**
  267. * 将Map转换为XML格式的字符串
  268. *
  269. * @param data Map类型数据
  270. * @return XML格式的字符串
  271. * @throws Exception
  272. */
  273. public static String mapToXml(Map<String, String> data) throws Exception {
  274. DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
  275. DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
  276. org.w3c.dom.Document document = documentBuilder.newDocument();
  277. org.w3c.dom.Element root = document.createElement("xml");
  278. document.appendChild(root);
  279. for (String key : data.keySet()) {
  280. String value = data.get(key);
  281. if (value == null) {
  282. value = "";
  283. }
  284. value = value.trim();
  285. org.w3c.dom.Element filed = document.createElement(key);
  286. filed.appendChild(document.createTextNode(value));
  287. root.appendChild(filed);
  288. }
  289. TransformerFactory tf = TransformerFactory.newInstance();
  290. Transformer transformer = tf.newTransformer();
  291. DOMSource source = new DOMSource(document);
  292. transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
  293. transformer.setOutputProperty(OutputKeys.INDENT, "yes");
  294. StringWriter writer = new StringWriter();
  295. StreamResult result = new StreamResult(writer);
  296. transformer.transform(source, result);
  297. String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
  298. try {
  299. writer.close();
  300. } catch (Exception ex) {
  301. }
  302. return output;
  303. }
  304. }