1.注册微信公众号。(简单)
2.注册图灵机器人。(自己百度)
1)注册后可以拿到key (注意 api接入里的钥匙不要打开,否则要加解密,麻烦)
3.配置微信公众号服务器验证。
1)在开发的基本配置下,填写控制器servlet访问的路径。
2)token随意写,不过要和后台一致
3)选择明文
4)随机选个字符串
然后点击提交(这里微信会发送请求和你写的验证看是否匹配,具体看微信公众号平台开发文档) ?其实这里不用操作什么,他发送的匹配直接返回验证就过了,但是不是很安全。
4.接着是解析微信发送过来的xml格式,把他弄成map集合
5.解析得到内容 发送httpGet请求 丢过去给图灵机器人接口,返回回复内容
6.将东西封装成xml返回回去
然后OK
涉及的包 一个都不能少(当初就是少了commons-logging)
代码如下:
package com.lin.po; /* * 文本消息 <xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <MsgId>1234567890123456</MsgId> </xml> * */ /** * 参数描述 *ToUserName开发者微信号 *FromUserName发送方帐号(一个OpenID) * CreateTime消息创建时间 (整型) *MsgTypetext *Content文本消息内容 *MsgId消息id,64位整型 * @author linxinda * */ public class TextMessage { private String ToUserName; private String FromUserName; private long CreateTime; private String MsgType; private String Content; private String MsgId; public String getToUserName() { return ToUserName; } public void setToUserName(String toUserName) { ToUserName = toUserName; } public String getFromUserName() { return FromUserName; } public void setFromUserName(String fromUserName) { FromUserName = fromUserName; } public long getCreateTime() { return CreateTime; } public void setCreateTime(long createTime) { CreateTime = createTime; } public String getMsgType() { return MsgType; } public void setMsgType(String msgType) { MsgType = msgType; } public String getContent() { return Content; } public void setContent(String content) { Content = content; } public String getMsgId() { return MsgId; } public void setMsgId(String msgId) { MsgId = msgId; } }
package com.lin.servlet; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.lin.po.TextMessage; import com.lin.util.MessageUtil; import com.lin.util.TulingApiUtil; import com.lin.util.WeChatConnectValidateUtil; public class WeChatServlet extends HttpServlet { public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); resp.setCharacterEncoding("UTF-8"); PrintWriter out =resp.getWriter(); try { Map<String, String> map=MessageUtil.xmlToMap(req); String toUserName=map.get("ToUserName"); String fromUserName=map.get("FromUserName"); String msgType=map.get("MsgType"); String content=map.get("Content"); String message=null; if("text".equals(msgType)){ //System.out.println("text.equals(msgType)"); TextMessage text =new TextMessage(); text.setFromUserName(toUserName); text.setToUserName(fromUserName); text.setMsgType("text"); //这里填写回复内容 text.setContent(TulingApiUtil.getTulingResult(content)); text.setCreateTime(new Date().getTime()); message=MessageUtil.textMessageToXml(text); } //System.out.println(message); out.print(message); } catch (Exception e) { //System.out.println("doPost->try..catch"); e.printStackTrace(); }finally{ out.close(); } } /* * Get方法是微信接入请求验证时用的 其他都是post请求 * 参数描述 signature微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 timestamp时间戳 nonce随机数 echostr随机字符串 */ //其实这里不用搞加密,直接返回echostr也行 只是不太安全 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String signature=req.getParameter("signature"); String timestamp=req.getParameter("timestamp"); String nonce=req.getParameter("nonce"); String echostr=req.getParameter("echostr"); PrintWriter out =resp.getWriter(); if(WeChatConnectValidateUtil.checkSignature(signature,timestamp,nonce)){ out.print(echostr); } } }
package com.lin.util; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * 使用Java自带的MessageDigest类 * @author linxinda */ public class EncryptionUtil { public static String getSha1(String source){ // 用来将字节转换成 16 进制表示的字符 // System.out.println("进getSha1"); char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; try { MessageDigest mdTemp = MessageDigest.getInstance("SHA1"); mdTemp.update(source.getBytes("UTF-8")); // 通过使用 update 方法处理数据,使指定的 byte数组更新摘要 byte[] encryptStr = mdTemp.digest(); // 获得密文完成哈希计算,产生128 位的长整数 int j=encryptStr.length; char buf[] = new char[j * 2]; int k = 0; // 表示转换结果中对应的字符位置 for (int i = 0; i < j; i++) { // 从第一个字节开始,对每一个字节,转换成 j 进制字符的转换 byte byte0 = encryptStr[i]; // 取第 i 个字节 buf[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移 buf[k++] = hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换 } // System.out.println(buf.toString()); return new String(buf); // 换后的结果转换为字符串 } catch (Exception e) { //System.out.println("getSha1->try...catch"); e.printStackTrace(); } return null; } }
package com.lin.util; import java.io.IOException; import java.io.InputStream; 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 com.lin.po.TextMessage; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.StaxDriver; public class MessageUtil { /** * xml转为map集合 * @param request * @return * @throws IOException * @throws DocumentException */ public static Map<String,String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException{ //System.out.println("进xmlToMap"); Map<String,String> map=new HashMap<String, String>(); //dom4j saxReader解析xml SAXReader reader=new SAXReader(); //从request中获取输入流 InputStream ins = request.getInputStream(); //解析xml文档 Document doc =reader.read(ins); //获得根节点 Element root = doc.getRootElement(); //List存储 遍历 List<Element> list= root.elements(); for (Element e : list) { map.put(e.getName(), e.getText()); } ins.close(); // System.out.println(map.toString()); return map; } /** * 将文本消息对象转换为xml * @param textMessage * @return */ //xtream jar包 -> XStrem类提供对象转xml public static String textMessageToXml(TextMessage textMessage){ // System.out.println("进textMessageToXml"); /** * new StaxDriver()这个很重要 没有这个就错了 * XStream xstream=new XStream(new StaxDriver()); */ XStream xstream=new XStream(new StaxDriver()); xstream.alias("xml", textMessage.getClass()); // System.out.println("textMessage"); return xstream.toXML(textMessage); } }
package com.lin.util; import java.util.Arrays; public class WeChatConnectValidateUtil { //Token 和微信后台接入接口的token一致 private final static String TOKEN="linxinda"; public static boolean checkSignature(String signature,String timestamp,String nonce){ //System.out.println("进checkSignature"); String arr[]=new String[]{TOKEN,timestamp,nonce}; //排序 Arrays.sort(arr); //生成字符串 StringBuffer content=new StringBuffer(); for(int i=0;i<arr.length;i++){ content.append(arr[i]); } //sha1加密 String temp=EncryptionUtil.getSha1(content.toString()); // System.out.println(temp+" "+signature.equals(temp)); return signature.equals(temp); } }
// 调用图灵机器人api接口,获取智能回复内容: package com.lin.util; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.json.JSONException; import org.json.JSONObject; /** * 调用图灵机器人api接口,获取智能回复内容 * @author pamchen-1 * */ public class TulingApiUtil { /** * 调用图灵机器人api接口,获取智能回复内容,解析获取自己所需结果 * @param content * @return */ private static final String KEY="这里填自己的key"; public static String getTulingResult(String content){ //System.out.println("传入的内容->"+content); /** 此处为图灵api接口,参数key需要自己去注册申请,先以11111111代替 */ String apiUrl = "http://www.tuling123.com/openapi/api?key="+KEY+"&info="; String param = ""; //System.out.println("!!!!!!!"); try { param = apiUrl+URLEncoder.encode(content,"utf-8"); } catch (UnsupportedEncodingException e1) { System.out.println("UnsupportedEncodingException"); e1.printStackTrace(); } //将参数转为url编码 //System.out.println("?????????"); /** 发送httpget请求 */ HttpGet request = new HttpGet(param); String result = ""; try { HttpResponse response = HttpClients.createDefault().execute(request); /** * 特别注意 这一步一定要加commons-logging 这个jar包 否则会没反应,调试了好久!! * 似乎这个jar包是打印信息的 */ int code =response.getStatusLine().getStatusCode(); if(code==200){ result = EntityUtils.toString(response.getEntity()); } else { //System.out.println("code="+code); } } catch (ClientProtocolException e) { System.out.println("ClientProtocolException"); e.printStackTrace(); } catch (IOException e) { System.out.println("IOException"); e.printStackTrace(); } /** 请求失败处理 */ if(null==result){ //System.out.println("null==result"); return "对不起,你说的话真是太高深了……"; } // //System.out.println("..........."); try { StringBuffer bf=new StringBuffer(); String s=""; JSONObject json = new JSONObject(result); //以code=100000为例,参考图灵机器人api文档 /** * code 说明 100000文本类 200000链接类 302000新闻类 308000菜谱类 */ if(100000==json.getInt("code")){ s = json.getString("text"); bf.append(s); } else if(200000==json.getInt("code")){ s = json.getString("text"); bf.append(s); bf.append("\n"); s = json.getString("url"); bf.append(s); } else if(302000==json.getInt("code")){ //s = json.getString("text"); s="待开发有点麻烦!\n"; bf.append(s); } else if(308000==json.getInt("code")){ //s = json.getString("text"); s="待开发有点麻烦!\n"; bf.append(s); } result=bf.toString(); } catch (JSONException e) { System.out.println("JSONException"); e.printStackTrace(); } //System.out.println("机器人回复->"+result); return result; } }
package com.lin.test; import java.io.BufferedInputStream; import java.util.Scanner; import com.lin.util.TulingApiUtil; public class Test { public static void main(String[] args) { Scanner scanner=new Scanner(new BufferedInputStream(System.in)); while(scanner.hasNext()){ String content=scanner.next(); System.out.println(TulingApiUtil.getTulingResult(content)); } scanner.close(); } }
最后总结自己遇到的问题,便于日后查看:
1. 图灵机器人的加密钥匙要关闭,否则就得进行加解密操作,他的api里有详细说明。
2.可以多写些测试类方便调试,不要每次都传到服务器上调试,好麻烦。
最后记下自己服务器的一些信息
service tomcat6/httpd/iptable restart
微信要80端口,一些忘记的命令见阿里云配置
转载请注明本文地址: 微信公众号后台java开发实现自动回复机器人