1.开通开发者帐号
注意:开通微信公众号必须是“个体户”或“企业性质”。
- 通过个人微信号扫码登录并开通微信服务号
- 开通成功后,此时的公众号是【未认证状态】
- 未认证与认证的公众号的主要区别
在【开发—接口权限】菜单中,可查看到使用各接口的权限。
我们要进行二次开发,不申请开通“开发者帐号”,你的公众号就只是个摆设。 - 认证服务号并开通开发者帐号
服务号的认证:无论是“个体户”还是“企业”,最好是首先将公司的对公帐户开通好。
因为如果你的系统还要申请微信支付功能的话,开通了对公帐户,后面的操作会简单很多。
- 服务号认证成功后,我们会看到接口权限基本上全部都可使用了
2.程序与公众号联合调试
2.1 准备联调的服务器
注意:微信公众号与服务器交互时,只能访问你服务器的 80端口
云服务器
云服务器联调,则在调试中,可能要多打些log日志来调试
2.2 配置公众平台
2.2.1 菜单: 开发-- 基本配置
```
IP白名单:公众号允许指定外网访问的IP地址(官方要求必须配置)
注意:如果你用的是云服务器,直接将服务器的公网IP配置此处即可。
2.2.2 服务器配置(重点)
URL: 公众号默认将访问的服务器的地址。
注意:这里是公众号与后台连接的总入口
Token:类似票据,可自行设置并系统自行保留
EncodingAESKey:随机生成即可,这个值应该是给公众号来用的,系统联调时,不会用到该值。
在配置上面的URL时,必须先确保你的服务器已成功启动
如果你服务器连接的URL配置错误,【提交】按钮就无法成功点击,公众平台会报错。
2.2.3 服务器后台核心代码
注:这里以springboot工程为例
因为公众号访问我们服务器,都走的统一的一个接口,就是我们上面配置的URL,所以在项目中,我们可以创建一个Servlet来专门接收和处理公众号的请求。
具体代码步骤如下
- 在启动类上添加注解
@SpringBootApplication
@ServletComponentScan
public class WXApplication {
public static void main(String[] args) {
SpringApplication.run(WXApplication.class, args);
}
}
- 创建一个servlet并编写连接所需的核心代码:WechatCallbackApi.java
@WebServlet("/wechat")
public class WechatCallbackApi extends HttpServlet {
@Autowired
private WeixinGZHService weixinGZHService;
@Override//不添加此方法,直接注入service会报空指针
public void init(ServletConfig config) {
try {
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
doGet(req, resp);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
try {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
//进行签名校验
weixinGZHService.validateWeixinServer(request, response);
//处理菜单响应操作
/*
<xml>
<ToUserName><![CDATA[gh_409cf2d2d396]]></ToUserName>
<FromUserName><![CDATA[o64up1E1tBRXaLhRne9Dm9rrcp5g]]></FromUserName>
<CreateTime>1558324778</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[CLICK]]></Event>
<EventKey><![CDATA[V1001_GET_ORDER]]></EventKey>
</xml>
*/
String message = IOUtils.toString(request.getInputStream(), "utf-8");
//先转成map对象
Map<String, String> xmlToMap = WeChatXMLUtils.xmlToMap(message);
//在调用模板消息时,有个非常坑的地方,就是微信公众号服务器每向微信用户发送消息后,必须要有回应,无回应微信那边则会报异常
if (xmlToMap == null || StringUtils.isBlank(xmlToMap.get("EventKey"))) {
return;
}
WeixinResult weixinResult = WeChatXMLUtils.xmlToBean(message, WeixinResult.class);
//发送模板消息时,也会向公众号返回一条消息,但此消息的数据类型与 click事件的返回类型不同。需要判断eventKey的值
if (weixinResult != null && StringUtils.isNotBlank(weixinResult.getEventKey())) {
switch (weixinResult.getEventKey()) {
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 实体类WeixinResult .java
/*
<xml>
<ToUserName><![CDATA[gh_409cf2d2d396]]></ToUserName>
<FromUserName><![CDATA[o64up1E1tBRXaLhRne9Dm9rrcp5g]]></FromUserName>
<CreateTime>1558324778</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[CLICK]]></Event>
<EventKey><![CDATA[V1001_GET_ORDER]]></EventKey>
</xml>
*/
//设置根据字段还是方法生成
//设置生成的xml的根节点的名称
@XmlRootElement(name = "xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class WeixinResult implements Serializable {
private String ToUserName;
private String FromUserName;
private String MsgType;
private long CreateTime;
private String Event;
private String EventKey;
private String Content;
// view类型时,需要这个字段
private String MenuId;
}
注意: 上面实体类的属性名,其实就是根据调用公众号接口返回的统一XML命名。实体类属性名,最好是与XML数据中返回的字段名保持一致,这样后面在接收数据并进行转换时就非常方便
- 签名校验方法weixinGZHService.validateWeixinServer
weixinGZHService.java类中核心代码
下面方法上会用到一个参数 TOKEN,这个值就是我们在公众号中配置的token值
/**
* 验证当前微信服务器是否正常
*
* @param request
* @param response
* @throws IOException
*/
public void validateWeixinServer(HttpServletRequest request, HttpServletResponse response) throws IOException {
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
ArrayList<String> array = new ArrayList<String>();
array.add(signature);
array.add(timestamp);
array.add(nonce);
//排序
String sortString = sort(TOKEN, timestamp, nonce);
//加密
String mytoken = SHA1.SHA1(sortString);
//校验签名
if (mytoken != null && mytoken != "" && mytoken.equals(signature)) {
response.getWriter().println(echostr); //如果检验成功输出echostr,微信服务器接收到此输出,才会确认检验完成。
}
}
/**
* 排序方法
*
* @param token
* @param timestamp
* @param nonce
* @return
*/
private String sort(String token, String timestamp, String nonce) {
String[] strArray = {token, timestamp, nonce};
Arrays.sort(strArray);
StringBuilder sbuilder = new StringBuilder();
for (String str : strArray) {
sbuilder.append(str);
}
return sbuilder.toString();
}
- 实体类SHA1.java
public class SHA1 {
public static String SHA1(String decript) {
try {
MessageDigest digest = MessageDigest
.getInstance("SHA-1");
digest.update(decript.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
}
2.2.4 联调检测
在上面的后台代码都配置好后,此时,再回到公众平台【开发–基本配置—服务器配置】
当修改配置成功后,点修改配置,弹出【提交成功提示】则表示配置成功。
到此,公众平台与我们服务器的整体联调测试就全部完成。
后面,会再教如何进行自定义菜单开发。