相信善良 發表於 2020-10-23 09:16:00

spring-boot-route(二十三)开发微信公众号

<p>在讲微信公众号开发之前,先来大概了解一下微信公众号。微信公众号大体上可以分为服务号和订阅号,订阅号和服务号的区别如下:</p>
<ol>
<li>服务号可以申请微信支付功能。</li>
<li>服务号只能由企业申请,订阅号可以有企业或个人申请。</li>
<li>订阅号和服务号每月推送消息次数不同,订阅号每天可以推送一次,服务号每月可以推送四次。</li>
<li>服务号推送的消息会出现在用户的聊天列表中,而订阅号推送的消息显示在订阅号文件夹中。</li>
<li>还有一些其他接口功能的区别和限制,总的来说服务号支持更高级的功能开发。</li>
</ol>
<p>订阅号更加偏向于向用户传递咨询,一般各种技术类公众号都属于订阅号,订阅号的消息推送并不会有太显眼的提醒,如果你想让某个公众号的推送内容更加显眼,可以选择置为星标。置为星标后公众号会显示在所有订阅号的最顶部,同时收到消息后会有黄色五角星星标提醒。</p>
<h2 id="一-公众号配置服务器">一 公众号配置服务器</h2>
<p>微信官方提供了非常完善的接入文档,如果想了解文档的具体内容,直接浏览器搜索<strong>微信开发文档</strong>就可以了。但是为了方便开发,一般不会直接去根据微信开发文档进行开发,gitee上有许多开源项目对微信开发文档进行了封装,这里我使用<code>mica-weixin</code>开发包进行演示,<code>mica-weixin</code>是<code>jfinal-weixin</code>的boot版本。</p>
<p>配置服务器信息很简单,具体流程就是<strong>微信服务发送请求一个请求给业务服务器,业务服务器验证请求后给微信服务一个响应</strong>。</p>
<h3 id="11-搭建业务服务">1.1 搭建业务服务</h3>
<p>本地搭建一个<code>spring-boot-weixin</code>的项目,使用内网穿透工具进行穿透,使其可以与外网进行通信。</p>
<h4 id="111-引入mica-weixin依赖">1.1.1 引入<code>mica-weixin</code>依赖</h4>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;net.dreamlu&lt;/groupId&gt;
    &lt;artifactId&gt;mica-weixin&lt;/artifactId&gt;
    &lt;version&gt;2.0.1&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
<h4 id="112-配置公众号信息">1.1.2 配置公众号信息</h4>
<p><code>mica-weixin</code>通过配置文件进行公众号信息的配置,如果你想通过数据库配置公众号信息,可以参考我以前写过的一篇文章jfinal-weixin自定义配置支持多公众号。</p>
<pre><code class="language-yml">dream:
weixin:
    wx-configs:
    - appId: xxxxxx
      appSecret: xxxxxx
      token: javatrip
      encodingAesKey: xxxxxx
</code></pre>
<p><code>appId</code>和<code>appSecret</code>可在公众号后台进行查看,具体位置在菜单<strong>开发—&gt;基本配置</strong>中,其中<code>appSecret</code>要妥善保管,现在公众号已经不支持查看<code>appSecret</code>了,如果你忘了<code>appSecret</code>,只能进行重置。</p>
<h4 id="113-开发消息校验接口">1.1.3 开发消息校验接口</h4>
<p><code>mica-weixin</code>已经为我们提供好了消息校验接口,只需要继承<code>DreamMsgControllerAdapter</code>就可以了。</p>
<pre><code class="language-java">@WxMsgController("/weixin/wx")
public class WeiXinMsgController extends DreamMsgControllerAdapter {
    @Override
    protected void processInFollowEvent(InFollowEvent inFollowEvent) {
    }

    @Override
    protected void processInTextMsg(InTextMsg inTextMsg) {
    }

    @Override
    protected void processInMenuEvent(InMenuEvent inMenuEvent) {
    }
}
</code></pre>
<p>同时,需要开启缓存,由于<code>mica-weixin</code>的将<code>access_token</code>等信息放在了缓存中。在启动类上加<code>@EnableCaching</code>就开启了。</p>
<pre><code class="language-java">@SpringBootApplication
@EnableCaching
public class WeixinApplication {
    public static void main(String[] args) {
      SpringApplication.run(WeixinApplication.class, args);
    }
}
</code></pre>
<h4 id="114-公众号后台配置服务器信息">1.1.4 公众号后台配置服务器信息</h4>
<p>使用内网穿透工具穿透内网地址,然后在公众号后台菜单<strong>开发—&gt;基本配置</strong>中填写服务器配置信息。</p>
<p><img src="https://i.loli.net/2020/08/27/PDwiB9cgTGkIJvr.png" alt="" loading="lazy"></p>
<p>填写完成后点击启用,这样就完成了微信服务器和业务服务器的关系配置。开启开发者配置后,自动回复、自定义菜单等功能都不能正常使用了。这时候就需要去调用对应的接口实现这些功能。</p>
<p><img src="https://i.loli.net/2020/08/27/nfciYyoJkMwarDU.png" alt="" loading="lazy"></p>
<h2 id="二-实现各种消息接口">二 实现各种消息接口</h2>
<h3 id="21-关注消息">2.1 关注消息</h3>
<p>在一步中,自定义类<code>WeiXinMsgController</code>中需要重写三个父类中的方法,其中<code>processInFollowEvent()</code>就是关注和取消关注的方法,取消关注后用户虽然不能收到消息,但是后台可以接收到用户取消关注的事件。</p>
<pre><code class="language-java">@Override
protected void processInFollowEvent(InFollowEvent inFollowEvent) {

    OutTextMsg defaultMsg = new OutTextMsg(inFollowEvent);
    // 关注
    if(InFollowEvent.EVENT_INFOLLOW_SUBSCRIBE.equals(inFollowEvent.getEvent())){
      // 可将关注用户录入db,此处可以获取到用户openid
      String openId = inFollowEvent.getFromUserName();
      // 查询db,根据响应消息类型封装消息体
      if("文本消息"){
            OutTextMsg otm = new OutTextMsg(inFollowEvent);
            otm.setContent("消息内容");
            render(otm);
            return;
      }else if("图片消息"){
            OutImageMsg oim = new OutImageMsg(inFollowEvent);
            // 这里需要调用微信提供的素材接口,将图片上传至素材库。
            oim.setMediaId("图片素材id");
            render(oim);
            return;
      }else if("图文消息"){
            OutNewsMsg onm = new OutNewsMsg(inFollowEvent);
            onm.addNews("标题","简介","图片地址","图文链接");
            render(onm);
            return;
      }else if("视频消息"){
            OutVideoMsg ovm = new OutVideoMsg(inFollowEvent);
            ovm.setTitle("标题");
            ovm.setDescription("简介");
            ovm.setMediaId("视频素材id");
            render(ovm);
            return;
      }else{
            defaultMsg.setContent("感谢关注");
      }
    }
    // 取消关注
    if(InFollowEvent.EVENT_INFOLLOW_UNSUBSCRIBE.equals(inFollowEvent.getEvent())){
      log.info("用户取消关注了");
      // 此处可以将取消关注的用户更新db
    }
}
</code></pre>
<h3 id="22-关键词消息">2.2 关键词消息</h3>
<p>响应内容跟关注消息一样,查询db去匹配关键词,然会根据消息内容封装对应的消息体进行返回,如果没匹配到关键词则回复统一的消息内容。<code>processInTextMsg()</code>方法就是用来回复关键词消息的。</p>
<pre><code class="language-java">@Override
protected void processInTextMsg(InTextMsg inTextMsg) {

    String content = inTextMsg.getContent();
    // 根据用户发送的content去查询db中的响应内容
    if("文本消息"){
      OutTextMsg otm = new OutTextMsg(inTextMsg);
      otm.setContent("消息内容");
      render(otm);
      return;
    }else if("图片消息"){
      OutImageMsg oim = new OutImageMsg(inTextMsg);
      // 这里需要调用微信提供的素材接口,将图片上传至素材库。
      oim.setMediaId("图片素材id");
      render(oim);
      return;
    }else if("图文消息"){
      OutNewsMsg onm = new OutNewsMsg(inTextMsg);
      onm.addNews("标题","简介","图片地址","图文链接");
      render(onm);
      return;
    }else if("视频消息"){
      OutVideoMsg ovm = new OutVideoMsg(inTextMsg);
      ovm.setTitle("标题");
      ovm.setDescription("简介");
      ovm.setMediaId("视频素材id");
      render(ovm);
      return;
    }else{
      OutTextMsg otm = new OutTextMsg(inTextMsg);
      otm.setContent("暂未查到关键词...");
    }
}
</code></pre>
<h3 id="23-菜单消息">2.3 菜单消息</h3>
<p>点击菜单后也是一样,通过<code>processInMenuEvent()</code>方法进行响应内容的回复。</p>
<pre><code class="language-java">@Override
protected void processInMenuEvent(InMenuEvent inMenuEvent) {
    String eventKey = inMenuEvent.getEventKey();
    // 根据用户发送的content去查询db中的响应内容
    if("文本消息"){
      OutTextMsg otm = new OutTextMsg(inMenuEvent);
      otm.setContent("消息内容");
      render(otm);
      return;
    }else if("图片消息"){
      OutImageMsg oim = new OutImageMsg(inMenuEvent);
      // 这里需要调用微信提供的素材接口,将图片上传至素材库。
      oim.setMediaId("图片素材id");
      render(oim);
      return;
    }else if("图文消息"){
      OutNewsMsg onm = new OutNewsMsg(inMenuEvent);
      onm.addNews("标题","简介","图片地址","图文链接");
      render(onm);
      return;
    }else if("视频消息"){
      OutVideoMsg ovm = new OutVideoMsg(inMenuEvent);
      ovm.setTitle("标题");
      ovm.setDescription("简介");
      ovm.setMediaId("视频素材id");
      render(ovm);
      return;
    }else{
      OutTextMsg otm = new OutTextMsg(inMenuEvent);
      otm.setContent("无效链接,请重试...");
    }
}
</code></pre>
<h3 id="三-接口api调用">三 接口API调用</h3>
<p>目前,微信提供的接口对订阅号的限制比较大,未认证的订阅号基本上只有接收消息的几个功能接口。</p>
<p>调用接口的时候需要传递<code>token</code>,获取token需要在微信后台中配置业务服务器的白名单。如下:</p>
<p><img src="https://i.loli.net/2020/08/27/TRMA8ZVJbt65k1v.png" alt="" loading="lazy"></p>
<p>如果需要配置多个白名单ip,使用回车键将多个ip分隔开。</p>
<p><code>mica-weixin</code>提供了所有的接口封装,具体可参考它的官方文档,如果要获取微信菜单,可以这样写:</p>
<pre><code class="language-java">@WxApi("weixin/api")
public class WeiXinApiController {
    @GetMapping("menu")
    @ResponseBody
    public String getMenu(){
      ApiResult menu = MenuApi.getMenu();
      return menu.getJson();
    }
}
</code></pre>
<p><code>@WxApi</code>这个是它的自定义注解,其实就是包含了<code>@RequestMapping</code>和<code>@Controller</code>。</p>
<h2 id="四-其他事项">四 其他事项</h2>
<h3 id="41-多公众号配置">4.1 多公众号配置</h3>
<p><code>mica-weixin</code>提供了多公众号配置的功能,使用<code>ThreadLocal</code>和<code>appid</code>进行绑定。只需要简单配置即可实现多公众号配置。</p>
<pre><code class="language-yml">dream:
weixin:
    wx-configs:
      - appId: xxxxxx
      appSecret: xxxxxx
      token: javatrip
      encodingAesKey: xxxxxx
      - appId: xxxxxx
      appSecret: xxxxxx
      token: javatrip
      encodingAesKey: xxxxxx
</code></pre>
<h3 id="42-redis配置">4.2 redis配置</h3>
<p><code>access_token</code>的有效期是2小时,并且该接口有调用次数限制,<code>mica-weixin</code>将<code>access_token</code>存储在redis中,避免每次调用接口都去获取<code>access-token</code>,因此项目需要配置redis。</p>
<pre><code class="language-yml">spring:
redis:
    host: localhost
    port: 6379
</code></pre>
<h3 id="43-手动选择threadlocal">4.3 手动选择ThreadLocal</h3>
<p>如果想要开发微信公众号的后台管理功能,多公众号的时候就需要手动去指定当前线程使用哪个公众号信息。如下:</p>
<pre><code class="language-java">ApiConfigKit.setThreadLocalAppId(appid);
</code></pre>
<p>至此,SpringBoot开发微信公众号就算完成了,由于订阅号开放的接口太少了,好多功能不能正常演示。还有<code>mica-weixin</code>也许不是最好的选择,如果想试着开发微信公众号,可以在gitee上找一下开发包。至于我为什么会使用<code>mica-weixin</code>,是因为我曾用过一段时间的<code>jfinal</code>框架,与之配套的微信开发包就是<code>jfinal-weixin</code>,也就是jfinal版的<code>mica-weixin</code>。</p>
<hr>
<p>更多优质内容推荐访问 毕设侠</p><br><br>
来源:https://www.cnblogs.com/zhixie/p/13862263.html
頁: [1]
查看完整版本: spring-boot-route(二十三)开发微信公众号