用Java搭建微信公众号(一)构建基础请求框架

最近帮朋友搭建一个微信公众号,通过查看微信公众号的开发者手册把基本功能实现了。把一些基本的可以通用的代码贴出来。

微信公众号提供了两种模式,一种是直接编辑模式,通过操作页面就能搭建基本的功能,比如自定义菜单功能就很好用。一种是开发者模式,需要写代码来搭建,基于HTTP接口(不完全符合REST风格)。比较麻烦的是两种模式是二选一的关系,使用了开发者模式,就得丢弃一些直接编辑的方便。

使用开发者模式的第一步是配置服务器。配置了URL,Token之后,微信服务器会发送一个HTTP GET请求到URL,并附加了signature,timestamp, nonce,echostr这几个参数。只要把echostr原样返回,微信服务器就认为配置成功了。而自己的服务器通过下列规则来判断是否配置成功

1. 把timestamp, nonce, token三个参数排序,然后拼成一个字符串

2. 使用SHA1加密这个字符串

3. 如果加密后的字符串等于signature,那么自己的服务器就可以认为配置成功。


配置的URL对应的控制器相当于一个前端控制器,负责处理微信服务器转发过来的请求。这里注意access_token的作用,如果自己的代码访问微信的HTTP接口,需要在HTTP请求中加入access_token。如果是微信服务器转发过来的请求,那么和access_token没有关系,可以直接处理。微信服务器转发过来的请求就两种,一种是GET,一般只在配置服务器的时候会有。另一种是POST XML的请求,比如用户点击微信公众的菜单,用户在微信公众号中发送的请求等等。


基本的处理微信服务器转发过来的请求代码框架如下


import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.springframework.web.servlet.ModelAndView;
import org.w3c.dom.Document;


public class WeixinAPIController extends AbstractBackController {
	private static final String token = "1234567890";

	@Override
	public ModelAndView handleBackRequest(HttpServletRequest request,
			HttpServletResponse response, Map model) throws Exception {
		
		boolean isGet = request.getMethod().toLowerCase().equals("get");
		if (isGet) {
			String echostr = request.getParameter("echostr");
			StringBuilder weixinContent = new StringBuilder();
			if (checkSignature(request)) {
				weixinContent.append(echostr);
			} else {
				weixinContent.append("Invalid request");
			}
			response.getWriter().print(weixinContent.toString());
		} else {
			ServletInputStream in = request.getInputStream();
			acceptXML(in, response);
		}
		response.getWriter().flush();
		response.getWriter().close();

		return null;

	}
	
	private void acceptXML(InputStream in, HttpServletResponse response) throws Exception{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(in);
			String toUserName = doc.getElementsByTagName("ToUserName").item(0).getFirstChild().getNodeValue();
			String fromUserName = doc.getElementsByTagName("FromUserName").item(0).getFirstChild().getNodeValue();
			String msgType = doc.getElementsByTagName("MsgType").item(0).getFirstChild().getNodeValue();
			if("text".equals(msgType)){
				String content = doc.getElementsByTagName("Content").item(0).getFirstChild().getNodeValue();
				
				if(content != null && content.length() > 0){
			             // 接收到微信服务器POST过来的文本信息		
				     // Do something
					
				}
			}else if("event".equals(msgType)){
				String event = doc.getElementsByTagName("Event").item(0).getFirstChild().getNodeValue();
				if("CLICK".equals(event)){
					String commandStr = doc.getElementsByTagName("EventKey").item(0).getFirstChild().getNodeValue();
					
					// 接收到微信服务器POST过来的点击菜单信息        
                                        // Do something
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	

	private boolean checkSignature(HttpServletRequest request) {
		boolean valid = false;
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		if (signature == null || timestamp == null || nonce == null) {
			return false;
		}

		List<String> array = new ArrayList<String>();
		array.add(token);
		array.add(timestamp);
		array.add(nonce);
		Collections.sort(array);
		String tempString = array.get(0) + array.get(1) + array.get(2);

		MessageDigest sha1;
		try {
			sha1 = MessageDigest.getInstance("SHA1");
			sha1.update(tempString.getBytes());
			byte[] bytes = sha1.digest();
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < bytes.length; i++) {
				String shaHex = Integer.toHexString(bytes[i] & 0xFF);
				if (shaHex.length() < 2) {
					sb.append(0);
				}
				sb.append(shaHex);
			}
			String encodedToken = sb.toString();
			if (encodedToken.equals(signature)) {
				valid = true;
			}
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}

		return valid;
	}

}


当启动服务器配置后,需要等待几分钟才会生效。生效之后就可以接收来自微信服务器转发的消息了。



你可能感兴趣的:(java,微信公众号)