从零开发微信公众号系列 【三】接收和自动回复消息


微信文档 

如果微信官方文档已能为您提供帮助,请忽略本文。

从零开发微信公众号系列 【三】接收和自动回复消息

WechatController.java

package com.blacklist.cotroller;

import java.io.IOException;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Scope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.blacklist.enums.WechatType;
import com.blacklist.server.WechatService;

@RestController
@SpringBootApplication
@RequestMapping("/wechat")
@Scope("prototype")
public class WechatController {
	@Autowired
	private WechatService wechatService;

	@RequestMapping(method = { RequestMethod.POST, RequestMethod.GET }, produces = "text/html;charset=UTF-8")
	@ResponseBody
	public void index(HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");
		boolean isGet = request.getMethod().toLowerCase().equals("get");
		if (isGet) {// 接入指引
			String signature = request.getParameter("signature");
			String timestamp = request.getParameter("timestamp");
			String nonce = request.getParameter("nonce");
			String echostr = request.getParameter("echostr");
			if (wechatService.validate(signature, timestamp, nonce)) {
				response.getWriter().write(echostr);
			}
		} else {// 接收用户消息
			Map<String, String> reqMap = wechatService.parseReq(request);
			if ("text".equalsIgnoreCase(reqMap.get("MsgType"))) {
				String input = wechatService.buildResponse(reqMap, WechatType.TEXT);
				response.getWriter().write(input);
			} else if("event".equalsIgnoreCase(reqMap.get("MsgType"))
					&& "subscribe".equalsIgnoreCase(reqMap.get("Event"))){
				String input = wechatService.buildResponse(reqMap, WechatType.EVENT);
				response.getWriter().write(input);
			}else {
				String input = wechatService.buildResponse(reqMap, WechatType.IMAGE);
				response.getWriter().write(input);
			}
		}
	}

}
WechatService.java
package com.blacklist.server;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.blacklist.config.WechatConfig;
import com.blacklist.domain.Topic;
import com.blacklist.domain.enums.TopicEnum;
import com.blacklist.enums.WechatType;
import com.blacklist.utils.FreemarkerUtils;
import com.blacklist.utils.LuceneIKUtil;
import com.blacklist.utils.SHA1;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

@Service
public class WechatService {
	private static Logger log = LoggerFactory.getLogger(WechatService.class);

	public String getToken() throws IOException {
		if ((System.currentTimeMillis() / 1000 - WechatConfig.expiresTime) > 7000) {
			String pathUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
					+ WechatConfig.appid
					+ "&secret="
					+ WechatConfig.secret;
			URL url = new URL(pathUrl);
			HttpURLConnection httpConn = (HttpURLConnection) url
					.openConnection();
			httpConn.setDoOutput(true);// 使用 URL 连接进行输出
			httpConn.setDoInput(true);// 使用 URL 连接进行输入
			httpConn.setUseCaches(false);// 忽略缓存
			httpConn.setRequestMethod("GET");// 设置URL请求方法
			httpConn.setRequestProperty("Accept", "*/*"); // 设置接收数据的格式
			httpConn.connect();

			int length = (int) httpConn.getContentLength();// 获取长度
			InputStream is = httpConn.getInputStream();
			if (length != -1) {
				byte[] data = new byte[length];
				byte[] temp = new byte[512];
				int readLen = 0;
				int destPos = 0;
				while ((readLen = is.read(temp)) > 0) {
					System.arraycopy(temp, 0, data, destPos, readLen);
					destPos += readLen;
				}
				String result = new String(data, "UTF-8");
				JsonObject json = new JsonParser().parse(result)
						.getAsJsonObject();
				WechatConfig.token = json.get("access_token")
						.getAsString();
				WechatConfig.expiresTime = System.currentTimeMillis() / 1000;
			}
		}

		System.out.println("wechat access token is:" + WechatConfig.token);
		return WechatConfig.token;
	}

	public boolean validate(String signature, String timestamp, String nonce) {
		List<String> list = new ArrayList<String>();
		list.add(timestamp);
		list.add(nonce);
		list.add(WechatConfig.token);
		Collections.sort(list);
		String temp = String.join("", list);
		if (signature.equals(SHA1.str2SHA1(temp))) {
			return true;
		}
		return false;
	}

	public Map<String, String> parseReq(HttpServletRequest request) {
		Map<String, String> resultMap = new HashMap<String, String>();
		try {
			InputStream inputStream = request.getInputStream();
			SAXReader reader = new SAXReader();
			Document document = reader.read(inputStream);
			Element root = document.getRootElement();
			@SuppressWarnings("unchecked")
			List<Element> elementList = root.elements();
			for (Element e : elementList) {
				resultMap.put(e.getName(), cut(e.getText()));
			}
			inputStream.close();
			inputStream = null;
		} catch (IOException | DocumentException e1) {
			log.error("wechat parseReq error:{}", e1.getMessage());
			e1.printStackTrace();
		}

		return resultMap;
	}

	public boolean validate() {
		return false;
	}
	
	private String cut(String str) {
		return str.replace("<![CDATA[", "").replace("]]>", "");
	}
	
	private String baseTextResponse(Map<String, String> map) {
		StringBuffer sb = new StringBuffer();
		sb.append("<xml>");
		sb.append("<ToUserName><![CDATA[" + map.get("FromUserName")
				+ "]]></ToUserName>");
		sb.append("<FromUserName><![CDATA[" + map.get("ToUserName")
				+ "]]></FromUserName>");
		sb.append("<CreateTime>" + System.currentTimeMillis() / 1000
				+ "</CreateTime>");
		sb.append("<MsgType><![CDATA[text]]></MsgType>");
		sb.append("<Content><![CDATA[###MSG###]]></Content>");
		sb.append("</xml>");
		return sb.toString();
	}

	private String buildNotSupportResponse(Map<String, String> map) {
		return baseTextResponse(map).replace("###MSG###", "不支持的消息!");
	}

	private String buildWelcome(Map<String, String> map) {
		return baseTextResponse(map).replace("###MSG###", "然而,你并不知道怎么玩");
	}
	
	private String buildError(Map<String, String> map, String err) {
		return baseTextResponse(map).replace("###MSG###", err);
	}

	private String buildResponse(Map<String, String> map) {
		String content = map.get("Content");
		if(WechatConfig.autoUser.equalsIgnoreCase(map.get("FromUserName"))) {
			return baseTextResponse(map).replace("###MSG###", "hello,"+content);
		} else {
			log.info("from user is:{}", map.get("FromUserName"));
			return buildNotSupportResponse(map);
		}
	}

	public String buildResponse(Map<String, String> map,
			WechatType type) {
		switch (type) {
		case TEXT:
			return buildResponse(map);
		case EVENT:
			return buildWelcome(map);
		default:
			return buildNotSupportResponse(map);
		}
	}
}
SHA1.java见上一篇

附请求参数:从零开发微信公众号系列 【三】接收和自动回复消息
响应参数:
从零开发微信公众号系列 【三】接收和自动回复消息

转载请注明来源【IT黑名单