天啦噜!微信公众号开发如此简单!竟然是因为……

当然是因为wx-tools啦!


springboot+wx-tools实践!音乐爬虫推送公众号DEMO

GitHub地址:wx-tools

最终DEMO源码地址: music_collector

先理一下大概的开发步骤:

  1. 创建一个Web工程(可以是Servlet/Spring Web/Spring boot)
  2. pom引入wx-tools / 手动引入wx-tools.jar包(可以去github下载自己build)
  3. 编写wx.properties配置文件
  4. 接入微信公众平台,验证服务器地址的有效性
  5. 实现自己的业务逻辑

简单吗?接下来一起写一个简单的Demo吧


1. 创建web项目

注意!本demo使用的是SpringBoot,如果你使用原生servlet,原理是一样的。这里就不再演示。

使用maven创建,或者在eclipse/IDEA创建web项目。

如何创建web项目,相信大家都会的了。就不详细介绍了。如果不会,自行度娘。

基于SpringBoot爬虫项目

这里我我基于springBoot创建了一个项目名为:music_collector

music_collector是一个爬虫项目,爬取各大音乐网的排行榜,并且可以支持设置关键字,来查询微信图文推送并推送给用户。(原理是通过搜狗搜索)

具体创建SpringBoot,这里就不赘述了。百度一下就知道了。


  • 如果使用maven创建项目,指令如下:
mvn archetype:generate -DgroupId=wxtools.demo -DartifactId=demo -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeCatalog=local
  • 注意:此指令创建的web工程版本是2.3的,比较低。可以修改web.xml,变成3.0
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"><display-name>demo</display-name>
</web-app>

引入wx-tools依赖

  • maven地址(最新版本可以去中央库查询wx-tools)
<dependency><groupId>com.soecode.wx-tools</groupId><artifactId>wx-tools</artifactId><version>2.1.4-RELEASE</version>
</dependency>

注意:如果需要看源代码的务必手动修改编码。导入后记得修改jar包的编码。window下默认读GBK,而框架本身是UTF-8。

  • 修改方式:在eclipse的工程下,对着jar包右键 --> Properties --> Encoding --> UTF-8

创建wx.properties配置文件

  • 搭好项目基本框架后,在src/main/resources下新建wx.properties文件
#配置如下
wx.appId=你的appId
wx.appSecret=你的appSecret
wx.token=你设置的token
wx.aesKey=如果选择安全模式,需要填入。如果是明文模式,填空就好了
wx.mchId=商户ID

最终项目目录结构如下:

不要填错了哦!注意大小写。


2. 验证服务器地址的有效性


2.3.1 启动web服务

可以使用SpringBoot启动或者tomcat/jBoss都可以。

内网映射

微信开发需要把本地127.0.0.1映射到公网上,微信服务器才可以把消息推送给你的程序。

映射工具有很多,例如:花生壳、Ngrok等。这里使用了免费版的Ngrok。
ngrok客户端windows+64版

  • 使用方法很简单:下载解压,双击打开,输入二级域名即可把本地127.0.0.1映射出去。

验证一下服务器的有效性

这时候,wx-tools下的所有api都可以调用了。

我们验证一下服务器的有效性。

验证接口官方文档 建议先看官方文档,理解好开发步骤,在继续下去。

  • 编写WxController对接微信服务器

@RestController
@RequestMapping("/wx")
public class WxController {private IService iService = new WxService();@GetMappingpublic String check(String signature, String timestamp, String nonce, String echostr) {if (iService.checkSignature(signature, timestamp, nonce, echostr)) {return echostr;}return null;}}
  • 开启服务,然后去微信公众平台后台或者测试号后台填写资料验证即可。( 确保wx.properties与微信后台配置一致即可。)

  • 打开微信配置后台:(这里我是用测试号的,还没有测试号的可以点击这里申请)

如果发现可以连接,就说明已经与微信服务器对接成功(验证成功)。接下来任何对你的公众号操作,微信服务器都会转发消息给你的服务器(你的程序)。


3. 接收微信服务器发来的消息


当你验证服务器有消息成功后,微信服务器就会把你的公众号任何事件和消息,以post请求推送到你验证的那个url地址上。所以我们现在需要做的就是写一个Post接收方法,来接收发来的消息~

完善WxController,添加Post接收方法

@RestController
@RequestMapping("/wx")
public class WxController {private IService iService = new WxService();@GetMappingpublic String check(String signature, String timestamp, String nonce, String echostr) {if (iService.checkSignature(signature, timestamp, nonce, echostr)) {return echostr;}return null;}@PostMappingpublic void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");PrintWriter out = response.getWriter();try {// 微信服务器推送过来的是XML格式。WxXmlMessage wx = XStreamTransformer.fromXml(WxXmlMessage.class, request.getInputStream());System.out.println("消息:\n " + wx.toString());} catch (Exception e) {e.printStackTrace();} finally {out.close();}}
}

可以看到,我把微信服务器发来的消息(request)的输入流扔给了XStreamTransformer来帮忙解析XML,并返回WxXmlMessage类。

  • WxXmlMessage类是统一消息的载体。所有消息包括事件推送都包含在这个类当中。

尝试与公众号交互,观察控制台

这时候,我们可以尝试向公众号发送一句:“Hello”。我们看一下结果。

wx-tools自动把发来的消息封装成一个类,方便处理。

我们再试试接收并解析事件(Event)推送,例如:新用户关注事件推送。

我用另一个微信号关注了一波我的测试号,观察控制台:

好了,至此。你已经成功一大半了。为什么呢!因为剩下的就是拿着这个消息(Message)去各种处理,最后返回给用户想要的东西即可~

下篇会讲一些路由器的使用方式,请移步下篇!嘻嘻


4. WxMessageRouter的使用例子


创建菜单栏

假设一下,我现在想把公众号的菜单栏设置成这样的:

我们可以写一个Main方法,来更改公众号的菜单栏,代码如下:

public class Menu {public static void main(String[] args) {IService iService = new WxService();WxMenu menu = new WxMenu();List<WxMenu.WxMenuButton> btnList = new ArrayList<>();//飙升功能WxMenu.WxMenuButton btn1 = new WxMenu.WxMenuButton();btn1.setName("分类");List<WxMenu.WxMenuButton> subList = new ArrayList<>();WxMenu.WxMenuButton btn1_1 = new WxMenu.WxMenuButton();btn1_1.setType(WxConsts.MENU_BUTTON_CLICK);btn1_1.setKey(MenuKey.HOT_SONG);btn1_1.setName("飙升榜");WxMenu.WxMenuButton btn1_2 = new WxMenu.WxMenuButton();btn1_2.setType(WxConsts.MENU_BUTTON_CLICK);btn1_2.setKey(MenuKey.TOP_500);btn1_2.setName("TOP500");WxMenu.WxMenuButton btn1_3 = new WxMenu.WxMenuButton();btn1_3.setType(WxConsts.MENU_BUTTON_CLICK);btn1_3.setKey(MenuKey.NET_HOT_SONG);btn1_3.setName("网络红歌");WxMenu.WxMenuButton btn1_4 = new WxMenu.WxMenuButton();btn1_4.setType(WxConsts.MENU_BUTTON_CLICK);btn1_4.setKey(MenuKey.HUAYU_SONG);btn1_4.setName("华语新歌");WxMenu.WxMenuButton btn1_5 = new WxMenu.WxMenuButton();btn1_5.setType(WxConsts.MENU_BUTTON_CLICK);btn1_5.setKey(MenuKey.XINAO_SONG);btn1_5.setName("洗脑神曲");WxMenu.WxMenuButton btn2 = new WxMenu.WxMenuButton();btn2.setType(WxConsts.MENU_BUTTON_CLICK);btn2.setKey(MenuKey.CHANGE_NEWS);btn2.setName("换一组");WxMenu.WxMenuButton btn3 = new WxMenu.WxMenuButton();btn3.setType(WxConsts.MENU_BUTTON_CLICK);btn3.setKey(MenuKey.HELP);btn3.setName("帮助");subList.addAll(Arrays.asList(btn1_1, btn1_2, btn1_3, btn1_4, btn1_5));btn1.setSub_button(subList);//将三个按钮设置进btnListbtnList.add(btn1);btnList.add(btn2);btnList.add(btn3);//设置进菜单类menu.setButton(btnList);//调用API即可try {//参数1--menu  ,参数2--是否是个性化定制。如果是个性化菜单栏,需要设置MenuRuleiService.createMenu(menu, false);} catch (WxErrorException e) {e.printStackTrace();}}
}
  • 接下来直接运行就行了,你就会看到你的公众号菜单栏的变化。

菜单栏的参数设置,请参考官方文档 - 菜单栏的创建, 菜单栏的按钮有分很多种类型(type),例如click,view等。详情建议先看官方文档。

创建消息路由并设置第一个规则(Rule)

假设需求如下: 我只接收菜单栏类型为:Click,且Key为MenuKey.HELP的消息,其他一律放弃不接收。

正常来说,常规写法应该是加一个if判断,例如:

if("CLICK".equals(message.event) &&  MenuKey.HELP.equals(message.eventKey)){doSomething();
}

这样的写法会随着需求增多,而越来越庞大臃肿。

而wx-tools使用消息路由的方式去过滤处理消息,写法如下:

  • 补充WxController中的Post处理方法:
    @PostMappingpublic void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");PrintWriter out = response.getWriter();// 创建一个路由器WxMessageRouter router = new WxMessageRouter(iService);try {// 微信服务器推送过来的是XML格式。WxXmlMessage wx = XStreamTransformer.fromXml(WxXmlMessage.class, request.getInputStream());System.out.println("消息:\n " + wx.toString());router.rule().event(WxConsts.EVT_CLICK).eventKey(MenuKey.HELP).handler(HelpDocHandler.getInstance()).end();// 把消息传递给路由器进行处理WxXmlOutMessage xmlOutMsg = router.route(wx);if (xmlOutMsg != null)// 因为是明文,所以不用加密,直接返回给用户out.print(xmlOutMsg.toXml());。} catch (Exception e) {e.printStackTrace();} finally {out.close();}}
  • HelpDocHandler.java代码如下:

Handler代码采用单例模式,为了解决消息重试的问题。但由于网络问题导致返回结果慢了。会自动重试,返回多条信息。当然,这种做法不建议你们使用,因为这样写,同一时间仅仅允许一个线程进来处理,并不适合多线程环境。

因为这个音乐爬虫项目是做给我女票使用的,用户仅仅只有一个。所以我可以这么做,而你不们作为项目,不可以!!!好了继续~

官方关于消息重试的机制点击这里查看。

public class HelpDocHandler implements WxMessageHandler {private static HelpDocHandler instance = null;private boolean isRun = false;private HelpDocHandler(){}public static synchronized HelpDocHandler getInstance(){if (instance == null) {instance = new HelpDocHandler();}return instance;}private synchronized  boolean getIsRun() {return isRun;}private synchronized void setRun(boolean run) {isRun = run;}@Overridepublic WxXmlOutMessage handle(WxXmlMessage wxMessage, Map<String, Object> context, IService iService) throws WxErrorException {WxXmlOutMessage response = null;if (!getIsRun()) {setRun(true);response = execute(wxMessage);setRun(false);}return response;}private WxXmlOutMessage execute(WxXmlMessage wxMessage) {return WxXmlOutMessage.TEXT().content(ResponseConst.HELP).toUser(wxMessage.getFromUserName()).fromUser(wxMessage.getToUserName()).build();}
}
  • 接下来测试一下,点击公众号的帮助按钮,正常返回帮助说明。而点击其他按钮,均无反应。

这样我们就成功利用消息路由和创建第一个规则(Rule)去过滤消息,并处理返回了。

是不是很简单~2333

现在我们尝试使用wx-tools其他特性,添加更多的功能进去吧~gogogo


完成菜单栏剩余功能


按钮[分类-飙升榜]

需求:当用户点击此按钮,后台爬虫帮我爬当天酷狗飙升榜的列表下来,并返回。 酷狗飙升榜在这。

  • 爬虫技术不是本文档的主要内容,所以在此就不细讲如何爬下数据。有兴趣的同学可以阅读下源代码。(原理很简单,仅仅使用HttpClient+Jsoup)

添加RankHandler.java

此handler专门处理爬虫分类Event事件。

RankHandler.java:(负责处理消息部分)

public class RankHandler implements WxMessageHandler {private static RankHandler instance = null;private boolean isRun = false;private RankHandler() {}public static synchronized RankHandler getInstance() {if (instance == null) {instance = new RankHandler();}return instance;}@Overridepublic WxXmlOutMessage handle(WxXmlMessage wxMessage, Map<String, Object> context, IService iService)throws WxErrorException {StringBuilder result = new StringBuilder();if (!getIsRun()) {setRun(true);try {result = execute(wxMessage);} catch (Exception e) {e.printStackTrace();} finally {setRun(false);}} else {result.append(ResponseConst.DUPLICATE_REQUEST);}return WxXmlOutMessage.TEXT().content(result.toString()).toUser(wxMessage.getFromUserName()).fromUser(wxMessage.getToUserName()).build();}private StringBuilder execute(WxXmlMessage wxMessage) throws Exception{StringBuilder stringBuilder = new StringBuilder();try {switch (wxMessage.getEventKey()) {case MenuKey.HOT_SONG:collectSongRank(stringBuilder, UrlConst.HOT_RANK_URL);break;default:stringBuilder.append("暂时无此分类噢!");break;}} catch (IOException e) {e.printStackTrace();}return stringBuilder;}private void collectSongRank(StringBuilder stringBuilder, String url) throws IOException {RankCollector collector = new RankCollector();Rank rank = collector.collect(url);stringBuilder.append("\uD83D\uDD25" + rank.getScope() + "[" + rank.getUpdateTime() + "]\n\n");for (HotSinger hotSinger : rank.getHotSingerList()) {stringBuilder.append(hotSinger.getName() + "-" + hotSinger.getHotSong() + "\n");}}private synchronized boolean getIsRun() {return isRun;}private synchronized void setRun(boolean run) {isRun = run;}}

RankCollector.java: (爬虫部分)

public class RankCollector {public Rank collect(String url) throws IOException {return getRank(url);}private Rank getRank(String rankUrl) throws IOException {Rank rank = new Rank();String body = HttpClientUtil.get(rankUrl);Document doc = Jsoup.parse(body);rank.setScope(doc.select("a[class=current]").attr("title"));rank.setUpdateTime(doc.select("span[class=rank_update]").text());List<Element> aElements = doc.select("a[data-active=playDwn]");for(int i = 0; i < aElements.size(); i++){String[] splitArray = aElements.get(i).text().split("-");String name = splitArray[0].toString().trim();String song = splitArray[1].toString().trim();rank.getHotSingerList().add(new HotSinger(doc.select("a[class=current]").attr("title"), name, song));}return rank;}
}

添加新的规则(Rule)

修改新增WxController的路由规则:

router.rule().event(WxConsts.EVT_CLICK).eventKey(MenuKey.HELP).handler(HelpDocHandler.getInstance()).next().rule().eventKey(MenuKey.HOT_SONG).handler(RankHandler.getInstance()).end();
  • 这里解释一下:next()和end()的意思。
  • next() 表示消息经过第一个规则(Rule)之后,允许继续匹配下面的规则,代表着同一个消息有可能被多个Handler处理。
  • end() 表示规则的结束。当消息满足某条规则时遇到end(),不会再往下匹配规则,就此结束。

重新运行,并测试

当天的飙升榜就这样返回回来了~很激动有木有!

  • 好了同一原理实现其他4个排行榜按钮的功能,这里就不展示了。详情可以查看demo源码。

5. WxMessageMatcher接口实现例子


WxMessageMatcher(消息匹配器)接口用于一些简单的匹配,可以自定义匹配逻辑,如格式验证。匹配成功则继续往下执行,否则不允许通过。

需求:我想当用户发送文本消息:“我是谁”时,后台获取该用户的微信用户信息(昵称)并返回。

创建WhoAmIMatcher.java

用于匹配符合”我是谁“的消息。

public class WhoAmIMatcher implements WxMessageMatcher{@Overridepublic boolean match(WxXmlMessage message) {if(StringUtils.isNotEmpty(message.getContent())){if(message.getContent().equals("我是谁")){return true;}}return false;}}

创建WhoAmIHandler.java

用于处理当匹配到“我是谁”的消息。

  • 修改路由规则:(这时候已经把所有的爬虫都写完啦!所以路由规则这么多!
router.rule().msgType(WxConsts.XML_MSG_TEXT).matcher(new WhoAmIMatcher()).handler(new WhoAmIHandler()).end().rule().event(WxConsts.EVT_CLICK).eventKey(MenuKey.HELP).handler(HelpDocHandler.getInstance()).next().rule().eventKey(MenuKey.HOT_SONG).handler(RankHandler.getInstance()).next().rule().eventKey(MenuKey.TOP_500).handler(RankHandler.getInstance()).next().rule().eventKey(MenuKey.NET_HOT_SONG).handler(RankHandler.getInstance()).next().rule().eventKey(MenuKey.HUAYU_SONG).handler(RankHandler.getInstance()).next().rule().eventKey(MenuKey.XINAO_SONG).handler(RankHandler.getInstance()).end();

运行,并测试

如图所示,输入”我是谁“的时候,返回了我微信的昵称。

小小总结一下

至此,我们已经尝试使用了路由器Router,规则Rule,匹配器Matcher,处理器Handler。

还有使用了IServer统一接口调用去获取用户信息。

IServer 接口是集成所有wx-tools已经实现的微信接口,统一调用入口。它的实现是WxService.java。想看实现源码的可以戳:这里


6.WxMessageInterceptor接口实现例子


WxMessageInterceptor(拦截器)功能与Matcher相同,用于过滤拦截,但是与Matcher最大的不同就是,它支持更复杂的业务处理,因为它携带了IService和上下文context,可以利用这两个参数进行业务处理。

  • IService : 统一接口调用入口。
  • context :上下文,可以向handler传递参数。

WxMessageInterceptor拦截器接口,可以处理更加复杂的验证。例如身份验证,时效校验等等。

由于我的音乐爬虫项目并没有涉及到这么深的处理,所以这里只给出一个DemoInterceptor看看。


假设需求:只有用户关注公众号时长大于3天才能参与活动。

  • 创建DemoInterceptor.java 实现 WxMessageInterceptor接口
/**
* Demo 拦截器,可以通过WxService做更加复杂的拦截,例如身份验证,权限验证等操作。
* @author antgan
*
*/
public class DemoInterceptor implements WxMessageInterceptor{public boolean intercept(WxXmlMessage wxMessage, Map context, IService wxService) throws WxErrorException {//可以使用wxService的微信API方法//可以在Handler和Interceptor传递消息,使用context上下文//可以实现自己的业务逻辑//这里就不编写验证关注三天以上的用户了if(/*用户关注时长大于3天*/){return true;}return false;}
}
  • 接下来你们都知道的,修改路由器规则,添加interceptor。

例如:

router.rule().matcher(new DemoMatcher()).interceptor(new DemoInterceptor()).handler(new DemoMessageHandler()).end();

搞定。接下来交给wx-tools去做吧~
简单吧!


7. 关于WxMessageRouter及Rule的详解


WxMessageRouter消息路由器,不知道你们理解了多少,接下来还是详细讲解一下需要注意的细节。

提到这个路由器,就要说说另一个东西:WxMessageRouterRule。简称规则(Rule)。

定义规则,用于对来自微信服务器的消息进行过滤和筛选,只针对有效消息进行处理,提高服务器处理效率。

通过链式配置路由规则(Rule),根据规则把来自微信的消息交给handler处理。

注意:

  1. 配置路由规则时尽量按照从细到粗的原则,否则可能消息可能会被提前处理
  2. 默认情况下消息只会被处理一次,除非使用 {WxMessageRouterRule的next()方法}
  3. 规则的结束必须用WxMessageRouterRule的end()方法或者WxMessageRouterRule的next()方法,否则不会生效。

使用方法:

//初始化一个路由器,把wxService传入。
WxMessageRouter router = new WxMessageRouter(wxService);
//新建路由规则,通过rule()方法创建新的规则,然后链式填写过滤条件。MSG_TYPE等参数填入WxConst中的常量,这里不作展示,可以查看WxConst代码或官方文档,有注释。
router.rule().msgType("MSG_TYPE").event("EVENT").eventKey("EVENT_KEY").content("CONTENT").matcher(matcher).interceptor(interceptor, ...).handler(handler, ...).end()
.rule().msgType("MSG_TYPE")...//另外一个匹配规则.end();
// 将WxXmlMessage交给消息路由器,处理后得到结果。
WxXmlOutMessage xmlOutMsg = router.route(wxXmlMessage);

关于路由规则条件

  1. 对于一条消息(WxXMLMessage)允许多个规则(Rule)去进行过滤和处理。用next()方法去连接两个规则。但是最后必须是以end()方法结束。
  2. 每条规则可以允许多个拦截器(Interceptor),多个处理器(Handler)处理。返回最后一个Handler处理的结果。
  3. 路由规则还提供正则表达式过滤,对于简单的过滤需求,如只接受数字消息。不想繁琐的建立Matcher匹配器。可以如下写法。
//正则表达式:^[0-9]*$只接受数字消息,其他消息过滤。
router.rule().rContent("^[0-9]*$").handler(new DemoHandler()).end();

去除多余消息,高效处理争对性消息,真是好用又简单。

小小总结一下

至此,如果你跟着做,并且都成功了话。你已经入门了wx-tools了。以后无非就是根据用户需求添加路由规则,并添加处理器去处理,入门教程就到此结束了。

DEMO的源码下载地址: music_collector

其实DEMO里还有关键字搜索并推送图文消息给用户的功能. 文档里没演示出来.有兴趣的同学可以查阅源代码.

最终效果图~可以是这样

互联网开发讨论群:577984291

公众号开发之wx-tools+springboot应用实战-音乐爬虫推送[JAVA]相关推荐

  1. 微信公众号开发之VS远程调试

    目录 (一)微信公众号开发之VS远程调试 (二)微信公众号开发之基础梳理 (三)微信公众号开发之自动消息回复和自定义菜单 (四)微信公众号开发之网页授权获取用户基本信息 (五)微信公众号开发之网页中及 ...

  2. 微信公众号开发之 “`高级接口`” 总结

    微信公众号开发之 "高级接口" 总结 代码如下: <?php// $weixin = new class_weixin("", "") ...

  3. WeChat - 微信公众号开发之.Net Core接入

    .net进行微信公众号开发的例子好像比较少,这里做个笔记 首先,我们需要让微信能访问到我们的项目,所以要么需要有一个可以部署项目的连接到公网下的服务器,要么可以通过端口转发将请求转发到我们的项目,总之 ...

  4. 微信公众号开发之H5页面跳转到指定的小程序

    前言: 最近公司有一个这样的需要,需要从我们在现有的公众号H5页面中加一个跳转到第三方小程序的按钮.之前只知道小程序之间是可以相互跳转的,今天查阅了下微信开发文档原来现在H5网页也支持小程序之间的跳转 ...

  5. 公众号开发之-node响应微信token验证

    微信公众号开发对新手实在太不友好了.官方文档给的又比较模糊,网上的文章也说的不太清楚,对与我们这种小白,很烦躁,中间遇到无数的坑,在此记录一下,免得以后忘记(ps:本人完全是一个新手小白,第一次接触微 ...

  6. 微信公众号开发之40164错误,获取不到access_token,获取不到jsapi_ticket错误问题...

    公司用开的微信签名接口突然间不能用了,调用的时候一直获取不到jsapi_ticket临时凭证,搞的我一脸懵逼,然后回想了下,接口代码没动过呀,公众号后台也只是设置过一次ip白名单,可是后来想了下,觉得 ...

  7. 微信公众号开发之jfinal wxin

    jfinal wxing大家可能不太熟悉,他是jfinal框架(中国开源框架),用这个做微信公众号开发,非常快的,因为他已经把所有的微信的接口都集成里面了,我们主要是调用它的按口 要是你们PM要快点开 ...

  8. c# 微信公众号开发之token验证第三方服务器

    初入微信,才发现真的一坑又一坑,小程序之前坑可能是前辈填掉了,前辈走后,公司开始搞公众平台,需要公众号开发,唯一后端的我,顶了上去. 服务器配置验证token,从官方文档理解就是,官方发送signat ...

  9. 微信公众号的二次开发(三、接收事件推送获取用户信息)

    在上篇<微信公众号的二次开发(二 自定义菜单的创建)>中我们介绍了自定义菜单的创建.本篇文章将介绍如何通过接收事件推送来获取用户信息.首先我们阅读官方文档: 根据官方文档的介绍 微信公众号 ...

最新文章

  1. 切尔西携手YouTube 英超第一家共享视频球队诞生
  2. delphi开发的小技巧----------------http://www.cto360.com/a/5000086716.shtml
  3. 手把手,嘴对嘴,讲解UCOSII嵌入式操作系统的任务调度策略(二)
  4. js ajax传对象数组参数,JS传递对象数组为参数给后端,后端获取
  5. PW Live 直播 | 清华大学博士生岂凡超:义原知识库的应用和扩充
  6. 关于同步VSS服务器上的代码发生Eclipse里面的项目全部不见了
  7. WebService传输DataSet的一点想法和实践-.NET教程,Web Service开发
  8. oracle查找clob中的值,Oracle 查找带有CLOB字段的所有表
  9. 深度学习自学(二十二):人脸检测人脸识别-嵌入式平台方案汇总
  10. java 如何去掉http debug日志_谈谈日志的最佳实践
  11. C语言 数组和指针
  12. 7.5日chinapub生日聚会
  13. 【编程|二十四点】关于编程解决二十四点的两种思路
  14. 工作转正申请自我评价
  15. IBM与广东中医院 携手共建智慧医疗
  16. SNF开发平台WinForm之六-上传下载组件使用-SNF快速开发平台3.3-Spring.Net.Framework
  17. java脚本引擎Rhino 入门
  18. 在群晖上搭建基于 PostgreSQL 的 Joplin Server
  19. 还不错,字母成熟了些!
  20. 实现一个canvas画板

热门文章

  1. Android抓包日记之Charles抓包软件的使用
  2. python玩微信小程序游戏_用python一步一步教你玩微信小程序【跳一跳】
  3. #HTML5网页中的文本与图像
  4. OSChina 周六乱弹 —— 下班调闹铃
  5. matlab 对mnist手写数字数据集进行判决分析_Python神经网络编程:手写数字的数据集MNIST...
  6. MySql索引失效及解决方案
  7. 网页黑名单系统的算法核心
  8. pandas中数据的复制
  9. 另一个伊甸 徽章效果获取方式汇总 23-03-04
  10. 机器学习 之 十大算法