首先我们必须先申请号所需要开发的微信公众号,这里传送门:https://mp.weixin.qq.com/,申请的流程我就不介绍了。
创建web工程,首先创建WeChatServlet类,重写它的doGet方法:
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();
if (CheckUtil.checkSignature(signature, timestamp, nonce)) {
out.print(echostr);
}
}
这是CheckUtil工具类:
public class CheckUtil {
private static final String token = "doomthr";
public static boolean checkSignature(String signature, String timestamp,
String nonce) {
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 = getSha1(content.toString());
return temp.equals(signature);
}
/**
* sha1加密
*
* @param str
* @return
*/
public static String getSha1(String str) {
if (null == str || 0 == str.length())
return null;
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(str.getBytes("UTF-8"));
byte[] md = mdTemp.digest();
int j = md.length;
char[] buf = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
buf[k++] = hexDigits[byte0 & 0xf];
}
return new String(buf);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
}
这个工具类主要验证了我们开发环境和微信后台环境的对接。
完成上述操作后在浏览器通过本地打开我们的WeChatServlet,看是否成功。成功后,就需要将我们内网映射到外网了。
这里我们使用的是ngrok工具,它的使用方法也很简单。先从命令提示行里切换到我们ngrok的安装路径,然后执行以下语句:
ngrok -config ngrok.cfg -subdomain wechat 8080
其中wechat是我们起的名字,8080是我们使用的端口。
执行完毕后,它会生成一个外网的http地址,我们用这个地址替换我们本地的地址,看是否映射成功,成功后就可以提交我们的开发者服务器配置了。
URL(服务器地址)就填写我们外网的地址,Token填写我们工具类中定义的token,点击生成EncodingAESKey,然后提交就可以了。
这里有可能会出现token验证失败、或者验证超时,检查下我们的代码,多提交几次就成功了
提交成功后,点击启用开发模式。
这里注意:开发模式和编辑模式是互相排斥的,二者只能使用一个。
返回我们的工程,创建MessageText实体类:
public class TextMessage {
private String ToUserName;
private String FromUserName;
private long CreateTime;
private String MsgType;
private String Content;
private String MsgId;
}
生成每一个属性的set和get方法。
这里注意,每一个属性的大小写和全名都要和帮助文档上的一致。
然后编写MessageUtil工具类,用来执行Stirng和Map还有xml之间的转换:
/**
* xml转换为map集合
*
* @param request
* @return
* @throws IOException
* @throws DocumentException
*/
public static Map xmlToMap(HttpServletRequest request)
throws IOException, DocumentException {
Map map = new HashMap();
SAXReader reader = new SAXReader();
InputStream in = request.getInputStream();
Document doc = reader.read(in);
Element root = doc.getRootElement();
List list = root.elements();
for (Element e : list) {
map.put(e.getName(), e.getText());
}
in.close();
return map;
}
/**
* 将文本消息转换为xml
*
* @param textMeesage
* @return
*/
public static String texMessageToXml(TextMessage textMeesage) {
XStream xStream = new XStream();
xStream.alias("xml", textMeesage.getClass());
return xStream.toXML(textMeesage);
}
这里还需要两个jar包,没有的需要下载一下,一个是解析xml的dom4j的jar包,一个是转换xml的xstream的jar包。
完成后,再重写我们的WeChatServlet里面的doPost方法:
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
try {
Map map = MessageUtil.xmlToMap(request);
String fromUserName = map.get("FromUserName");
String toUserName = map.get("ToUserName");
String msgType = map.get("MsgType");
String content = map.get("Content");
String message = null;
if ("text".equals(msgType)) {
TextMessage text = new TextMessage();
text.setFromUserName(toUserName);
text.setToUserName(fromUserName);
text.setMsgType("text");
text.setCreateTime(new Date().getTime());
text.setContent("您发送的消息是:" + content);
message = MessageUtil.texMessageToXml(text);
}
System.out.println(message);
out.print(message);
} catch (DocumentException e) {
e.printStackTrace();
} finally {
out.close();
}
}
然后测试向公众号发送消息,它已经可以根据你发的消息做自动回复了!
继续完善我们的工程,使它和我们用编辑器编辑的效果一致。
添加几种消息类型的常量:
public static final String MESSAGE_TEXT = "text";
public static final String MESSAGE_IMAGE = "image";
public static final String MESSAGE_VOICE = "voice";
public static final String MESSAGE_VIDEO = "video";
public static final String MESSAGE_LINK = "link";
public static final String MESSAGE_LOCATION = "location";
public static final String MESSAGE_EVENT = "event";
public static final String MESSAGE_SUBSCRIBE = "subscribe";
public static final String MESSAGE_UNSUBSCRIBE = "unsubscribe";
public static final String MESSAGE_CLICK = "CLICK";
public static final String MESSAGE_VIEW = "VIEW";
添加生成消息的方法:
/**
* 主菜单
*
* @return
*/
public static String menuText() {
StringBuffer sb = new StringBuffer();
sb.append("欢迎你的关注,请按照菜单提示操作:\n\n");
sb.append("1、近期好看的电影\n");
sb.append("2、87届奥斯卡获奖电影\n");
sb.append("回复?调出帮助菜单");
return sb.toString();
}
/**
* 回复1的菜单
* @return
*/
public static String firstMenu() {
StringBuffer sb = new StringBuffer();
sb.append("近期口碑不错的电影推荐——《大圣归来》,很不错,建议体验一下哦~");
return sb.toString();
}
/**
* 回复2的菜单
* @return
*/
public static String secondMenu() {
StringBuffer sb = new StringBuffer();
sb.append("《消失的爱人》——87届奥斯卡最佳女主角获奖电影,爱情悬疑类型电影迷的最爱。");
return sb.toString();
}
修改WeChatServlet类,根据不同消息做出不同的回复:
if (MessageUtil.MESSAGE_TEXT.equals(msgType)) {
if ("1".equals(content)) {
message = MessageUtil.initText(toUserName, fromUserName,
MessageUtil.firstMenu());
} else if ("2".equals(content)) {
message = MessageUtil.initText(toUserName, fromUserName,
MessageUtil.secondMenu());
} else if ("?".equals(content) || "?".equals(content)) {
message = MessageUtil.initText(toUserName, fromUserName,
MessageUtil.menuText());
}
// TextMessage text = new TextMessage();
// text.setFromUserName(toUserName);
// text.setToUserName(fromUserName);
// text.setMsgType("text");
// text.setCreateTime(new Date().getTime());
// text.setContent("您发送的消息是:" + content);
// message = MessageUtil.texMessageToXml(text);
} else if (MessageUtil.MESSAGE_EVENT.equals(msgType)) {
String eventType = map.get("Event");
if (MessageUtil.MESSAGE_SUBSCRIBE.equals(eventType)) {
message = MessageUtil.initText(toUserName, fromUserName,
MessageUtil.menuText());
}
}
OK~
源码下载