package com.leenleda.project.manager.common.utils;
import com.alibaba.fastjson.JSONObject;
import com.leenleda.project.manager.common.config.LeenledaConfig;
import com.leenleda.project.manager.common.dto.response.JsTicketResponseDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* @author pengbenlei
* @company leenleda
* @date 2021/3/29 9:49
* @description
*/
@Component
public class WechatUtil {
private static final String JSTICKET_CACHE_KEY="leenleda:wechat:jsticket:cache";
private static final int JSTICKET_CACHE_TIME=6200;
@Autowired
RedisUtil redisUtil;
@Resource
LeenledaConfig leenledaConfig;
private String getAccessToken() {
String accessToken = (String) redisUtil.get(leenledaConfig.getWechatAppId());
if (StringUtils.isEmpty(accessToken)) {
// 获取缓存
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + leenledaConfig.getWechatAppId() + "&secret=85e05903abd1e3772e85de160120dc2d";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity response = restTemplate.getForEntity(url, String.class);
JSONObject jsonObject = JSONObject.parseObject(response.getBody());
accessToken = jsonObject.getString("access_token");
redisUtil.set(leenledaConfig.getWechatAppId(), accessToken, 7200, TimeUnit.SECONDS);
}
return accessToken;
}
/**
* 发送公众号模板消息
* @param templeteId
* @param pageUrl
* @param openId
* @param data
*/
public void sendTemplateMsg(String templeteId, String pageUrl, String openId, String data) {
String token = getAccessToken();
String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/bizsend?access_token=" + token;
JSONObject jsonObject = new JSONObject();
jsonObject.put("access_token", token);
jsonObject.put("touser", openId);
jsonObject.put("template_id", templeteId);
jsonObject.put("page", pageUrl);
jsonObject.put("data", data);
String requestJsonStr = JSONObject.toJSONString(jsonObject);
connectWeiXinInterface(url, requestJsonStr);
}
/**
* 获取微信js配置
* @param url
* @return
*/
public JsTicketResponseDto getConfig(String url) {
try {
url= URLDecoder.decode(url,"GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String ticket = getJsapiTicket();
String timestamp = create_timestamp();
String nonceStr = create_nonce_str();
String string1 = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "×tamp=" + timestamp +
"&url=" + url;
String signature = "";
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8")); // 对string1 字符串进行SHA-1加密处理
signature = byteToHex(crypt.digest()); // 对加密后字符串转成16进制
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Assert.isTrue(!StringUtils.isEmpty(signature),"生成js签名出错!");
JsTicketResponseDto jsTicketResponseDto = new JsTicketResponseDto(leenledaConfig.getWechatAppId(), timestamp, nonceStr, signature);
return jsTicketResponseDto;
}
public String getJsapiTicket() {
String ticket = redisUtil.getStr(JSTICKET_CACHE_KEY);
if (!StringUtils.isEmpty(ticket)) {
return ticket.replace("\"", "");
}
String token = getAccessToken();
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + token + "&type=jsapi";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity response = restTemplate.getForEntity(url, String.class);
JSONObject jsonObject = JSONObject.parseObject(response.getBody());
ticket = jsonObject.getString("ticket");
Assert.isTrue(!StringUtils.isEmpty(ticket), "获取jsticket出错!");
redisUtil.set(JSTICKET_CACHE_KEY, ticket, JSTICKET_CACHE_TIME, TimeUnit.SECONDS);
return ticket;
}
// 生成时间戳字符串
public static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
// 生成随机字符串
public static String create_nonce_str() {
return UUID.randomUUID().toString();
}
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;
}
public static void connectWeiXinInterface(String action, String json) {
URL url;
try {
url = new URL(action);
HttpURLConnection http = (HttpURLConnection) url.openConnection();
http.setRequestMethod("POST");
http.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
http.connect();
OutputStream os = http.getOutputStream();
os.write(json.getBytes("UTF-8"));// 传入参数
InputStream is = http.getInputStream();
int size = is.available();
byte[] jsonBytes = new byte[size];
is.read(jsonBytes);
String result = new String(jsonBytes, "UTF-8");
os.flush();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
微信工具类
package com.leenleda.project.manager.wechat.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.leenleda.project.manager.common.config.LeenledaConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLDecoder;
import java.net.URLEncoder;
/**
* @author pengbenlei
* @company leenleda
* @date 2021/3/30 14:36
* @description
*/
@Component
public class WeChatAuthInterceptor implements HandlerInterceptor {
@Autowired
LeenledaConfig leenledaConfig;
// 进入controller方法之前调用
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String code = request.getParameter("code");
if (StringUtils.isEmpty(code)) {
// 跳转微信授权页面
String redirect_uri = leenledaConfig.getWechatRdirect() + "?redirect_uri=" + request.getParameter("redirect_uri");
redirect_uri = URLEncoder.encode(redirect_uri, "GBK");
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + leenledaConfig.getWechatAppId() + "&redirect_uri=" + redirect_uri + "" +
"&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
response.sendRedirect(url);
return false;
} else {
String redirect_uri = request.getParameter("redirect_uri");
Assert.isTrue(!StringUtils.isEmpty(redirect_uri), "业务回调地址不能为空!");
// 授权成功,跳转指定的回调地址,并拼接openid
String url = URLDecoder.decode(redirect_uri, "GBK");
// 解析openid
String openId = deCode(code);
if (url.indexOf("?") > -1) {
url += "&openId=" + openId;
} else {
url += "?openId=" + openId;
}
response.sendRedirect(url);
return true;
}
}
/**
* 通过code解析openid
*/
private String deCode(String code) {
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + leenledaConfig.getWechatAppId() + "&" +
"secret=" + leenledaConfig.getWechatSecret() + "&code=" + code + "&grant_type=authorization_code";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity response = restTemplate.getForEntity(url, String.class);
JSONObject jsonObject = JSONObject.parseObject(response.getBody());
String openId = jsonObject.getString("openid");
Assert.isTrue(!StringUtils.isEmpty(openId), "解析微信code出错!");
return openId;
}
}
公众号登陆授权获取openId
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<wx-open-subscribe template="vk-tuJWjy30BDJvwkf-SQrOvRiLfOc9HExH-wIx_DfE,JXk-rEwyK2-s3P3KLDOb9Y9thx-uge_yWJQX9aqQNBo,x_1oPRm1ykvw08KvTp-A26qlaYmf4vAwh88SRgvpFFw,S8idG88AEwPMFBOrxLP4i6fJNahX5HYjtLgG5fP_DIM" id="subscribe-btn">
<template slot="style">
<style>
.subscribe-btn {
color: #fff;
background-color: #07c160;
}
style>
template>
<template>
<button class="subscribe-btn">
一次性模版消息订阅
button>
template>
wx-open-subscribe>
body>
html>
<script src="http://res2.wx.qq.com/open/js/jweixin-1.6.0.js">script>
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js">script>
<script>
var url = window.location.href;
// 微信jsticket配置
$.get("xxxxx/wechat/get-signature?&url=" + encodeURIComponent(url), function (res) {
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: res.appId, // 必填,公众号的唯一标识
timestamp: res.timestamp, // 必填,生成签名的时间戳
nonceStr: res.nonceStr, // 必填,生成签名的随机串
signature: res.signature,// 必填,签名
jsApiList: [], // 必填,需要使用的JS接口列表
openTagList:['wx-open-subscribe']
});
});
wx.ready(function () {
console.log("配置引入成功")
var btn = document.getElementById('subscribe-btn');
btn.addEventListener('success', function (e) {
console.log('success', e.detail);
});
btn.addEventListener('error',function (e) {
console.log('fail', e.detail);
});
});
script>
页面调用订阅消息