微信公众号开发入门
<svg xmlns="http://www.w3.org/2000/svg" style="display: none"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0)"></path>
</svg>
<p><em>实在是太折腾,太难懂了。也太坑了。</em></p>
<p>下面是这几天来,有关微信公众号的工作总结。算不上全面,只是作为一个初学者的记录,仅以备忘。</p>
<h2>一、微信公众号开发,开发什么?</h2>
<p>公众号与小程序不同。小程序类似手机APP,独立开发,微信只是提供了一个入口;而公众号则基本上是在微信框架内。微信公众号本质上是用户的一个联系人,只不过是比较特殊的联系人而已。通过微信提供的公众号管理后台,无须任何编程,就可以很快搭建出一个像模像样的公众号,菜单、机器人客服、文章更新,五脏俱全。</p>
<p>但是,如果要更强的功能,就需要开发了。比如,<strong>机器人客服</strong>。通过公众号管理后台,可以定义一些自动回复语句,但毕竟不够智能,这时我们可以在互联网上搭建服务器,提供相应服务。当然,这需要准备好网址、域名。</p>
<p>第二个,<strong>菜单</strong>。公众号的菜单项点击后,可以是回复一些消息,或跳转到小程序,或打开一张网页。打开网页的话,如果是未经认证的公众号,只能打开公众号里的素材,或已经发表在当前公众号里的文章或图片、视频之类;而经过认证的公众号,则可以直接打开任意网址。这些网页,通常都会是部署在互联网上的所谓微信网页,它们使用了微信JS-SDK,上面有各种微信的元素,比如扫一扫啦,分享到朋友圈啦,诸如此类。那这部分,当然需要开发。</p>
<p>还有就是给关注者<strong>发送消息</strong>。我认为这是微信公众号最大的卖点。比如说,我关注了某个公众号,通过这个公众号的菜单,打开了相关小程序办事,事情有了进展,系统就可以通过这个公众号给我发消息,提示一下当前办事进度。我认为这是公众号开发中最值得做的工作。</p>
<p>当然,还有可以通过程序自动在公众号上发表文章。不过这种事情,人工在公众号管理后台也能做,无非动动手而已。</p>
<h2>二、开发铺垫</h2>
<p>在开发之前,先要了解一下有关的规约。建议也阅读一下开发文档的开始部分:微信公众平台开发概述</p>
<h3>1、公众号的分类</h3>
<p>衣穿三色,食分五等。所谓微信公众号,分为订阅号和服务号。个人只能申请订阅号,企业可以申请订阅号和服务号。然后公众号又有经过认证和未经认证之分。公众号类型,是否经过认证,决定了许多微信服务能否被调用。未经认证,基本上没有啥可以玩的。而且不幸的是,个人申请的订阅号,根本不能进行微信认证,直接堵死了这扇门。</p>
<p>那怎么开发?微信又很“贴心”地提供了<strong>测试账号</strong>这个机制。我们可以先不申请公众号,而是先申请一个测试账号,用这个账号来测试微信服务接口。测试账号所有微信服务接口都能访问。然鹅!像微信网页这些,需要跑在手机上才能看到效果,而如果用的是测试账号的话,有些东西是渲染不出来的。比如所谓的微信开放标签(就是微信自己定义的,类似HTML的标签)。</p>
<p>订阅号与服务号侧重点不同。按我的理解,订阅号侧重发表文章,服务号则侧重针对性发通知消息。总的来说,服务号功能比订阅号要强大许多。<br> <img src="https://i-blog.csdnimg.cn/blog_migrate/830dfb9f99c49e6bb6ade9eee8b1643b.png"><br> 表面上看,订阅号每天可以群发1条消息,而服务号只能每个月发4条,订阅号要强。问题是,群发消息有啥用?我们网上办事,要的是针对本人的消息。只有服务号才能发送这针对性的通知消息。<br> <img src="https://i-blog.csdnimg.cn/blog_migrate/b9007fd24ab1652e313e5929d8ce7486.png"><br> 文档里,管这种消息叫<strong>模板消息</strong>。为啥叫模板消息呢?是因为这种消息要结合模板生成。就像我们的手机短信。做过手机短信开发都知道,手机短信可不是随随便便就能发送的,因为众所周知的原因,怕有违法、出格的内容,要有所谓的模板,即短信格式是固定的,许多字眼也都是固定的,我们每次发送时只需往里面填一些内容。这个模板要事先创建好并通过电信运营商审批。微信这个消息也要使用模板,调用发送接口时,需要将模板ID作为参数传递。</p>
<p>目前,小程序的模板消息功能已经废弃了,改用所谓“统一服务消息”,其实就是改用服务号进行发送。就是说,小程序如果要给用户发送通知的话,必须要对应一个服务号。</p>
<p>不过世界上还有一种东西叫做订阅消息。公众号里叫做订阅通知,小程序里叫订阅消息。分为一次性和长期2种。订阅消息要用户主动订阅。比如用麦当劳小程序订餐,每次付款以后,它都会问你,要不要接受取餐通知。长期性只对某些民生、医院类的公众号开放。这个在申请公众号时就给定了性。不要心存侥幸,低估了微信折腾人的本事。否则,发送时对方总是收不到,错误提示可能没有;就算有,可能也专业得很,根本想不到是账号类型的问题。</p>
<p>模板消息和订阅消息有啥区别呢?订阅消息不就是要用户手动订阅一下嘛,也没啥。问题是,这就一定要用手机来操作啊。假如我是通过PC端来办事,想手机收到提醒呢?订阅消息就完犊子了。(是不是这样啊?微信PC端也能进行订阅操作?)</p>
<h3>2、公众号调试工具</h3>
<p>就是微信开发者工具。注意是开发者工具,而不是开发工具。这个工具,对于小程序来说,的确就是一个开发工具;而对于公众号来说,只是一个调试工具,并不能通过它来键入什么代码;而且只是微信网页的调试工具。此时它只是一个微信浏览器。方法是在微信开发者工具的顶部输入微信网页地址即可浏览,调试,跟普通浏览器按下<code>F12</code>差不多。</p>
<h3>3、查看微信网页运行结果</h3>
<p>公众号通过微信客户端就能看到。这里说的查看结果,是指查看 微信网页 的运行结果。虽然有网页二字,但这不是普通的网页,用一般浏览器访问,虽然不报错,但看不到什么效果,应该通过微信浏览器或者微信开发者工具来运行。注意手机上并没有一个app叫微信浏览器,这是微信隐含的。怎么召唤它呢?可以将微信网页的地址发给微信某个好友,比如“文件传输助手”,然后在聊天记录里点击这个网址,就会用微信浏览器打开。绝逼是微信浏览器,QQ浏览器都不好使。</p>
<h3>4、开发文档</h3>
<p>基于微信做二次开发,网上查资料基本没什么卵用,最好还是老老实实地啃微信官方开发文档。</p>
<p>公众号开发文档在 公众号管理后台 - 设置与开发 - 开发者工具 - 开发文档 打开。</p>
<p>微信有两个平台,小程序的叫“微信开发开放平台”,公众号的叫“微信开发公众平台”。</p>
<h3>5、一些术语</h3>
<p><strong>1)管理员及运营者</strong><br> 开发过程中,免不了要访问微信公众号管理后台,对某些设置作出修改或设置,但是改变设置必须扫二维码进行身份认证。这就尴尬了。申请公众号的人是管理员,但他不一定参与开发。如果下下都惊动这个大老板来扫二维码不方便,甚至不可能。可以把开发人员加到运营者名单里,自己扫码就行。运营者分长期和短期2种,应该是长期运营者,权限才够大。</p>
<p>可在 微信公众号管理后台 - 设置与开发 - 人员设置 里设置。</p>
<p><strong>2)IP白名单</strong><br> 在开发过程中,我们需要访问微信服务器,比如获取token之类。发出请求的IP,需要在白名单上。这个IP,是指互联网IP。假如我们在公司内部开发,那这个IP是公司上网的IP。问题是,这个IP经常变。我不知道有什么好办法,所以基本上是每天改一次白名单。</p>
<p>IP白名单是给我们在本地调试微信开发者工具用的。手机运行不需要。</p>
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/ed4deb29bfe044a6d8d8d824ca49de42.png"></p>
<p><strong>3)开发者微信号</strong><br> 公众号管理后台 - 设置与开发 - web开发者工具,将我们开发人员的微信号加进去。这是开发微信网页要用到的。因为微信开发者工具需要微信号登录。</p>
<p><strong>4)JS接口安全域名</strong><br> 公众号管理后台 - 设置与开发 - 公众号设置 - 功能设置。</p>
<p>也是微信网页开发需要。我们的页面,需要放在这个域名里,微信的js-sdk才可以使用。</p>
<p>填写这个域名的时候,需要下载一个txt文件放到域名下,微信验证域名真伪才能保存。不过填好以后,我们在本地开发时,可以修改host文件,将本机ip映射为该域名。毕竟是前端的一个东西,js-sdk本身需要微信浏览器支持,它也判断不出来请求来自于哪个IP,我们传给它什么它都信。</p>
<p><strong>5)微信开放标签</strong><br> 类似HTML的,微信独有的标签。如</p>
<pre><code class="prism language-html">跳转小程序:<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>wx-open-launch-weapp</span><span class="token punctuation">></span></span>
跳转App:<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>wx-open-launch-app</span><span class="token punctuation">></span></span>
服务号订阅通知:<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>wx-open-subscribe</span><span class="token punctuation">></span></span>
音频播放:<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>wx-open-audio</span><span class="token punctuation">></span></span>
</code></pre>
<h2>三、微信网页开发</h2>
<h3>1、概述</h3>
<p>微信网页真的就是一张张网页,只不过,它引用了微信提供的JS库,可能使用微信独有的,类似html的所谓开放标签。并且这个微信网页似乎在普通浏览器上运行,虽不会报错,但似乎看不到什么效果,只能运行在微信浏览器或微信开发者工具上。</p>
<p>以下是一张微信网页(spring boot下,结合了thymeleaf)</p>
<pre><code class="prism language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xmlns:</span>th</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.thymeleaf.org<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>wechat<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://res.wx.qq.com/open/js/jweixin-1.6.0.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>./libs/jquery.min.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css">
<span class="token selector">.sao</span><span class="token punctuation">{</span>
<span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span><span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span><span class="token property">height</span><span class="token punctuation">:</span>5.5em<span class="token punctuation">;</span><span class="token property">background-color</span><span class="token punctuation">:</span> #ddd<span class="token punctuation">;</span><span class="token property">line-height</span><span class="token punctuation">:</span> 5.5em<span class="token punctuation">;</span>
<span class="token property">cursor</span><span class="token punctuation">:</span>pointer<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.block</span><span class="token punctuation">{</span>
<span class="token property">height</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span>
<span class="token property">border</span><span class="token punctuation">:</span>solid 1px red<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span>
<span class="token comment"><!-- 在手机微信上打开本页面,点这个扫一扫,真的会打开摄像头 --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sao qr_btn<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>扫一扫<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>block<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token comment"><!-- 微信开放标签。测试号不支持,只有认证服务号才可以 --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>wx-open-subscribe</span> <span class="token attr-name"><span class="token namespace">th:</span>template</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${template}<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>subscribe-btn<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/wxtag-template<span class="token punctuation">"</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>style<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
<span class="token operator"><</span>style<span class="token operator">></span>
<span class="token punctuation">.</span>subscribe<span class="token operator">-</span>btn <span class="token punctuation">{</span>
<span class="token literal-property property">color</span><span class="token operator">:</span> #fff<span class="token punctuation">;</span>
background<span class="token operator">-</span>color<span class="token operator">:</span> #07c160<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token operator"><</span><span class="token operator">/</span>style<span class="token operator">></span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/wxtag-template<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
<span class="token operator"><</span>button <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"subscribe-btn"</span><span class="token operator">></span>
模版消息订阅
<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>wx-open-subscribe</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
<span class="token comment">//微信验证</span>
wx<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">debug</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
<span class="token literal-property property">appId</span><span class="token operator">:</span> <span class="token comment">/*[[${wc.appId}]]*/</span><span class="token string">''</span><span class="token punctuation">,</span>
<span class="token literal-property property">timestamp</span><span class="token operator">:</span> <span class="token comment">/*[[${wc.timestamp}]]*/</span><span class="token string">''</span><span class="token punctuation">,</span>
<span class="token literal-property property">nonceStr</span><span class="token operator">:</span> <span class="token comment">/*[[${wc.nonceStr}]]*/</span><span class="token string">''</span><span class="token punctuation">,</span><span class="token comment">//随机串</span>
<span class="token literal-property property">signature</span><span class="token operator">:</span> <span class="token comment">/*[[${wc.signature}]]*/</span><span class="token string">''</span><span class="token punctuation">,</span>
<span class="token literal-property property">jsApiList</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'chooseImage'</span><span class="token punctuation">,</span><span class="token string">'scanQRCode'</span><span class="token punctuation">,</span><span class="token string">'updateAppMessageShareData'</span><span class="token punctuation">,</span><span class="token string">'updateTimelineShareData'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token comment">//需要使用的微信js-sdk函数列表</span>
<span class="token literal-property property">openTagList</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'wx-open-subscribe'</span><span class="token punctuation">]</span><span class="token comment">//开放标签列表</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
wx<span class="token punctuation">.</span><span class="token function">ready</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 微信分享 -- 分享给朋友</span>
wx<span class="token punctuation">.</span><span class="token function">updateAppMessageShareData</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'分享给您的猪朋狗友吧'</span><span class="token punctuation">,</span>
<span class="token literal-property property">desc</span><span class="token operator">:</span> <span class="token string">'独食难肥'</span><span class="token punctuation">,</span>
<span class="token literal-property property">link</span><span class="token operator">:</span> location<span class="token punctuation">.</span>href<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'#'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token literal-property property">imgUrl</span><span class="token operator">:</span> <span class="token string">"http://test.duduchuhai.com/images/share.png"</span><span class="token punctuation">,</span>
<span class="token function-variable function">success</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 微信分享 -- 分享到朋友圈</span>
wx<span class="token punctuation">.</span><span class="token function">updateTimelineShareData</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'分享到猪圈'</span><span class="token punctuation">,</span>
<span class="token literal-property property">link</span><span class="token operator">:</span> location<span class="token punctuation">.</span>href<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'#'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token literal-property property">imgUrl</span><span class="token operator">:</span> <span class="token string">"http://test.duduchuhai.com/images/share.png"</span><span class="token punctuation">,</span>
<span class="token function-variable function">success</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
wx<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// res为微信返回的错误结果</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 微信扫一扫</span>
<span class="token function">$</span><span class="token punctuation">(</span><span class="token string">".qr_btn"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
wx<span class="token punctuation">.</span><span class="token function">scanQRCode</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">needResult</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token comment">// 默认为0,扫描结果由微信处理,1则直接返回扫描结果,</span>
<span class="token literal-property property">scanType</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"qrCode"</span><span class="token punctuation">,</span><span class="token string">"barCode"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// 可以指定扫二维码还是一维码,默认二者都有</span>
<span class="token function-variable function">success</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">var</span> result <span class="token operator">=</span> res<span class="token punctuation">.</span>resultStr<span class="token punctuation">;</span> <span class="token comment">// 当needResult 为 1 时,扫码返回的结果</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">var</span> btn <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'subscribe-btn'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>btn<span class="token punctuation">)</span><span class="token punctuation">;</span>
btn<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'success'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'success'</span><span class="token punctuation">,</span> e<span class="token punctuation">.</span>detail<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
btn<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'error'</span><span class="token punctuation">,</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'fail'</span><span class="token punctuation">,</span> e<span class="token punctuation">.</span>detail<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span>
</code></pre>
<h3>2、验证</h3>
<p>微信网页运行时,首先要经过微信验证,然后才能正常使用微信各种功能。验证流程是,<br> 1)凭appId和appSecret访问微信服务器获得token<br> 2)用token访问微信服务器获得ticket<br> 3)依次用ticket、随机串、时间戳、当前页面地址组合成一个字符串,然后对字符串进行sha散列运算,得到一个摘要<br> 4)用摘要访问微信服务器获得签名<br> 5)将 appId、时间戳、随机串、签名、本页面需要使用的微信函数、微信开放标签注册到微信</p>
<p>上面例子中,</p>
<pre><code class="prism language-js"> wx<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">debug</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
<span class="token literal-property property">appId</span><span class="token operator">:</span> <span class="token comment">/*[[${wc.appId}]]*/</span><span class="token string">''</span><span class="token punctuation">,</span>
<span class="token literal-property property">timestamp</span><span class="token operator">:</span> <span class="token comment">/*[[${wc.timestamp}]]*/</span><span class="token string">''</span><span class="token punctuation">,</span><span class="token comment">//注意是秒,不是毫秒</span>
<span class="token literal-property property">nonceStr</span><span class="token operator">:</span> <span class="token comment">/*[[${wc.nonceStr}]]*/</span><span class="token string">''</span><span class="token punctuation">,</span><span class="token comment">//随机串</span>
<span class="token literal-property property">signature</span><span class="token operator">:</span> <span class="token comment">/*[[${wc.signature}]]*/</span><span class="token string">''</span><span class="token punctuation">,</span><span class="token comment">//关键所在</span>
<span class="token literal-property property">jsApiList</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'chooseImage'</span><span class="token punctuation">,</span><span class="token string">'scanQRCode'</span><span class="token punctuation">,</span><span class="token string">'updateAppMessageShareData'</span><span class="token punctuation">,</span><span class="token string">'updateTimelineShareData'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token comment">//需要使用的微信js-sdk函数列表</span>
<span class="token literal-property property">openTagList</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'wx-open-subscribe'</span><span class="token punctuation">]</span><span class="token comment">//开放标签列表</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>为了得到这个json对象可不容易。appId在微信公众号管理后台可得到,每个公众号都有唯一一个appId;时间戳也容易得到;随机串是自己定的,相对比较容易;最麻烦的是这个签名signature,我调试了差不多1天,总是说非法签名。</p>
<p>获取这个json对象的java代码:</p>
<pre><code class="prism language-java"><span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>alibaba<span class="token punctuation">.</span>fastjson<span class="token punctuation">.</span></span>JSON<span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>alibaba<span class="token punctuation">.</span>fastjson<span class="token punctuation">.</span></span><span class="token class-name">JSONObject</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Autowired</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Service</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">redis<span class="token punctuation">.</span>clients<span class="token punctuation">.</span>jedis<span class="token punctuation">.</span></span><span class="token class-name">Jedis</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">PostConstruct</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span><span class="token class-name">HttpURLConnection</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span>URL<span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span><span class="token class-name">URLConnection</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>security<span class="token punctuation">.</span></span><span class="token class-name">MessageDigest</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>security<span class="token punctuation">.</span></span><span class="token class-name">NoSuchAlgorithmException</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Date</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Random</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span>locks<span class="token punctuation">.</span></span><span class="token class-name">ReentrantLock</span><span class="token punctuation">;</span>
<span class="token annotation punctuation">@Service</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WxServiceImpl</span> <span class="token keyword">implements</span> <span class="token class-name">WxService</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token class-name">WxConfig</span> <span class="token function">getWxConfig</span><span class="token punctuation">(</span><span class="token class-name">String</span> url<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//url是微信网页地址</span>
<span class="token class-name">WxConfig</span> wc <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WxConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//这个是自定义的对象,不必深究</span>
wc<span class="token punctuation">.</span><span class="token function">setAppId</span><span class="token punctuation">(</span>APPID<span class="token punctuation">)</span><span class="token punctuation">;</span>
wc<span class="token punctuation">.</span><span class="token function">setNonceStr</span><span class="token punctuation">(</span><span class="token function">getNonceStr</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//随机串</span>
wc<span class="token punctuation">.</span><span class="token function">setTimestamp</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//时间戳</span>
wc<span class="token punctuation">.</span><span class="token function">setSignature</span><span class="token punctuation">(</span><span class="token function">getSignature</span><span class="token punctuation">(</span>wc<span class="token punctuation">.</span><span class="token function">getNonceStr</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> wc<span class="token punctuation">.</span><span class="token function">getTimestamp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> url<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//签名</span>
<span class="token keyword">return</span> wc<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@PostConstruct</span>
<span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">/*
由于从微信服务器获取token和ticket的函数有调用次数限制(每天<=2000),因此用redis将它们缓存起来
*/</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>jedis <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Jedis</span><span class="token punctuation">(</span>redis的IP<span class="token punctuation">,</span> redis端口号<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> <span class="token function">getSignature</span><span class="token punctuation">(</span><span class="token class-name">String</span> nonceStr<span class="token punctuation">,</span> <span class="token keyword">long</span> timestamp<span class="token punctuation">,</span> <span class="token class-name">String</span> url<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//获取签名</span>
<span class="token class-name">String</span> signature <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> ticket <span class="token operator">=</span> <span class="token function">getTicket</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ticket <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> string1 <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"jsapi_ticket=%s&noncestr=%s&timestamp=%d&url=%s"</span><span class="token punctuation">,</span>
ticket<span class="token punctuation">,</span>
nonceStr<span class="token punctuation">,</span>
timestamp<span class="token punctuation">,</span>
url<span class="token punctuation">)</span><span class="token punctuation">;</span>
signature <span class="token operator">=</span> <span class="token function">getSha1</span><span class="token punctuation">(</span>string1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> signature<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//redis对象</span>
<span class="token keyword">private</span> <span class="token class-name">Jedis</span> jedis<span class="token punctuation">;</span>
<span class="token comment">//除了redis缓存,也用静态变量保存一份。不过,应用程序重启它们就消失了,并且不会自动过期</span>
<span class="token comment">//而从微信获取到的token和ticket有效期是7200秒</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> _ticket <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> _token <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token comment">//锁。为避免并发,使用锁机制,不要大家都去获取token和ticket</span>
<span class="token keyword">private</span> <span class="token class-name">ReentrantLock</span> lockTok <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ReentrantLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">ReentrantLock</span> lockTik <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ReentrantLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> <span class="token function">getTicket</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> ticket <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> key <span class="token operator">=</span> <span class="token string">"ticket"</span><span class="token punctuation">;</span>
ticket <span class="token operator">=</span> <span class="token function">getKey</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_ticket<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ticket <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">//锁定。</span>
lockTik<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
ticket <span class="token operator">=</span> <span class="token function">getKey</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_ticket<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//再努力一把</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ticket <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> token <span class="token operator">=</span> <span class="token function">getToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
ticket <span class="token operator">=</span> <span class="token function">callGet</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi"</span><span class="token punctuation">,</span>
token<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"ticket"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ticket <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>_ticket <span class="token operator">=</span> ticket<span class="token punctuation">;</span>
<span class="token function">setKey</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> ticket<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">//解锁</span>
lockTik<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> ticket<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> <span class="token function">getToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> token <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> key <span class="token operator">=</span> <span class="token string">"token"</span><span class="token punctuation">;</span>
token <span class="token operator">=</span> <span class="token function">getKey</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_token<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
lockTok<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
token <span class="token operator">=</span> <span class="token function">getKey</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_token<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
token <span class="token operator">=</span> <span class="token function">callGet</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"</span><span class="token punctuation">,</span>APPID<span class="token punctuation">,</span><span class="token class-name">AppSecret</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token string">"access_token"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>_token <span class="token operator">=</span> token<span class="token punctuation">;</span>
<span class="token function">setKey</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> token<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
lockTok<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> token<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">final</span> <span class="token keyword">static</span> <span class="token keyword">int</span> EXPIRTED <span class="token operator">=</span> <span class="token number">7200</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> <span class="token function">getKey</span><span class="token punctuation">(</span><span class="token class-name">String</span> key<span class="token punctuation">,</span> <span class="token class-name">String</span> v<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> value <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
value <span class="token operator">=</span> jedis<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
value <span class="token operator">=</span> v<span class="token punctuation">;</span><span class="token comment">//如果无法从redis中读取则将候补变量值返回。但变量值可能有过期的问题</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>err<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>ex<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> value<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">setKey</span><span class="token punctuation">(</span><span class="token class-name">String</span> key<span class="token punctuation">,</span> <span class="token class-name">String</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
jedis<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span>
jedis<span class="token punctuation">.</span><span class="token function">expire</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> EXPIRTED<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>err<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>ex<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">final</span> <span class="token keyword">static</span> <span class="token keyword">int</span> NONCESTR <span class="token operator">=</span> <span class="token number">16</span><span class="token punctuation">;</span><span class="token comment">//随机串的长度为16。这个数值是自己定的</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> <span class="token function">getNonceStr</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 生成随机字符串noncestr</span>
<span class="token class-name">String</span> chars <span class="token operator">=</span> <span class="token string">"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"</span><span class="token punctuation">;</span>
<span class="token class-name">StringBuffer</span> noncestr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StringBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> limit <span class="token operator">=</span> chars<span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> NONCESTR<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Random</span> r <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> j <span class="token operator">=</span> r<span class="token punctuation">.</span><span class="token function">nextInt</span><span class="token punctuation">(</span>limit<span class="token punctuation">)</span><span class="token punctuation">;</span>
noncestr<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>chars<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span>j<span class="token punctuation">,</span> j <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> noncestr<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getSha1</span><span class="token punctuation">(</span><span class="token class-name">String</span> string1<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">MessageDigest</span> sha <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token comment">// 此处的sha代表sha1</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
sha <span class="token operator">=</span> <span class="token class-name">MessageDigest</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token string">"SHA"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">NoSuchAlgorithmException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> md5Bytes <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
md5Bytes <span class="token operator">=</span> sha<span class="token punctuation">.</span><span class="token function">digest</span><span class="token punctuation">(</span>string1<span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token string">"UTF-8"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">UnsupportedEncodingException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token class-name">StringBuffer</span> hexValue <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StringBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> md5Bytes<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> val <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> md5Bytes<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">&</span> <span class="token number">0xff</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>val <span class="token operator"><</span> <span class="token number">16</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
hexValue<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"0"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
hexValue<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">toHexString</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> hexValue<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">callGet</span><span class="token punctuation">(</span><span class="token class-name">String</span> api<span class="token punctuation">,</span> <span class="token class-name">String</span> key<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//get的方式访问微信api</span>
<span class="token class-name">String</span> re <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"正在获取 %s : %s"</span><span class="token punctuation">,</span> key<span class="token punctuation">,</span> api<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token class-name">URL</span> url <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token function">URL</span><span class="token punctuation">(</span>api<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">HttpURLConnection</span> connection <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">HttpURLConnection</span><span class="token punctuation">)</span> url<span class="token punctuation">.</span><span class="token function">openConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
connection<span class="token punctuation">.</span><span class="token function">connect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">BufferedReader</span> br <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BufferedReader</span><span class="token punctuation">(</span>
<span class="token keyword">new</span> <span class="token class-name">InputStreamReader</span><span class="token punctuation">(</span>connection<span class="token punctuation">.</span><span class="token function">getInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"UTF-8"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> line<span class="token punctuation">;</span>
<span class="token class-name">StringBuilder</span> sb <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StringBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>line <span class="token operator">=</span> br<span class="token punctuation">.</span><span class="token function">readLine</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>line<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
br<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
connection<span class="token punctuation">.</span><span class="token function">disconnect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">JSONObject</span> json <span class="token operator">=</span> JSON<span class="token punctuation">.</span><span class="token function">parseObject</span><span class="token punctuation">(</span>sb<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>json<span class="token punctuation">.</span><span class="token function">containsKey</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
re <span class="token operator">=</span> json<span class="token punctuation">.</span><span class="token function">getString</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>re<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
ex<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"访问接口%s失败"</span><span class="token punctuation">,</span> api<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> re<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h3>3、调试</h3>
<p>在微信开发者工具上,输入微信网页地址,运行,得到好多提示。对于微信公众号来说,微信开发者工具就是一个调试工具,一个开了调试模式的浏览器。但刚开始时,总是失败。表现在,我在例子中声明,需要用到下列微信函数:</p>
<pre><code class="prism language-js"> wx<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token literal-property property">debug</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
<span class="token literal-property property">appId</span><span class="token operator">:</span> <span class="token comment">/*[[${wc.appId}]]*/</span><span class="token string">''</span><span class="token punctuation">,</span>
<span class="token literal-property property">timestamp</span><span class="token operator">:</span> <span class="token comment">/*[[${wc.timestamp}]]*/</span><span class="token string">''</span><span class="token punctuation">,</span><span class="token comment">//注意是秒,不是毫秒</span>
<span class="token literal-property property">nonceStr</span><span class="token operator">:</span> <span class="token comment">/*[[${wc.nonceStr}]]*/</span><span class="token string">''</span><span class="token punctuation">,</span><span class="token comment">//随机串</span>
<span class="token literal-property property">signature</span><span class="token operator">:</span> <span class="token comment">/*[[${wc.signature}]]*/</span><span class="token string">''</span><span class="token punctuation">,</span><span class="token comment">//关键所在</span>
<span class="token literal-property property">jsApiList</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'chooseImage'</span><span class="token punctuation">,</span><span class="token string">'scanQRCode'</span><span class="token punctuation">,</span><span class="token string">'updateAppMessageShareData'</span><span class="token punctuation">,</span><span class="token string">'updateTimelineShareData'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token comment">//需要使用的微信js-sdk函数列表</span>
<span class="token literal-property property">openTagList</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'wx-open-subscribe'</span><span class="token punctuation">]</span><span class="token comment">//开放标签列表</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>结果从返回的信息看,我有权访问的函数为0。除此之外,就是到处提示什么“fail, the permission value is offline verifying”之类。</p>
<p>打开微信开发者工具调试模式:微信开发者工具中,顶部菜单“微信开发者工具” - 调试 - “调试微信开发者工具” - network,看这个preverify?_r=…的返回信息,结果是 {errcode: 63002, errmsg: “invalid signature”}!</p>
<p>难道是签名算法有问题?我在微信公众号管理后台上,用它们提供的微信 JS 接口签名校验工具,结果完全一致,因此不存在算法有误的问题。</p>
<h3>4、填坑</h3>
<p>后来发现是URL的问题。生成签名过程中,需要传递当前微信网页的URL参与构造一个字符串,然后散列处理后,传给微信服务器获得签名。问题是,这个URL该怎么写?由于我这个微信页面,名为index.html,一般访问时,习惯在浏览器上这样输入地址:http://www.abc.com,因此我也就把这个地址参与构造签名,结果就是一直提示签名无效。后来将地址写全:http://www.abc.com/index,结果一下子OK了。</p>
<p>但官方开发文档上是怎么写的?<br> <img src="https://i-blog.csdnimg.cn/blog_migrate/19657d65f09ee9a7cab25ca46947dcff.png"><br> 不认真审题害死人。</p>
<h2>四、向公众号订阅者发送模板消息</h2>
<p>这个功能,在我们自己的服务器端调用微信接口来实现。</p>
<pre><code class="prism language-java"><span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>alibaba<span class="token punctuation">.</span>fastjson<span class="token punctuation">.</span></span>JSON<span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>alibaba<span class="token punctuation">.</span>fastjson<span class="token punctuation">.</span></span><span class="token class-name">JSONObject</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Autowired</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Service</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">redis<span class="token punctuation">.</span>clients<span class="token punctuation">.</span>jedis<span class="token punctuation">.</span></span><span class="token class-name">Jedis</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">PostConstruct</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span><span class="token class-name">HttpURLConnection</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span>URL<span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span><span class="token class-name">URLConnection</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>security<span class="token punctuation">.</span></span><span class="token class-name">MessageDigest</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>security<span class="token punctuation">.</span></span><span class="token class-name">NoSuchAlgorithmException</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Date</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Random</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span>locks<span class="token punctuation">.</span></span><span class="token class-name">ReentrantLock</span><span class="token punctuation">;</span>
<span class="token annotation punctuation">@Service</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WxServiceImpl</span> <span class="token keyword">implements</span> <span class="token class-name">WxService</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">sendMess</span><span class="token punctuation">(</span><span class="token class-name">String</span> jsonStr<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> re <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> token <span class="token operator">=</span> <span class="token function">getToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>token <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> api <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s"</span><span class="token punctuation">,</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
re <span class="token operator">=</span> <span class="token function">callPost</span><span class="token punctuation">(</span>api<span class="token punctuation">,</span> jsonStr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> re<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@PostConstruct</span>
<span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>jedis <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Jedis</span><span class="token punctuation">(</span>redis的IP<span class="token punctuation">,</span> redis端口号<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token class-name">Jedis</span> jedis<span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> _token <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">ReentrantLock</span> lockTok <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ReentrantLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> <span class="token function">getToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> token <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> key <span class="token operator">=</span> <span class="token string">"token"</span><span class="token punctuation">;</span>
token <span class="token operator">=</span> <span class="token function">getKey</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_token<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
lockTok<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
token <span class="token operator">=</span> <span class="token function">getKey</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_token<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
token <span class="token operator">=</span> <span class="token function">callGet</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"</span><span class="token punctuation">,</span><span class="token class-name">AppId</span><span class="token punctuation">,</span><span class="token class-name">AppSecret</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"access_token"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>_token <span class="token operator">=</span> token<span class="token punctuation">;</span>
<span class="token function">setKey</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> token<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
lockTok<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> token<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">final</span> <span class="token keyword">static</span> <span class="token keyword">int</span> EXPIRTED <span class="token operator">=</span> <span class="token number">7200</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> <span class="token function">getKey</span><span class="token punctuation">(</span><span class="token class-name">String</span> key<span class="token punctuation">,</span> <span class="token class-name">String</span> v<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> value <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
value <span class="token operator">=</span> jedis<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
value <span class="token operator">=</span> v<span class="token punctuation">;</span><span class="token comment">//如果无法从redis中读取则将候补变量值返回。但变量值可能有过期的问题</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>err<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>ex<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> value<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">setKey</span><span class="token punctuation">(</span><span class="token class-name">String</span> key<span class="token punctuation">,</span> <span class="token class-name">String</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
jedis<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span>
jedis<span class="token punctuation">.</span><span class="token function">expire</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> EXPIRTED<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>err<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>ex<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">callPost</span><span class="token punctuation">(</span><span class="token class-name">String</span> api<span class="token punctuation">,</span> <span class="token class-name">String</span> param<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">PrintWriter</span> out <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token class-name">BufferedReader</span> in <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> result <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token class-name">URL</span> realUrl <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token function">URL</span><span class="token punctuation">(</span>api<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 打开和URL之间的连接</span>
<span class="token class-name">URLConnection</span> conn <span class="token operator">=</span> realUrl<span class="token punctuation">.</span><span class="token function">openConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 设置通用的请求属性</span>
conn<span class="token punctuation">.</span><span class="token function">setRequestProperty</span><span class="token punctuation">(</span><span class="token string">"accept"</span><span class="token punctuation">,</span> <span class="token string">"*/*"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
conn<span class="token punctuation">.</span><span class="token function">setRequestProperty</span><span class="token punctuation">(</span><span class="token string">"Content-Type"</span><span class="token punctuation">,</span> <span class="token string">"application/json"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
conn<span class="token punctuation">.</span><span class="token function">setRequestProperty</span><span class="token punctuation">(</span><span class="token string">"connection"</span><span class="token punctuation">,</span> <span class="token string">"Keep-Alive"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
conn<span class="token punctuation">.</span><span class="token function">setRequestProperty</span><span class="token punctuation">(</span><span class="token string">"user-agent"</span><span class="token punctuation">,</span>
<span class="token string">"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 发送POST请求必须设置如下两行</span>
conn<span class="token punctuation">.</span><span class="token function">setDoOutput</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
conn<span class="token punctuation">.</span><span class="token function">setDoInput</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 获取URLConnection对象对应的输出流</span>
out <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PrintWriter</span><span class="token punctuation">(</span>conn<span class="token punctuation">.</span><span class="token function">getOutputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 发送请求参数</span>
out<span class="token punctuation">.</span><span class="token function">print</span><span class="token punctuation">(</span>param<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// flush输出流的缓冲</span>
out<span class="token punctuation">.</span><span class="token function">flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 定义BufferedReader输入流来读取URL的响应</span>
in <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BufferedReader</span><span class="token punctuation">(</span>
<span class="token keyword">new</span> <span class="token class-name">InputStreamReader</span><span class="token punctuation">(</span>conn<span class="token punctuation">.</span><span class="token function">getInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> line<span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>line <span class="token operator">=</span> in<span class="token punctuation">.</span><span class="token function">readLine</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
result <span class="token operator">+=</span> line<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"发送 POST 请求出现异常!"</span> <span class="token operator">+</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span><span class="token comment">//使用finally块来关闭输出流、输入流</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>out <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
out<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>in <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
in<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
ex<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> result<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">callGet</span><span class="token punctuation">(</span><span class="token class-name">String</span> api<span class="token punctuation">,</span> <span class="token class-name">String</span> key<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> re <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"正在获取 %s : %s"</span><span class="token punctuation">,</span> key<span class="token punctuation">,</span> api<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token class-name">URL</span> url <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token function">URL</span><span class="token punctuation">(</span>api<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">HttpURLConnection</span> connection <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">HttpURLConnection</span><span class="token punctuation">)</span> url<span class="token punctuation">.</span><span class="token function">openConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
connection<span class="token punctuation">.</span><span class="token function">connect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">BufferedReader</span> br <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BufferedReader</span><span class="token punctuation">(</span>
<span class="token keyword">new</span> <span class="token class-name">InputStreamReader</span><span class="token punctuation">(</span>connection<span class="token punctuation">.</span><span class="token function">getInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"UTF-8"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> line<span class="token punctuation">;</span>
<span class="token class-name">StringBuilder</span> sb <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StringBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>line <span class="token operator">=</span> br<span class="token punctuation">.</span><span class="token function">readLine</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>line<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
br<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
connection<span class="token punctuation">.</span><span class="token function">disconnect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">JSONObject</span> json <span class="token operator">=</span> JSON<span class="token punctuation">.</span><span class="token function">parseObject</span><span class="token punctuation">(</span>sb<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>json<span class="token punctuation">.</span><span class="token function">containsKey</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
re <span class="token operator">=</span> json<span class="token punctuation">.</span><span class="token function">getString</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>re<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
ex<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"访问接口%s失败"</span><span class="token punctuation">,</span> api<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> re<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>测试</p>
<pre><code class="prism language-java"> <span class="token annotation punctuation">@Autowired</span>
<span class="token class-name">WxService</span> service<span class="token punctuation">;</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testSendMess</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token class-name">String</span> json <span class="token operator">=</span> <span class="token string">"{\n"</span> <span class="token operator">+</span>
<span class="token string">" \"touser\":OPENID,\n"</span> <span class="token operator">+</span>
<span class="token string">" \"template_id\":模板ID,\n"</span> <span class="token operator">+</span>
<span class="token string">" \"data\":{\n"</span> <span class="token operator">+</span>
<span class="token string">" \"name01\": {\n"</span> <span class="token operator">+</span>
<span class="token string">" \"value\":\"韩擒虎女士\"\n"</span> <span class="token operator">+</span>
<span class="token string">" },\n"</span> <span class="token operator">+</span>
<span class="token string">" \"thing01\":{\n"</span> <span class="token operator">+</span>
<span class="token string">" \"value\":\"您的大头佛到货了\"\n"</span> <span class="token operator">+</span>
<span class="token string">" },\n"</span> <span class="token operator">+</span>
<span class="token string">" \"date01\": {\n"</span> <span class="token operator">+</span>
<span class="token string">" \"value\":\"2022-04-15\"\n"</span> <span class="token operator">+</span>
<span class="token string">" }\n"</span> <span class="token operator">+</span>
<span class="token string">" }\n"</span> <span class="token operator">+</span>
<span class="token string">"}"</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> re <span class="token operator">=</span> service<span class="token punctuation">.</span><span class="token function">sendMess</span><span class="token punctuation">(</span>json<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>re<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>这个功能只有通过认证的服务号才能权限使用。但开发时候,可以通过申请一个测试账号来试验。需要在公众号管理后台创建一个模板。模板参考如下:<br> <img src="https://i-blog.csdnimg.cn/blog_migrate/a37ee2568637aeac1d1c7975fc5a98c8.png"><br> 用户的OPENID也容易得到:<br> <img src="https://i-blog.csdnimg.cn/blog_migrate/37b3e4263df26a27e5afeec2db99e989.png"><br> 测试结果<br> <img src="https://i-blog.csdnimg.cn/blog_migrate/e41e2772fd4ad9b003f2fa0ac4b82f47.png"></p>
<h2>五、小结</h2>
<p>整个微信体系,东西很多很杂,各种自定义的术语,对于初接触者,晕头转向。然后提供的开发文档,洋洋洒洒,密密麻麻,只是一堆手册,等待你自己去查阅。许多东西,你根本不知道它是什么鬼,用来干啥的,文档只是泛泛地说应该怎么怎么弄,却又极少举例子。这就给初学者带来很大的困扰,人为制造了许多的障碍。</p>
<p>而且这种二次开发并没有什么意义。</p>
<p>微信公众号及小程序开发入门(二)</p><br><br>
来源:https://www.cnblogs.com/leftfist/p/19643494
頁:
[1]