微信公众号开发常用工具类


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>
页面调用订阅消息