微信公众号自定义菜单和推送模板消息

1.微信公众号测试账号:
找到服务号的开发文档,点击进去。

  1. Java代码:
    准备工作:
    (1)填写JS接口安全域名
    在这里插入图片描述
    (2)填写接口配置信息:在这里插入图片描述

    (2)java的Token验证接口

@RequestMapping(value = "/verifier",method = {RequestMethod.GET})
    public void processGet(HttpServletRequest request, HttpServletResponse response) throws Exception{
        System.out.println("验证接口消息");
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        //校验证签名
        boolean check = wxService.check(signature, timestamp, nonce);
        if (check){
            System.out.println("接入成功");
            PrintWriter writerOut = response.getWriter();
            writerOut.print(echostr);
            writerOut.flush();
            writerOut.close();
        }else {
            System.out.println("接入失败");
        }
    }
	验证签名:
public boolean check(String signature, String timestamp, String nonce){
        //字典排序
        String token = "自定义的Token值";
        String[] wxStrArr = {token, timestamp, nonce};
        Arrays.sort(wxStrArr);
        //进行sha1加密
        String wxString = wxStrArr[0]+wxStrArr[1]+wxStrArr[2];
        String wxSha1 = sha1(wxString);
        //加密后的数据和signature进行对比
       return StringUtils.equalsIgnoreCase(wxSha1,signature);
    }
private static String sha1(String wxString) {
        try {
            //获取加密对象
            MessageDigest sha1 = MessageDigest.getInstance("sha1");
            byte[] digest = sha1.digest(wxString.getBytes());
            StringBuilder sb = new StringBuilder();
            char[] chars = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
            //处理加密结果
            for (byte b : digest) {
                sb.append(chars[(b>>4)&15]);
                sb.append(chars[b&15]);
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

###创建菜单;

(1)抽象的菜单类

public class AbstractButton {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public AbstractButton(String name) {
        super();
        this.name = name;
    }
}

(2)view菜单

public class ViewButton extends AbstractButton {
    private String type = "view";

    private String url;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public ViewButton(String name, String url) {
        super(name);
        this.url = url;
    }
}

###获取Token

public void getToken(){
        String wxTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
        String appId = "微信公众号的APPID值";
        String appsecret = "微信公众号的APPSECRET值";
        String url = StringUtils.replace(wxTokenUrl, "APPID", appId).replace("APPSECRET", appsecret);
        String tokenStr = WechatUtils.get(url);
        JSONObject tokenjson = JSONObject.fromObject(tokenStr);
        String accessToken = tokenjson.getString("access_token");
        String expiresIn = tokenjson.getString("expires_in");
        //
        wxAccessToken = new WxAccessToken(accessToken,expiresIn);
    }
	Token的有效时间为2小时,创建一个保存Token值和判断Token是否过期的类;
public class WxAccessToken {
    private String accessToken;

    private long expiresTime;
    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public long getExpiresTime() {
        return expiresTime;
    }

    public void setExpiresTime(long expiresTime) {
        this.expiresTime = expiresTime;
    }

    public WxAccessToken(String accessToken, String expiresIn) {
        super();
        this.accessToken = accessToken;
        expiresTime = System.currentTimeMillis()+Integer.parseInt(expiresIn)*1000;
    }
    /**
     *判断 accessToken是否过期
     */
    public boolean isExpires(){
        return System.currentTimeMillis()>expiresTime;
    }
}
向外暴露 获取Token方法
 /**
     *向外暴露 获取Token方法
     *
     */
    public String getAccessToken(){
        if (wxAccessToken == null || wxAccessToken.isExpires()){
            getToken();
        }
        return wxAccessToken.getAccessToken();
    }
创建微信公众号菜单的接口:
/**
     *创建微信的自定义菜单
     */
    public void createMenu(){
        String creatMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
        String appId = "微信公众号的APPID值";
        String reUrl = "点击菜单需要跳转的路径";
        int result = 0;
        String accessToken = getAccessToken();
        String muenUrlAccessToken = StringUtils.replace(creatMenuUrl, "ACCESS_TOKEN", accessToken);
        Button button = new Button();
        //设置url要加https//
        button.getButton().add(new ViewButton("菜单名称","https://open.weixin.qq.com/connect/oauth2/authorize?appid="+appId+"&redirect_uri="+reUrl+"/login&response_type=code&scope=snsapi_base&#wechat_redirect"));
        String jsonObjectStr = JSONObject.fromObject(button).toString();
        JSONObject jsonObject = WechatUtils.httpRequest(muenUrlAccessToken, "POST", jsonObjectStr);
        if (null != jsonObject) {
            if (0 != jsonObject.getInt("errcode")) {
                result = jsonObject.getInt("errcode");
                System.out.println("创建菜单失败 errcode:{}");
                System.out.println(jsonObject.getString("errmsg"));
                System.out.println(jsonObject.getInt("errcode"));
            }
        }
    }

创建微信的工具类:

package cn.kkou.justice.common.utils;


import cn.kkou.justice.common.MyX509TrustManager;
import cn.kkou.justice.common.PropertiesLoader;
import net.sf.json.JSONObject;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.ConnectException;
import java.net.URL;
import java.net.URLConnection;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author
 * @version 1.0.0
 */
public class WechatUtils {
    private static Logger logger = LoggerFactory.getLogger(PropertiesLoader.class);

    /**
     *向指定的地址发送get请求
     */
    public static String get(String url){
        try {
            URL urlObj = new URL(url);
            //开连接
            URLConnection urlConnection = urlObj.openConnection();
            InputStream is = urlConnection.getInputStream();
            byte[] bytes = new byte[1024];
            int len;
            StringBuilder sb = new StringBuilder();
            while ((len=is.read(bytes))!=-1){
                sb.append(new String(bytes,0,len));
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 描述:  发起https请求并获取结果
     * @param requestUrl 请求地址
     * @param requestMethod 请求方式(GET、POST)
     * @param outputStr 提交的数据
     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
     */
    public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        StringBuffer buffer = new StringBuffer();
        try {
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = { new MyX509TrustManager() };
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);

            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);

            // 设置请求方式(GET/POST)
            httpUrlConn.setRequestMethod(requestMethod);

            if ("GET".equalsIgnoreCase(requestMethod)){
                httpUrlConn.connect();
            }
            // 当有数据需要提交时
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 注意编码格式,防止中文乱码
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            inputStream = null;
            httpUrlConn.disconnect();
            jsonObject = JSONObject.fromObject(buffer.toString());
        } catch (ConnectException ce) {
            logger.info("连接超时:",ce);
        } catch (Exception e) {
            logger.info("微信菜单创建请求错误:",e);
        }
        return jsonObject;
    }

    /*
     * xml转map
     */
    public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException {
        HashMap<String, String> map = new HashMap<String,String>();
        SAXReader reader = new SAXReader();

        InputStream ins = request.getInputStream();
        Document doc = reader.read(ins);

        Element root = doc.getRootElement();
        @SuppressWarnings("unchecked")
        List<Element> list = (List<Element>)root.elements();

        for(Element e:list){
            map.put(e.getName(), e.getText());
        }
        ins.close();
        return map;
    }

}

推送模板消息给关注的用户:

		//1,推送消息
        JSONObject templateMessage = disposeTemInfo("用户的openId");
        //3,如果是正式版发送模版消息,这里需要配置你的信息
        JSONObject msgJsonObject = disposePushInfoList();
        JSONObject jsonObject = JSONObject.fromObject(templateMessage);
        jsonObject.put("data",msgJsonObject);
        //发起推送
        try {
            sendTemplateMsg(jsonObject);
            System.out.println("推送成功");
        } catch (Exception e) {
            System.out.println("推送失败:" + e.getMessage());
            e.printStackTrace();
        }
public JSONObject disposeTemInfo(String openId){
		//openId是用户关注公众号的唯一标识
        String wxTemplateId = "模板Id";
        String appId = "APPID";
        String url = "点击消息跳转的路径";
        JSONObject templateMessageJson = new JSONObject();
        templateMessageJson.put("touser",openId);
        templateMessageJson.put("template_id",wxTemplateId);
        templateMessageJson.put("url","https://open.weixin.qq.com/connect/oauth2/authorize?appid="+appId+"&redirect_uri="+url+"/login&response_type=code&scope=snsapi_base&#wechat_redirect");
        return templateMessageJson;
    }
public JSONObject disposePushInfoList(){
		//对应微信公众号模板的.DATA 前面的值
        String wxTemplateFirst = "";
        String wxTemplateKey1 = "";
        String wxTemplateKey2 = "";
        String wxTemplateKey3 = "";
        String wxTemplateRemark = "";
        //字体颜色
        String wxTemplateColor ="";
       
        String firstStr = StringUtils.EMPTY;
        JSONObject first = new JSONObject();
        first.put("value",firstStr);
        first.put("color",wxTemplateColor);

        JSONObject KeyWord1 = new JSONObject();
        KeyWord1.put("value","");
        KeyWord1.put("color",wxTemplateColor);

        JSONObject KeyWord2 = new JSONObject();
        KeyWord2.put("value","");
        KeyWord2.put("color",wxTemplateColor);

        JSONObject KeyWord3 = new JSONObject();
        KeyWord3.put("value","";
        KeyWord3.put("color",wxTemplateColor);

        JSONObject remark = new JSONObject();
        remark.put("value","");
        remark.put("color",wxTemplateColor);
        JSONObject msgJson = new JSONObject();
        msgJson.put(wxTemplateFirst,first);
        msgJson.put(wxTemplateKey1,KeyWord1);
        msgJson.put(wxTemplateKey2,KeyWord2);
        msgJson.put(wxTemplateKey3,KeyWord3);
        msgJson.put(wxTemplateRemark,remark);

        return msgJson;
    }
public void sendTemplateMsg(JSONObject templateMessage){
        int result = 0;
        String accessToken = getAccessToken();
        String sendMsgUrlStr = StringUtils.replace("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN", "ACCESS_TOKEN", accessToken);
        String msgJsonStr = templateMessage.toString();
        JSONObject jsonObject = WechatUtils.httpRequest(sendMsgUrlStr, "POST", msgJsonStr);
        if (null != jsonObject) {
            if (0 != jsonObject.getInt("errcode")) {
                result = jsonObject.getInt("errcode");
                logger.error("推送消息失败");
            }
        }
    }
微信公众号消息推送通常通过微信提供的开发者API来完成,主要包括以下几个步骤: 1. **注册并获取appid**: 首先需要在微信公众平台上注册一个公众号,并获得AppID。 2. **安装微信开放平台SDK**: 下载微信开发者工具或参考官方文档,集成微信JS-SDK到你的项目中,这包括`wx.config`初始化配置以及`onMenuShareTimeline`等函数。 3. **服务器端设置**: 创建一个服务器接口用于接收用户的关注、取消关注及主动发送消息的请求。你需要申请一个服务器域名并配置到微信公众平台后台。 4. **事件订阅`: 使用微信提供的`subscribe``unsubscribe`接口来订阅取消订阅用户。当用户关注或取消关注公众号时,服务器会收到通知。 5. **消息推送**: 对于群发消息,可以使用`sendTemplateMessage`或`sendNewsMessage`接口,传递新闻文章或多图文模板数据给指定的用户列表。对于单聊消息,一般通过客服接口或者用户主动发送消息来触发。 6. **处理用户交互**: 当用户点击公众号消息中的链接或按钮时,会在微信客户端打开网页并触发自定义菜单的跳转,这时可以在服务器接收到`click`事件后做出相应的响应。 7. **验证与安全性**: 确保所有交互都经过安全验证,防止恶意操作,例如使用加密签名进行数据校验。 **示例代码片段**(简化版): ```python from flask import request, jsonify import wechat_sdk def send_message(openid, message): jsapi_ticket = get_jsapi_ticket() # 获取微信jsapi_ticket wx_config = { 'url': request.host_url + '/path/to/receive/response', # 跳转地址 'timestamp': str(time.time()), 'nonceStr': generate_nonce_str(), # 随机字符串 'signature': generate_signature(jsapi_ticket) } wechat_sdk.jsapi.send_news(openid, message, jsapi_ticket, wx_config) # 接收用户发送的消息并处理 @app.route('/receive/response', methods=['POST']) def receive_response(): data = request.get_json() if data['type'] == 'event': if data['event'] == 'CLICK': user_id = data['openid'] click_button = data['button']['name'] # 根据button名做相应处理 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值