又颓废了些日子,说好认真来半年的,那就接着来啊,公司的easyUI平台慢慢开始明白了,可是最近bug太多了,只能找时间在研究了,平时无聊看见了了java微信平台开发,感觉有点意思呀,自己也来试试,不过又得求教博客园里面的大神们了,现在开始研究。
一开始无聊的时候,自己在新浪云服务器注册了一个账号,可以建立一些应用在上面,微信平台也是可以的。于是自己照着微信官方的例子,建立了微信公众平台与新浪云服务器的接口,成功了。不过官方是用PHP语言写的(也许PHP是世界上最好的语言)。可是作为一个Javaer,当然要学会怎么写Java了。先贴把这个例子贴一下吧。
<?php/** * wechat php test *///define your tokendefine("TOKEN", "haojiahongxihuanliyuan");$wechatObj = new wechatCallbackapiTest();$wechatObj->valid();class wechatCallbackapiTest{ public function valid() { $echoStr = $_GET["echostr"]; //valid signature , option if($this->checkSignature()){ echo $echoStr; exit; } } public function responseMsg() { //get post data, May be due to the different environments $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; //extract post data if (!empty($postStr)){ /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection, the best way is to check the validity of xml by yourself */ libxml_disable_entity_loader(true); $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); $fromUsername = $postObj->FromUserName; $toUsername = $postObj->ToUserName; $keyword = trim($postObj->Content); $time = time(); $textTpl = "<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Content><![CDATA[%s]]></Content> <FuncFlag>0</FuncFlag> </xml>"; if(!empty( $keyword )) { $msgType = "text"; $contentStr = "Welcome to wechat world!"; $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr); echo $resultStr; }else{ echo "Input something..."; } }else { echo ""; exit; } } private function checkSignature() { // you must define TOKEN by yourself if (!defined("TOKEN")) { throw new Exception('TOKEN is not defined!'); } $signature = $_GET["signature"]; $timestamp = $_GET["timestamp"]; $nonce = $_GET["nonce"]; $token = TOKEN; $tmpArr = array($token, $timestamp, $nonce); // use SORT_STRING rule sort($tmpArr, SORT_STRING); $tmpStr = implode( $tmpArr ); $tmpStr = sha1( $tmpStr ); if( $tmpStr == $signature ){ return true; }else{ return false; } }}?>
这个是官方提过的接口程序。
下面开始研究Java接口程序。
当用户通过微信客服端发送消息到微信服务后,微信服务器会将此消息转发给我们的公网服务器,也就是上面所说sae新浪云服务器。具体的业务逻辑就在sae上完成,处理完后再将结果发回微信服务器,微信服务器再发给用户。
让两个完全不沾边的服务器(微信服务器和sae)对接是有风险,因此必须有验证机制的存在。具体的验证过程是
代码如下:
微信公众平台去请求sae中的coreServlet。
package org.liufeng.course.servlet;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.liufeng.course.service.CoreService;import org.liufeng.course.util.SignUtil;/** * 请求处理的核心类 * * @author liufeng * @date 2013-09-29 */public class CoreServlet extends HttpServlet { private static final long serialVersionUID = 4440739483644821986L; /** * 请求校验(确认请求来自微信服务器) */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 微信加密签名 String signature = request.getParameter("signature"); // 时间戳 String timestamp = request.getParameter("timestamp"); // 随机数 String nonce = request.getParameter("nonce"); // 随机字符串 String echostr = request.getParameter("echostr"); PrintWriter out = response.getWriter(); // 请求校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败 if (SignUtil.checkSignature(signature, timestamp, nonce)) { out.print(echostr); } out.close(); out = null; } /** * 处理微信服务器发来的消息 */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 将请求、响应的编码均设置为UTF-8(防止中文乱码) request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); // 调用核心业务类接收消息、处理消息 String respXml = CoreService.processRequest(request); // 响应消息 PrintWriter out = response.getWriter(); out.print(respXml); out.close(); }}
消息处理类:
package org.liufeng.course.util;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Arrays;/** * 请求校验工具类 * * @author liufeng * @date 2013-09-01 */public class SignUtil { // 与开发模式接口配置信息中的Token保持一致 private static String token = "weixinCourse"; /** * 校验签名 * * @param signature 微信加密签名 * @param timestamp 时间戳 * @param nonce 随机数 * @return */ public static boolean checkSignature(String signature, String timestamp, String nonce) { // 对token、timestamp和nonce按字典排序 String[] paramArr = new String[] { token, timestamp, nonce }; Arrays.sort(paramArr); // 将排序后的结果拼接成一个字符串 String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]); String ciphertext = null; try { MessageDigest md = MessageDigest.getInstance("SHA-1"); // 对接后的字符串进行sha1加密 byte[] digest = md.digest(content.toString().getBytes()); ciphertext = byteToStr(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } // 将sha1加密后的字符串与signature进行对比 return ciphertext != null ? ciphertext.equals(signature.toUpperCase()) : false; } /** * 将字节数组转换为十六进制字符串 * * @param byteArray * @return */ private static String byteToStr(byte[] byteArray) { String strDigest = ""; for (int i = 0; i < byteArray.length; i++) { strDigest += byteToHexStr(byteArray[i]); } return strDigest; } /** * 将字节转换为十六进制字符串 * * @param mByte * @return */ private static String byteToHexStr(byte mByte) { char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; char[] tempArr = new char[2]; tempArr[0] = Digit[(mByte >>> 4) & 0X0F]; tempArr[1] = Digit[mByte & 0X0F]; String s = new String(tempArr); return s; }}
web.xml中配置了coreServlet:
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>coreServlet</servlet-name> <servlet-class> org.liufeng.course.servlet.CoreServlet </servlet-class> </servlet> <!-- /coreServlet用于指定该Servlet的访问路径 --> <servlet-mapping> <servlet-name>coreServlet</servlet-name> <url-pattern>/coreServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list></web-app>
微信公众平台的配置截图:
微信平台提示接入成功。