# wechat-learn **Repository Path**: luotianhao25182/wechat-learn ## Basic Information - **Project Name**: wechat-learn - **Description**: 微信公众平台之"你问我答" - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2020-03-13 - **Last Updated**: 2025-01-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 微信开发 微信的开发主要是两个平台:微信公众平台和微信开放平台;基于这两个不同的平台可以开发不同的需求 - **微信公众平台:**开发服务号、订阅号、小程序、企业微信 - **微信开放平台:**开发移动应用、网站应用、公众账号、第三方平台 两个服务平台的区别: 1. 微信公众平台面向的是普通的用户,比如自媒体和媒体,企业官方微信公众账号运营人员使用,当然你所在的团队或者公司有实力去开发一些内容,也可以调用公众平台里面的接口,比如自定义菜单,自动回复,查询功能。目前大多数微信在认证之后,都在做这个事情。 2. 开放平台面向的是开发者和第三方独立软件开发商。开发者或软件开发商通过微信开放提供的平台和接口,可以开发适合企业的电子商务网站,比如微信登录,微信支付等。 ## 公众号开发实战 ### 准备工具 1. 内网穿透工具:[NATAPP]( https://natapp.cn/tunnel/lists ) 2. 微信公众订阅号一个:[订阅号]( https://mp.weixin.qq.com/cgi-bin/home?t=home/index&token=251194586&lang=zh_CN ) ### 内网穿透 **问题一:什么是内网穿透?** 内网穿透简单来说就是将内网外网通过natapp隧道打通,让内网的数据让外网可以获取。比如常用的办公室软件等,一般在办公室或家里,通过拨号上网,这样办公软件只有在本地的局域网之内才能访问,那么问题来了,如果是手机上,或者公司外地的办公人员,如何访问到办公软件呢?这就需要natapp内网穿透工具了。运行natapp隧道之后,natapp会分配一个专属域名/端口,办公软件就已经在公网上了,在外地的办公人员可以在任何地方愉快的访问办公软件了~~ ![](https://img2020.cnblogs.com/blog/1911393/202003/1911393-20200313095751371-699953856.png) **问题二:能干什么?** 1. 上文举例的办公软件 2. 放在家里的树莓派,服务器等,需要远程ssh管理,这样打通服务器的22端口即可远程通过ssh操作服务器了. 3. 微信/支付宝等本地开发.现在微信/支付宝等应用,需要服务器接收微信/支付宝发送的回调信息,然而在本地开发程序的话,还得实时上传到服务器,以便支持微信/支付宝的回调信息,如果使用了natapp内网穿透软件,将回调地址设置成natapp提供的地址,回调数据立即传递回本地,,这样很方便的在本地就可以实时调试程序,无须再不断上传服务器等繁琐且无意义的步骤. 4. 一些企业内部数据库,由于安全等原因,不愿意放到云服务器上,可以将数据库放到办公室本地,然后通过natapp的tcp隧道映射,这样既保证安全,又保证公网可以正常访问. 5. 一些开发板做的监控等信息,每台设备运行一条隧道,可以方便的管理监控各个设备的运行情况. 6. 一些本地运行的游戏,想和好基友一起联网玩,一条命令运行natapp即可实现联网游戏. 7. 群辉上运行natapp之后,随时随地在任何地方可以访问到群辉上应用 **问题三:如何使用?** 1. 注册登录natapp网站,先下载natapp,放到本地 2. 在网站上创建自己的免费隧道,并将端口映射到本地的80端口上(微信平台的要求)![](https://img2020.cnblogs.com/blog/1911393/202003/1911393-20200313095410639-918945788.png) 3. 记录下自己的 **authtoken** ![](https://img2020.cnblogs.com/blog/1911393/202003/1911393-20200313095524477-1247618936.png) 4. 在本地创建一个bat脚本,内容是natapp的启动命令`natapp -authtoken=ad6fa1b675****` 5. 查看映射的域名,值得注意的是这个域名会隔一段时间变化一次![](https://img2020.cnblogs.com/blog/1911393/202003/1911393-20200313095717172-1016085686.png) ### 本地开发: #### 步骤一:创建SpringBoot项目 该项目依赖于SpringBoot的2.0.6.RELEASE版本 ```xml org.springframework.boot spring-boot-starter-parent 2.0.6.RELEASE ``` 导入依赖,其中注释了的一个依赖是关于Spring配置文件的,可加可不加 ```xml junit junit 4.11 test org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.apache.commons commons-lang3 3.4 org.apache.httpcomponents httpclient org.codehaus.xfire xfire-core 1.2.6 com.thoughtworks.xstream xstream 1.4.10 dom4j dom4j 1.6.1 org.bouncycastle bcpkix-jdk15on 1.60 com.alibaba fastjson 1.2.46 ``` 配置application.yml文件(其中的token是自己定义的;appid和sceret需要在公众号平台查看;tokenUrl是公众号平台提供的获取access-token的接口),暂时先把选项添加上 ```yml server: port: 80 spring: application: name: hello data: wechat: token: admin appid: wx9f1c0f01***** sceret: 53275ff4638a0e32d4436bd9e***** tokenUrl: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${data.wechat.appid}&secret=${data.wechat.sceret} ``` 创建配置类 ![](https://img2020.cnblogs.com/blog/1911393/202003/1911393-20200313100719121-1225474060.png) 创建controller类,来和公众号平台获取连接,值得注意的是,本地开发提供一个Get请求接口 ```java @RestController @RequestMapping("/test") public class TestController { @Autowired private WeChatUtils weChatUtils; @GetMapping("/check") public String checkLink(@RequestParam String signature, @RequestParam String timestamp, @RequestParam String nonce, @RequestParam String echostr ){ return weChatUtils.checkLink(signature, timestamp, nonce, echostr); } } ``` WeChatUtils工具类中提供一个checkLink方法 ```java public String checkLink(String signature,String timestamp,String nonce,String echostr){ //1)将token、timestamp、nonce三个参数进行字典序排序 String[] arr = {weChatConfig.getToken(),timestamp,nonce}; Arrays.sort(arr); //2)将三个参数字符串拼接成一个字符串进行sha1加密 StringBuilder stringBuilder = new StringBuilder(); for (String s:arr) { stringBuilder.append(s); } String sha1 = getSha1(stringBuilder.toString()); //3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信 if (signature.equals(sha1)) { return echostr; }else { return ""; } } ``` #### 步骤二:订阅号配置 1. 登录公众号开发平台,[点击跳转至链接]( https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=112023637&lang=zh_CN ) 2. 获取appid及secret;并将这两个数据填入application.yml![](https://img2020.cnblogs.com/blog/1911393/202003/1911393-20200313101352678-1433021129.png) 3. 设置本机IP白名单( 在IP白名单内的IP来源,[获取access_token](https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN)接口才可调用成功)![](https://img2020.cnblogs.com/blog/1911393/202003/1911393-20200312132133095-1119634369.png) 4. 启动本地SpringBoot项目,并且natapp保持开启 5. 在左侧<开发>菜单项下的<基本配置>中设置好内网穿透的URL(能够提供checkLink校验的)、Token(本地项目设置的)等;点击提交,提示通过就可继续开发。如果没有校验通过,看看自己的natapp的域名是否发生变化;还有就是后台接口是否正确。![](https://img2020.cnblogs.com/blog/1911393/202003/1911393-20200312132008227-1772964691.png) 6. 至此算是本地服务器与微信服务器建立了连接 #### 步骤三:自定义消息回复 在本地服务中校验连接的controller中,添加一个支持Post请求的接口,并且该接口的url和校验的一致;其功能就是能够解析微信服务器传过来的一个xml数据,并根据msgType类型进行响应 ```java @PostMapping(value = "/check") public String messageMonitor(HttpServletRequest request) { return service.message(request); } ``` 开发MessageService,下面给出代码片段 ```java @Override public String message(HttpServletRequest request){ Map map = null; try { map = utils.xmlToMap(request); HashMap hashMap = new HashMap<>(); hashMap.put(TO_USER_NAME,map.get(FROM_USER_NAME)); hashMap.put(FROM_USER_NAME,map.get(TO_USER_NAME)); hashMap.put(CREATETIME,String.valueOf(System.currentTimeMillis())); String msgType = map.get(MSGTYPE); String message = "success"; String content = ""; String mediaId = ""; switch (msgType) { case "text" : content = map.get(CONTENT); if (content.contains("笑话")) { hashMap.put(MSGTYPE,"voice"); hashMap.put("MediaId",luoSmartReply.voiceReply(content)); }else if (content.contains("图片")) { hashMap.put(MSGTYPE,"image"); hashMap.put("MediaId",luoSmartReply.pictureReply(content)); }else { hashMap.put(MSGTYPE,msgType); hashMap.put(CONTENT,luoSmartReply.textReply(content)); } try { LOGGER.info("{} success",content); message = utils.mapToXml(hashMap); break; } catch (IOException | DocumentException e) { e.printStackTrace(); } case "image": hashMap.put(MSGTYPE,msgType); mediaId = map.get("MediaId"); hashMap.put("MediaId",mediaId); try { message = utils.mapToXml(hashMap); break; } catch (IOException | DocumentException e) { e.printStackTrace(); } case "voice": hashMap.put(MSGTYPE,msgType); mediaId = map.get("MediaId"); hashMap.put("MediaId",mediaId); try { message = utils.mapToXml(hashMap); break; } catch (IOException | DocumentException e) { e.printStackTrace(); } default: break; } return message; } catch (IOException | DocumentException e) { e.printStackTrace(); } return "success"; } ``` 除此之外还需要提供能够获取access_token的接口,该接口需要向微信提供的接口发送Get请求,下面是一个get请求方法。当我们能够获取的access_token的时候,就可以进行下一步操作了。 ```java public static Object get(String uri) { HttpGet httpGet = new HttpGet(uri); CloseableHttpClient httpClient = HttpClientBuilder.create().build(); try { CloseableHttpResponse response = httpClient.execute(httpGet); HttpEntity entity = response.getEntity(); String res = EntityUtils.toString(entity,DEFAULT_ENCODING); return JSONObject.parse(res); } catch (IOException e) { LOGGER.error(e.getMessage()); return null; } finally { try { httpClient.close(); } catch (IOException e) { LOGGER.error(e.getMessage()); } } } ``` 在微信的[debug平台]( https://mp.weixin.qq.com/debug ),进行本地服务的api测试,后台是否能够支持;根据返回值判断 ![](https://img2020.cnblogs.com/blog/1911393/202003/1911393-20200313103536701-2027561597.png) 当本地服务写好启动之后,还需要在微信平台启动该服务配置![](https://img2020.cnblogs.com/blog/1911393/202003/1911393-20200313101710167-995690892.png) ### 本地测试: ![](https://img2020.cnblogs.com/blog/1911393/202003/1911393-20200313133244103-612541109.png)