zttcc 2012-12-11
最近要给公司写个微信的公众平台自动回复的程序,就研究了微信的公众平台的api,发现目前api提供的功能还比较少,仅仅只能被动式应答,而且只能收取文字,图片和地理信息类的消息,但是从这个web版的管理平台可以在线管理消息来看,其实是可以用Java模拟浏览器的行为从而实现高级的功能,比如获取声音,主动群发消息,但是由于这些功能不是api中提供的,存在以后接口发生变化的可能,所以可以用来做个小工具来使用这些高级功能但不适合在产品中使用
官方给的调用api的例子只有php的,我这里用java实现了个简单的文本回复的,DOM解析部分因为刚好有dom4j的jar包就用了,换成jdk自带的w3c的dom解析也行,反正消息xml内容很少
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; public class WeixinpublicServlet extends HttpServlet { private static final long serialVersionUID = -4267408236898837036L; private static final String TOKEN = "weixin"; private static final String RESPONSE_TXT = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[%s]]></MsgType><Content><![CDATA[%s]]></Content><FuncFlag>0</FuncFlag></xml>"; public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { String signature = request.getParameter("signature"); String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); PrintWriter out = response.getWriter(); if(checkSignature(signature,timestamp,nonce)){ out.print(request.getParameter("echostr")); } out.close(); out = null; } public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); Document doc = null; SAXReader reader = new SAXReader(); InputStream in = request.getInputStream(); try { doc = reader.read(in); Element root = doc.getRootElement(); String toUserName = root.element("ToUserName").getTextTrim(); String fromUserName = root.element("FromUserName").getTextTrim(); String content = root.element("Content").getTextTrim(); // root.element("MsgType")可以获取消息类型 // 这里只回复简单文本信息 out.printf(RESPONSE_TXT, fromUserName,toUserName,System.currentTimeMillis(),"text","您发送的内容是:"+content); } catch (DocumentException e) { e.printStackTrace(); } in.close(); in = null; out.close(); out = null; } private static boolean checkSignature(String signature,String timestamp,String nonce){ String[] arr = new String[]{TOKEN,timestamp,nonce}; Arrays.sort(arr); StringBuilder content = new StringBuilder(); for(int i=0;i<arr.length;i++){ content.append(arr[i]); } MessageDigest md = null; String tmpStr = null; try { md = MessageDigest.getInstance("SHA-1"); byte[] digest = md.digest(content.toString().getBytes()); tmpStr = byteToStr(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } content = null; return tmpStr!=null?tmpStr.equals(signature.toUpperCase()):false; } // 将字节转换为十六进制字符串 private static String byteToHexStr(byte ib) { char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; char[] ob = new char[2]; ob[0] = Digit[(ib >>> 4) & 0X0F]; ob[1] = Digit[ib & 0X0F]; String s = new String(ob); return s; } // 将字节数组转换为十六进制字符串 private static String byteToStr(byte[] bytearray) { String strDigest = ""; for (int i = 0; i < bytearray.length; i++) { strDigest += byteToHexStr(bytearray[i]); } return strDigest; } }