微信公众号开发——1、搭建服务器+与用户交流

第一部分:前导篇

一、注册公众号开发者

1、新手开发阶段建议申请测试账号进行公众号的开发,注册账号可更直观的了解公众号的结构功能等。

2、登录微信公众平台,使用邮箱进行注册,每一个邮箱只能注册一种项目(小程序、订阅号、服务号、企业微信)。

3、服务号相比公众号,拥有更全的功能,功能差异戳这里。

4、公众号许多功能需要用户认证后才能使用,因此不建议注册无法认证的个人账号。

5、 建议成为公众号开发者。公众号:微信公众平台->开发者工具->web开发者工具->绑定开发者微信

二、公众号开发关键文档和开发工具

1、微信公众平台:公众号的注册、开发管理等。

2、微信公众平台技术文档:提供公众号接口等。

3、微信硬件平台:硬件接入开发技术说明等。

4、微信web开发者工具:用于公众号嵌入网页的调试。

5、ngrok,nat123等内网穿透工具:将本地端口映射到公网,使用域名访问本地服务器。


第二部分:开发阶段

一、开发模式

1、编辑模式(默认):在微信公众平台进行自定义菜单、添加素材等。

2、开发者模式:微信公众平台->基本配置->服务器配置->启用,在该模式下,所有菜单、素材、更多插件功能等都需要调用微信接口生成。本文主要介绍开发者模式,并使用公众号测试账号进行开发,开发语言:java,服务器:tomcat,数据库:mySql.


二、服务器配置

1、搭建本地服务器

创建javaWeb项目,新建TestServlet用于服务器配置。配置服务器时参数必须是echostr,并将其输出

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String echostr = req.getParameter("echostr");
		PrintWriter writer = resp.getWriter();
		if (null != echostr && !"".equals(echostr)) {
			writer.write(echostr);
		}
		writer.flush();
		writer.close();
	}
2、内网映射

下载并启动ngrok工具,输入命令ngrok http 80(公众号仅支持80和443端口),https协议也是相同命令(tomcat下重定向到443端口)。弹出如下窗口

微信公众号开发——1、搭建服务器+与用户交流_第1张图片

3、尝试用ngrok提供的域名访问Test项目

微信公众号开发——1、搭建服务器+与用户交流_第2张图片

4、进入公众号平台测试号管理界面,为测试账号进行服务器配置(接口配置信息),

URL:填写URL为以上测试时所用的url,不要加入额外参数,提交配置时,微信服务器会携带Token作为echostr等参数转发给testServlet,由testServlet返回该值。

Token:随便填写。

微信公众号开发——1、搭建服务器+与用户交流_第3张图片

经过以上操作,服务器配置就已经完成了,关注公众号后,用户的操作将会被微信服务器转发给testServlet,我们可以通过testServlet响应用户的操作。


三、为用户提供可视化菜单,学习过程请参考微信公众平台技术文档

1、接口在线调试工具,

微信公众平台提供,接口在线调试工具,方便开发者调用微信接口创建菜单、接入硬件等操作。请打开“自定义菜单”进行学习。

2、获取access_token

在接口在线调试工具中选择“基础支持”,输入测试号所提供的appid,和secret,用于生成access_token,该值有效期为2小时。(Get请求)

3、自定义菜单

在接口在线调试工具中选择“自定义菜单,输入access_token。填入body,用于创建菜单,Body参数作为Post请求的参数。示例创建菜单body代码如下:

{
    "button": [
		{
            "type": "view", 
            "name": "百度一下", 
            "url": "http://www.baidu.com"
        }, 
        {
            "name": "我的助手", 
            "sub_button": [
			    {
					"type": "click", 
					"name": "赞我吧", 
                    "key": "zanwoba"
				}, 
                {
					"type": "scancode_push", 
					"name": "扫一扫", 
                    "key": "rselfmenu_0_1"
				}
            ]
        }
    ]
}
这便完成了创建菜单的操作
微信公众号开发——1、搭建服务器+与用户交流_第4张图片

4、扫码关注测试公众号,效果如下

微信公众号开发——1、搭建服务器+与用户交流_第5张图片


四、处理用户事件

当用户发送消息或点击菜单时,微信服务器会首先捕获取这些事件,并将这些事件数据转发到我们在接口配置信息中填入的testServlet中,我们可以获取这些事件,并进行响应的处理。本文模拟用户发送文本消息,并返回一段逆序的文本。实现效果如下:

微信公众号开发——1、搭建服务器+与用户交流_第6张图片

结接收用户事件并响应大致流程如下:

1、用户发起事件、点击菜单或发送文本

2、微信服务器获取到该事件,检查是否需要将消息转发到第三方服务器(我们的TestServlet)。

3、将消息转发到我们的服务器,通过接口配置url(testServlet)获取微信服务器转发的消息

4、解析数据。

5、根据需要返回的数据格式,生成正确格式的数据。并将其写入输出流。

6、微信服务器获取到我们的服务器的数据,将其返回给用户。

7、用户接收到经处理过的数据。

以下代码是获取接口配置信息、获取用户事件、返回用户事件的代码,之后讲解具体实现逻辑

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
		PrintWriter writer = null;
		resp.setCharacterEncoding("UTF-8");
		resp.setContentType("text/html;charset=UTF-8");
		resp.setHeader("Content-Type", "text/html;charset=UTF-8");
		String echostr = req.getParameter("echostr");
		try {
			writer = resp.getWriter();
			if (null != echostr && !"".equals(echostr)) {
				writer.write(echostr);//如果当前是接口配置,则直接输入返回值
				writer.flush();
				writer.close();
				return;
			}
			//接收微信服务器转发的请求
			String data = acceptRequest(req);
			System.out.println("公众号用户请求消息为: " + data);
			Map map = XmlHelper.parse(data);
			
			//给微信服务器返回消息,并由微信服务器将消息转发给用户。
			callback(writer, data);
		} catch (Exception e) {
			if (null != writer) {
				writer.write("success");
			}
		}finally{
			if (null != writer) {
				writer.flush();
				writer.close();
			}
		}

	}

1、在TestServlet中获取用户发送的数据

	private String acceptRequest(HttpServletRequest req) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(req.getInputStream()));
		String sb = "";
		StringBuffer stringBuffer = new StringBuffer();
		while((sb = br.readLine()) != null){
			System.out.println(sb);
			stringBuffer.append(sb);
		}
		br.close();
		return stringBuffer.toString();
	}
在testServlet的doPost()方法中添加此方法,并在控制台输出该数据,数据如下



1504950429


6463712875121877522

2、解析用户数据格式,并保存起来。

由于该数据并未标准和xml格式,本文对该文本格式文本进行了简单的解析,并以key-value形式保存在map中。本段代码并不能很好的解析所有微信事件数据格式。

package com.uyeh.wx.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class XmlHelper {

	private static String[] attributs_array = new String[] { "ToUserName", "FromUserName", "CreateTime", "MsgType",
			"MsgId", "Content", "PicUrl", "LocationX", "LocationY", "Scale", "Label", "Title", "Description", "Url",
			"MediaId", "Format", "Recognition", "Event", "EventKey", "Ticket","ScanCodeInfo","ScanResult","ScanType",
			"DeviceType", "DeviceID","SessionID","OpenID"};
	private static List list = new ArrayList<>();

	private static String cdata = "") && text.contains("");
	}

	private static String get(String text, String key) {
		if (containKey(text, key)) {
			String value = text.substring(text.indexOf("<" + key + ">") + ("<" + key + ">").length(),
					text.lastIndexOf(""));
			if (null != value && value.contains(cdata) && !key.equals("ScanCodeInfo")) {
				value = value.substring(value.indexOf(cdata) + (cdata).length(), value.lastIndexOf("]]>"));
				list.add(key);
			}
			return value;
		}
		return null;
	}

	/**
	 * 生成微信端需要的数据格式
	 * @param map
	 * @return
	 */
	public static String generate(Map map) {
		StringBuffer sb = new StringBuffer();
		if (null != map && map.size() > 0) {
			sb.append("");
			for (String key : map.keySet()) {
				if (key.equals("ScanResult") || key.equals("ScanType")) {
					continue;
				}
				sb.append("<" + key + ">");
				if (list.contains(key)) {
					sb.append(cdata);
				}
				sb.append(map.get(key));
				if (list.contains(key)) {
					sb.append("]]>");
				}
				sb.append("");
			}
			sb.append("");
		}
		return sb.toString();
	}

	/**
	 * 解析公共号发过来的数据
	 * 
	 * @param text
	 * @return
	 */
	public static Map parse(String text) {
		Map map = new HashMap<>();
		String[] array = attributs_array;
		for (String key : array) {
			if (containKey(text, key)) {
				String value = get(text, key);
				map.put(key, value);
			}
		}
		return map;
	}
}
3、给用户返回数据

在本例中,只需要给用户的数据进行逆序转换,只需要将FromUserName和ToUserName进行交换,并反转text文本即可。

	private void callback(Writer writer, String data) throws Exception {
		Map map = XmlHelper.parse(data);
		if (map.containsKey("ToUserName") && map.containsKey("FromUserName")) {
			String to = map.get("ToUserName");
			String from = map.get("FromUserName");
			map.put("FromUserName", to);
			map.put("ToUserName", from);
		}
		switch (map.get("MsgType")) {
		case "text":
			//1、如果是文字,刚逆序返回
			responseText(writer, map);
			break;
		case "image":
			//2、如果是图片,则返回图片
			responseImage(writer,map);
			break;
		case "event":
			responseEvent(writer, map);
			switch (map.get("Event")) {
			case "VIEW":
				break;
			case "CLICK":
				break;
			case "scancode_push":
				break;
			case "scancode_waitmsg":
				break;
			default:
				break;
			}
			break;
		default:
			break;
		}
	}

	private void responseText(Writer writer, Map map) throws IOException {
		String responseText = "success";
		if (map.containsKey("MsgType") && map.containsKey("Content") && map.get("MsgType").equals("text")) {
			String type = map.get("Content");
			map.put("Content", new StringBuffer(type).reverse().toString());
		}
		responseText = XmlHelper.generate(map);
		System.out.println("返回公众号数据为:" + responseText);
		writer.append(responseText);
	}
通过以上处理,大致完成了公众号最基本功能的设计。

你可能感兴趣的:(微信开发)