您的位置:首页 > 移动开发 > 微信开发

微信公众号后台java开发实现自动回复机器人

2016-06-26 13:50 756 查看
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		消息创建时间 (整型)
*	MsgType			text
*	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端口,一些忘记的命令见阿里云配置
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: