我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java微信公众号发送消息-保姆级教程附源码

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java微信公众号发送消息-保姆级教程附源码

目录

1. 概念说明:

2. 开发准备:

3. 测试demo(更改配置信息即可使用)

3.1. 服务器配置

 3.1.1.配置填写说明

3.1.2.校验服务器有效性:

3.1.3.URL后端接口代码和校验代码(servlet)

 3.1.4.配置内网穿透,完成本地调试

 3.1.5. 可能存在的问题

3.2 模板消息

3.2.1. 搞定 template_id 即模板消息id:

3.2.2. 搞定 touser 即openid

3.2.3. 从获取openid的请求中我们发现需要access_token:

3.2.4. 发送模板消息的url参数

3.2.5. topcolor

3.2.5. data

3.3. 源码

3.3.1 模板消息DTO

3.3.2. 模板消息内容DTO

3.3.3. access_token缓存类:

3.3.4.http请求工具类:

3.3.5. 最终的Servlet(controller自行转换)(为方便观看所有逻辑都写在这里了,自行优化):

3.4.测试

官方文档:

微信公众平台开发概述 | 微信开放文档

全局返回码文档 :微信开放文档

1. 概念说明:

  • access_token:是公众号的全局唯一接口调用凭据,公众号调用各接口的必要参数(2小时内有效,过期需要重新获取,但1天内获取次数有限,需自行存储)

  • OpenID :为了识别用户每个公众号针对,每个用户会产生一个OpenID(用户id:对用户的操作需要用到)

  • UnionID: 同一开放平台账号下不同公众号或应用下用户的共同id(这里不需要用到)

  • 消息会话(这里用到模板消息)

    • 公众号是以微信用户的一个联系人形式存在的,消息会话是公众号与用户交互的基础。

    • 公众号内主要有这样几类消息服务的类型,分别用于不同的场景:

      • 群发消息:订阅号为每天1次,服务号为每月4次

      • 被动回复消息:在用户给公众号发消息后,公众号可以回复一个消息

      • 客服消息:用户在公众号内发消息/触发特定行为后,公众号可以给用户发消息

      • 模板消息:在需要对用户发送服务通知(如刷卡提醒、服务预约成功通知等)时,公众号可以用特定内容模板,主动向用户发送消息。

2. 开发准备:

  1. 开发者在公众平台网站中创建服务号、获取接口权限后方可开始

    https://kf.qq.com/faq/120911VrYVrA150918fMZ77R.html?scene_id=kf3386

  2. 个人研究测试:通过手机微信扫描二维码获得测试号

    https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

3. 测试demo(更改配置信息即可使用)

3.1. 服务器配置

这里坑比较多,服务器配置不是随便填一个url就完事了,需要后端接口配合校验。

界面:

 测试号界面:

 3.1.1.配置填写说明

  • URL:服务器地址--是开发者用来接收微信消息和事件的接口URL (在提交配置修改时微信会向该URL接口发送请求验证服务器地址的有效性)

  • Token:任意填写,用作生成签名(微信向上述URL接口发送的请求是携带token的,需要在接口中校验token一致以确保安全性)这个token与上述的access_token不是一回事。这个token只用于验证开发者服务器。

  • EncodingAESKey: 由开发者手动填写或随机生成,将用作消息体加解密密钥

  • 消息加解密方式 :明文模式、兼容模式和安全模式

3.1.2.校验服务器有效性:

这是重点:点击完提交修改后,微信会向url发起一个请求并将token携带过去,这个请求要能正确被你的后端服务器所响应并返回正确的结果,服务器配置才算修改成功

校验请求说明:

  • 开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:
    • signature:微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。

    • timestamp:时间戳

    • nonce :随机数

    • echostr:随机字符串

  • 开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。

3.1.3.URL后端接口代码和校验代码(servlet)

@WebServlet(urlPatterns = {"/wx"})public class WxServlet extends HttpServlet {    // 服务器配置填写的token    private static final String wxToken = "888888";    @Overrideprotected void doGET(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {        doGetWx(request, response); }public void doGetWx(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String signature = request.getParameter("signature");String timestamp = request.getParameter("timestamp");String nonce = request.getParameter("nonce");String echostr = request.getParameter("echostr");// 将微信echostr返回给微信服务器try (OutputStream os = response.getOutputStream()) {String sha1 = getSHA1(wxToken, timestamp, nonce, "");// 和signature进行对比if (sha1.equals(signature)) {// 返回echostr给微信os.write(URLEncoder.encode(echostr, "UTF-8").getBytes());os.flush();}} catch (Exception e) {e.printStackTrace();}}public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws Exception {try {String[] array = new String[] { token, timestamp, nonce, encrypt };StringBuffer sb = new StringBuffer();// 字符串排序Arrays.sort(array);for (int i = 0; i < 4; i++) {sb.append(array[i]);}String str = sb.toString();// SHA1签名生成MessageDigest md = MessageDigest.getInstance("SHA-1");md.update(str.getBytes());byte[] digest = md.digest();StringBuffer hexstr = new StringBuffer();String shaHex = "";for (int i = 0; i < digest.length; i++) {shaHex = Integer.toHexString(digest[i] & 0xFF);if (shaHex.length() < 2) {hexstr.append(0);}hexstr.append(shaHex);}return hexstr.toString();} catch (Exception e) {e.printStackTrace();}return "";}    }

项目路径是/xjsrm,因此服务器url地址就是:http://localhost:8080/xjsrm/wx

直接将http://localhost:8080/xjsrm/wx地址填到服务配置的url可以吗?答案是不可以!

 3.1.4.配置内网穿透,完成本地调试

 3.1.4.1. 内网穿透的必要性:

  • 微信需要检验服务器有效性,因此这个url必须是公网资源,就是外网能访问的,不支持本地127.0.0.1/localhost ,而且这样调试起来非常的不方便。
  • 因此这里使用内网穿透将本地资源映射到公网。(直接部署到服务器上调试的可以跳过)

 3.1.4.2. 用到的工具cpolar:

  •  也可以使用花生壳、natapp、ngrok等;但不建议使用natapp、ngrok,这两个工具都不能直接访问到服务资源,中间会多一层手动校验(提示用户是否要访问该网站),会造成不必要的麻烦。

 3.1.4.3. cpolar配置内网穿透的教程

 3.1.4.4. 获取本地项目的公网路径

        配置完cpolar后在在线隧道列表中找到本地项目的地址,我项目是localhost:8080,因此公网地址对应(最好用https协议)https://22717eef.r6.vip.cpolar.cn

        因此完整的服务器Url就是: https://22717eef.r6.vip.cpolar.cn/xjsrm/wx

        浏览器访问该url,看后端是否接受到了请求,如果接收到说明接口没问题,此时将URL填到对应的配置栏中点击提交即可。

 3.1.5. 可能存在的问题

        如果你在使用点击修改配置的提交发现微信发送的请求根本就没有进到后端的项目中

        此时查看sandboxinfo这个包。如果出现 errorcode=-1多半是内网穿透工具的问题。

        出现其他错误代码可以去错误大全中根据信息排查

         ngrok错误排查示例:         

3.2 模板消息

 模板消息的官方文档:微信公众平台 (qq.com)

从官方给出的请求示例入手,看需要准备的接口和数据:

POST请求https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN请求包为一个json:{    "template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",    "touser":"OPENID","url":"http://weixin.qq.com/download",    "topcolor":"#FF0000",    "data":{            "User": {                "value":"黄先生",                "color":"#173177"            },            "Date":{                "value":"06月07日 19时24分",                "color":"#173177"            },            "CardNumber": {                "value":"0426",                "color":"#173177"            },            "Type":{                "value":"消费",                "color":"#173177"            },            "Money":{                "value":"人民币260.00元",                "color":"#173177"            },            "DeadTime":{                "value":"06月07日19时24分",                "color":"#173177"            },            "Left":{                "value":"6504.09",                "color":"#173177"            }    }}

3.2.1. 搞定 template_id 即模板消息id:

新增模板消息(以测试号为例)

模板内容可设置参数(模板标题不可),供接口调用时使用,参数需以{{开头,以.DATA}}结尾(具体传参看后续代码)

3.2.2. 搞定 touser 即openid

查看用户管理的官方文档;微信开放文档 (qq.com),通过官方接口获取

因为我们是公众号,所以选用获取用户列表的接口:微信开放文档 (qq.com)

http请求方式: GET(请使用https协议)https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID参数是否必须说明access_token是调用接口凭证next_openid是第一个拉取的OPENID,不填默认从头开始拉取返回说明正确时返回JSON数据包:{    "total":2,    "count":2,    "data":{    "openid":["OPENID1","OPENID2"]},    "next_openid":"NEXT_OPENID"}

3.2.3. 从获取openid的请求中我们发现需要access_token

获取access_token官方文档:微信开放文档 (qq.com)

https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET参数说明参数是否必须说明grant_type是获取access_token填写client_credentialappid是第三方用户唯一凭证secret是第三方用户唯一凭证密钥,即appsecret返回说明正常情况下,微信会返回下述JSON数据包给公众号:{"access_token":"ACCESS_TOKEN","expires_in":7200}

3.2.4. 发送模板消息的url参数

        这个是发送消息后用户点击卡片跳转的地址(自定义)可以不填

3.2.5. topcolor

       消息卡片的顶部颜色(自定义)

3.2.5. data

       消息的内容(了解结构即可,后续代码中会体现)

3.3. 源码

拷贝完再理解

3.3.1 模板消息DTO

import java.util.Map;public class TemplateMessage {  private String touser;      private String template_id;        private String url;        private String topcolor;            private Map data;   // private String data;public TemplateMessage() {}    public TemplateMessage(String touser, String template_id, String url, String topcolor, Map data) {        this.touser = touser;        this.template_id = template_id;        this.url = url;        this.topcolor = topcolor;        this.data = data;    }public String getTouser() {return touser;}public void setTouser(String touser) {this.touser = touser;}public String gettemplate_id() {return template_id;}public void settemplate_id(String template_id) {this.template_id = template_id;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getTopcolor() {return topcolor;}public void setTopcolor(String topcolor) {this.topcolor = topcolor;}public Map getData() {return data;}public void setData(Map data) {this.data = data;}@Overridepublic String toString() {return "TemplateMessage [touser=" + touser + ", template_id=" + template_id + ", url=" + url + ", topcolor="+ topcolor + ", data=" + data + "]";}}

3.3.2. 模板消息内容DTO

import java.io.Serializable;public class WeChatTemplateMsg implements Serializable{    private String value;        private String color;      public WeChatTemplateMsg(String value) {        this.value = value;        this.color = "#173177";    }     public WeChatTemplateMsg(String value, String color) {        this.value = value;        this.color = color;    }@Overridepublic String toString() {return "WeChatTemplateMsg [value=" + value + ", color=" + color + "]";}public String getValue() {return value;}public void setValue(String value) {this.value = value;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}}

3.3.3. access_token缓存类:

public class AccessToken {private String accessToken;    //过期时间 当前系统时间+微信传来的过期时间    private Long expiresTime;    public AccessToken(String accessToken, String expiresIn) {        this.accessToken = accessToken;        this.expiresTime = System.currentTimeMillis()+Integer.parseInt(expiresIn)*1000;    }        public boolean isExpired(){        return System.currentTimeMillis()>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 AccessToken(String accessToken, Long expiresTime) {this.accessToken = accessToken;this.expiresTime = expiresTime;}public AccessToken() {}}

3.3.4.http请求工具类:

import java.io.BufferedReader;import java.net.*;import java.nio.charset.StandardCharsets;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStream;import java.net.HttpURLConnection;import java.net.URL;import java.util.ArrayList;import java.util.List;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject;import com.xx.xx.pojo.TemplateMessage;public class WXPublicAccountHttpUtil {public static String get(String url) throws IOException {        HttpURLConnection connection = null;        BufferedReader reader = null;        try {            URL requestUrl = new URL(url);            connection = (HttpURLConnection) requestUrl.openConnection();            connection.setRequestMethod("GET");            int responseCode = connection.getResponseCode();            if (responseCode == HttpURLConnection.HTTP_OK) {                reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));                StringBuilder response = new StringBuilder();                String line;                while ((line = reader.readLine()) != null) {                    response.append(line);                }                return response.toString();            } else {                // Handle error response                System.out.println("HTTP GET request failed with response code: " + responseCode);                return null;            }        } finally {            if (reader != null) {                reader.close();            }            if (connection != null) {                connection.disconnect();            }        }    }public static JSONObject getJsonObject(String url) throws IOException {        HttpURLConnection connection = null;        BufferedReader reader = null;        try {            URL urlObj = new URL(url);            connection = (HttpURLConnection) urlObj.openConnection();            connection.setRequestMethod("GET");            StringBuilder response = new StringBuilder();            reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));            String line;            while ((line = reader.readLine()) != null) {                response.append(line);            }                                    return JSON.parseObject(response.toString());        } finally {            if (reader != null) {                reader.close();            }            if (connection != null) {                connection.disconnect();            }        }    }    public static  List getOpenidList(String url) throws IOException {    // 获取关注用户列表数据        JSONObject jsonObject = getJsonObject(url);        System.out.println(jsonObject);                // 错误情况        if (jsonObject.containsKey("errcode")) {            int errcode = jsonObject.getIntValue("errcode");            String errmsg = jsonObject.getString("errmsg");            throw new RuntimeException("Failed to get openid list. errcode: " + errcode + ", errmsg: " + errmsg);        }         int total = jsonObject.getIntValue("total");       // 无用户关注 {"total":0,"count":0,"next_openid":""}        if (total == 0) {            throw new RuntimeException("No openid found. Total is 0.");        }        // 有用户关注:                JSONObject dataObject = jsonObject.getJSONObject("data");                int count = dataObject.getIntValue("count");        System.out.println("关注总人数:"+count);        JSONArray openidArray = dataObject.getJSONArray("openid");                // 将 openid 数组封装为 List 集合        List openidList = new ArrayList<>();        for (int i = 0; i < openidArray.size(); i++) {            String openid = openidArray.getString(i);            openidList.add(openid);        }                return openidList;    }            public static String sendMessage( String accessToken, TemplateMessage templateMessage) throws IOException {        String requestUrl ="https://api.weixin.qq.com/cgi-bin/message/template/send" + "?access_token=" + accessToken;        URL urlObject = new URL(requestUrl);        HttpURLConnection connection = (HttpURLConnection) urlObject.openConnection();        connection.setRequestMethod("POST");        connection.setDoOutput(true);        connection.setRequestProperty("Content-Type", "application/json");        String requestBody = JSON.toJSONString(templateMessage);        byte[] requestBodyBytes = requestBody.getBytes(StandardCharsets.UTF_8);        connection.setRequestProperty("Content-Length", String.valueOf(requestBodyBytes.length));        OutputStream outputStream = connection.getOutputStream();        outputStream.write(requestBodyBytes);        outputStream.close();        int responseCode = connection.getResponseCode();        BufferedReader reader;        if (responseCode >= 200 && responseCode <= 299) {            reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));        } else {            reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));        }        StringBuilder response = new StringBuilder();        String line;        while ((line = reader.readLine()) != null) {            response.append(line);        }        reader.close();        connection.disconnect();        System.out.println("Response Code: " + responseCode);        System.out.println("Response Body: " + response.toString());        return response.toString();    }}

3.3.5. 最终的Servlet(controller自行转换)(为方便观看所有逻辑都写在这里了,自行优化):

import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.UnsupportedEncodingException;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLEncoder;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject;import com.xx.srm.pojo.AccessToken;import com.xx.xx.pojo.TemplateMessage;import com.xx.xx.pojo.WeChatTemplateMsg;import com.xx.xx.utils.WXPublicAccountHttpUtil;@WebServlet(urlPatterns = {"/wx", "/wx/message" })public class WxServlet extends HttpServlet {    // 必须替换private static final String wxToken = "xxxxxm8";    // 必须替换public static final String APPID = "wx3xxxxxx1795fa";    // 必须替换public static final String SECRET = "57b96fxxxxxxxxeab62bfe3";    // 必须替换public static final String MESSAGE_TEMPLATE_ID = "N6MyyAF0Ucxxxxxxxxxxxxxxxxp-OGsWnQut_niUAaY";private static AccessToken at;@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {if ("/wx".equals(request.getServletPath())) {doGetWx(request, response);} else if ("/wx/message".equals(request.getServletPath())) {doSendMessage(request, response);}}public void doGetWx(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String signature = request.getParameter("signature");String timestamp = request.getParameter("timestamp");String nonce = request.getParameter("nonce");String echostr = request.getParameter("echostr");// 将微信echostr返回给微信服务器try (OutputStream os = response.getOutputStream()) {String sha1 = getSHA1(wxToken, timestamp, nonce, "");// 和signature进行对比if (sha1.equals(signature)) {// 返回echostr给微信os.write(URLEncoder.encode(echostr, "UTF-8").getBytes());os.flush();}} catch (Exception e) {e.printStackTrace();}}private void doSendMessage(HttpServletRequest request, HttpServletResponse response) throws IOException {String token = getToken();String url = "https://api.weixin.qq.com/cgi-bin/user/get?" + "access_token=" + token;// 获取 openid 数组List userOpenids = WXPublicAccountHttpUtil.getOpenidList(url);// 主要的业务逻辑:for (String openId : userOpenids) {TemplateMessage templateMessage = new TemplateMessage();templateMessage.setTouser(openId);templateMessage.settemplate_id(MESSAGE_TEMPLATE_ID);templateMessage.setTopcolor("#FF0000");// key对应创建模板内容中的形参//{{title.DATA}} {{username.DATA}} {{quote.DATA}} {{date.DATA}} // WeChatTemplateMsg对应实参和字体颜色Map data = new HashMap();data.put("title", new WeChatTemplateMsg("你有一条新的消息", "#173177"));data.put("username", new WeChatTemplateMsg("黄先生", "#173177"));data.put("date", new WeChatTemplateMsg("2023年05月29日 16时24分", "#173177"));data.put("quote", new WeChatTemplateMsg("你好", "#173177"));templateMessage.setData(data);System.out.println(templateMessage);WXPublicAccountHttpUtil.sendMessage(getToken(), templateMessage);}}public static String getToken() {if (at == null || at.isExpired()) {getAccessToken();}return at.getAccessToken();}private static void getAccessToken() {// 发送请求获取tokenString token = null;try {String url ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"+ "&appid=" + APPID + "&secret=" + SECRET;token = WXPublicAccountHttpUtil.get(url);} catch (Exception e) {e.printStackTrace();}JSONObject jsonObject = JSONObject.parseObject(token);String accessToken = (String) jsonObject.get("access_token");Integer expiresIn = (Integer) jsonObject.get("expires_in");// 创建token对象,并存储at = new AccessToken(accessToken, String.valueOf(expiresIn));System.out.println(token);}public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws Exception {try {String[] array = new String[] { token, timestamp, nonce, encrypt };StringBuffer sb = new StringBuffer();// 字符串排序Arrays.sort(array);for (int i = 0; i < 4; i++) {sb.append(array[i]);}String str = sb.toString();// SHA1签名生成MessageDigest md = MessageDigest.getInstance("SHA-1");md.update(str.getBytes());byte[] digest = md.digest();StringBuffer hexstr = new StringBuffer();String shaHex = "";for (int i = 0; i < digest.length; i++) {shaHex = Integer.toHexString(digest[i] & 0xFF);if (shaHex.length() < 2) {hexstr.append(0);}hexstr.append(shaHex);}return hexstr.toString();} catch (Exception e) {e.printStackTrace();}return "";}}

3.4.测试

关注公众号

浏览器访问 http://22717eef.r6.vip.cpolar.cn/xjsrm/wx/message(替换为自己的)

查看微信消息

来源地址:https://blog.csdn.net/weixin_52156647/article/details/130944682

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java微信公众号发送消息-保姆级教程附源码

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

java微信公众号推送消息教程

本教程提供Java微信公众号消息推送指南,涵盖先决条件、依赖项、获取访问令牌、推送文本消息、图片消息、语音消息等功能。通过使用Java语言和第三方库,开发者可以实现微信公众号与用户交互的推送消息功能。
java微信公众号推送消息教程
2024-04-02

java微信公众号消息推送教程

本教程详细介绍了Java微信公众号消息推送的流程。首先需要准备AppID、AppSecret等信息。然后编写代码,包括引入相关库、定义消息推送方法、获取AccessToken方法以及获取HttpClient方法。接着在Java项目中测试代码。需要注意的是,AccessToken有效期为2小时,消息推送频率有限制,消息内容不能包含违规信息。
java微信公众号消息推送教程
2024-04-02

Java怎么实现微信公众号发送模版消息

这篇文章主要介绍Java怎么实现微信公众号发送模版消息,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!微信公众号发送模版消息 背景:如下图,当用户发布需求的时候,公众号自定推送消息。例如:微信支付的时候,公众号会推送支
2023-06-29

微信公众号推送天气教程,自动定时推送【Java版】开发者和小白详细教程

GitHub源码链接放这里 建议先打开,因为GitHub在国内加载很慢。 点击打开 Java版本,教程最近一次更新时间为: 2022-11-08 目录: 1.通用准备 2.面向开发者 3.面向小bai 4.联系作者 5.常见问题 通用准备
2023-08-17

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录