# 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会分配一个专属域名/端口,办公软件就已经在公网上了,在外地的办公人员可以在任何地方愉快的访问办公软件了~~

**问题二:能干什么?**
1. 上文举例的办公软件
2. 放在家里的树莓派,服务器等,需要远程ssh管理,这样打通服务器的22端口即可远程通过ssh操作服务器了.
3. 微信/支付宝等本地开发.现在微信/支付宝等应用,需要服务器接收微信/支付宝发送的回调信息,然而在本地开发程序的话,还得实时上传到服务器,以便支持微信/支付宝的回调信息,如果使用了natapp内网穿透软件,将回调地址设置成natapp提供的地址,回调数据立即传递回本地,,这样很方便的在本地就可以实时调试程序,无须再不断上传服务器等繁琐且无意义的步骤.
4. 一些企业内部数据库,由于安全等原因,不愿意放到云服务器上,可以将数据库放到办公室本地,然后通过natapp的tcp隧道映射,这样既保证安全,又保证公网可以正常访问.
5. 一些开发板做的监控等信息,每台设备运行一条隧道,可以方便的管理监控各个设备的运行情况.
6. 一些本地运行的游戏,想和好基友一起联网玩,一条命令运行natapp即可实现联网游戏.
7. 群辉上运行natapp之后,随时随地在任何地方可以访问到群辉上应用
**问题三:如何使用?**
1. 注册登录natapp网站,先下载natapp,放到本地
2. 在网站上创建自己的免费隧道,并将端口映射到本地的80端口上(微信平台的要求)
3. 记录下自己的 **authtoken** 
4. 在本地创建一个bat脚本,内容是natapp的启动命令`natapp -authtoken=ad6fa1b675****`
5. 查看映射的域名,值得注意的是这个域名会隔一段时间变化一次
### 本地开发:
#### 步骤一:创建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}
```
创建配置类

创建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
3. 设置本机IP白名单( 在IP白名单内的IP来源,[获取access_token](https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN)接口才可调用成功)
4. 启动本地SpringBoot项目,并且natapp保持开启
5. 在左侧<开发>菜单项下的<基本配置>中设置好内网穿透的URL(能够提供checkLink校验的)、Token(本地项目设置的)等;点击提交,提示通过就可继续开发。如果没有校验通过,看看自己的natapp的域名是否发生变化;还有就是后台接口是否正确。
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测试,后台是否能够支持;根据返回值判断

当本地服务写好启动之后,还需要在微信平台启动该服务配置
### 本地测试:
