微信公众平台开发实战(05) 历史上的今天
实现历史上的今天功能:
- 接受“历史MMDD”的输入;
- 如果只输入“历史”,则输出当前日期的历史;
- 如果输入“历史1022”,则输出“10月22日”的历史
目录结构
- 项目结构图
- 增加和修改相关源代码
- 历史实体类
- 历史操作类
- 历史服务类
- 历史表和数据脚本文件
-
核心Service
- 消息工具类
- 上传本地代码到GitHub
- 上传工程WAR档至SAE
- 微信客户端测试
- 参考文档
- 完整项目源代码
项目结构图
源代码文件说明
序号 | 文件名 | 说明 | 操作 |
1 | History.java | 历史实体类 | 新增 |
2 | HistoryDao.java | 历史操作类 | 新增 |
3 | TodayInHistoryService.java | 历史上的今天服务类 | 新增 |
4 | history.sql | 历史表和数据脚本文件 | 新增 |
5 | CoreService.java | 核心服务类,新增处理各种输入,返回不同图文信息 | 更新 |
6 | MessageUtil.java | 新增生成图文信息的方法 | 更新 |
增加和修改相关源代码
历史实体类
History.java
package com.coderdream.bean;
/**
* 历史
*
* @author CoderDream
*
*/
public class History {
private String day;
private String event;
public String getDay() {
return day;
}
public void setDay(String day) {
this.day = day;
}
public String getEvent() {
return event;
}
public void setEvent(String event) {
this.event = event;
}
}
历史操作类
HistoryDao.java
package com.coderdream.dao;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.coderdream.bean.History;
import com.coderdream.util.DBUtil;
public class HistoryDao {
private static Logger logger = LoggerFactory.getLogger(HistoryDao.class);
public static List<History> getHistoryList(String dayStr) {
List<History> list = new ArrayList<History>();
Connection connection = null;
Statement stmt = null;
ResultSet rs = null;
// 检索数据
try {
connection = DBUtil.getConnection();
stmt = connection.createStatement();
int number = stmt.executeUpdate("prepare mystmt from 'select day,event from history where day = ?'");
if (null == dayStr || "".equals(dayStr.trim())) {
DateFormat df = new SimpleDateFormat("MMdd");
dayStr = df.format(Calendar.getInstance().getTime());
}
stmt.execute("set @day='" + dayStr + "'");
rs = stmt.executeQuery("execute mystmt using @day");
System.out.println(number);
ResultSetMetaData rsmd = rs.getMetaData(); // 表的字段属性变量
// 按字段属性输出表的数据名
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
logger.info(rsmd.getColumnName(i) + "\t");
}
logger.info("\n--------------------------------------\n");
History history = null;
while (rs.next()) {
history = new History();
String day = rs.getString("day");
String event = rs.getString("event");
history.setDay(day);
history.setEvent(event);
logger.info("%-8d%-8d%-12s\n", day, event);
list.add(history);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public static void main(String[] args) {
List<History> list = getHistoryList("0220");
for (Iterator<History> iterator = list.iterator(); iterator.hasNext();) {
History history = iterator.next();
System.out.println(history.getDay() + ":" + history.getEvent());
}
List<History> list2 = getHistoryList("");
for (Iterator<History> iterator = list2.iterator(); iterator.hasNext();) {
History history = iterator.next();
System.out.println(history.getDay() + ":" + history.getEvent());
}
}
}
历史上的今天服务类
TodayInHistoryService.java
package com.coderdream.service;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.coderdream.bean.History;
import com.coderdream.dao.HistoryDao;
/**
* 历史上的今天查询服务
*
*
*/
public class TodayInHistoryService {
/**
* 发起http get请求获取网页源代码
*
* @param requestUrl
* @return
*/
private static String httpRequest(String requestUrl) {
StringBuffer buffer = null;
try {
// 建立连接
URL url = new URL(requestUrl);
HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
httpUrlConn.setDoInput(true);
httpUrlConn.setRequestMethod("GET");
// 获取输入流
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
// 读取返回结果
buffer = new StringBuffer();
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
httpUrlConn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
return buffer.toString();
}
/**
* 从html中抽取出历史上的今天信息
*
* @param html
* @return
*/
private static String extract(String html) {
StringBuffer buffer = null;
// 日期标签:区分是昨天还是今天
String dateTag = getMonthDay(0);
Pattern p = Pattern.compile("(.*)(<div class=\"listren\">)(.*?)(</div>)(.*)");
Matcher m = p.matcher(html);
if (m.matches()) {
buffer = new StringBuffer();
if (m.group(3).contains(getMonthDay(-1)))
dateTag = getMonthDay(-1);
// 拼装标题
buffer.append("≡≡ ").append("历史上的").append(dateTag).append(" ≡≡").append("\n\n");
// 抽取需要的数据
for (String info : m.group(3).split(" ")) {
info = info.replace(dateTag, "").replace("(图)", "").replaceAll("</?[^>]+>", "")
.replaceAll(" ", "").trim();
// 在每行末尾追加2个换行符
if (!"".equals(info)) {
buffer.append(info).append("\n\n");
}
}
}
// 将buffer最后两个换行符移除并返回
return (null == buffer) ? null : buffer.substring(0, buffer.lastIndexOf("\n\n"));
}
/**
* 获取前/后n天日期(M月d日)
*
* @return
*/
private static String getMonthDay(int diff) {
DateFormat df = new SimpleDateFormat("M月d日");
Calendar c = Calendar.getInstance();
c.add(Calendar.DAY_OF_YEAR, diff);
return df.format(c.getTime());
}
/**
* 封装历史上的今天查询方法,供外部调用
*
* @return
*/
public static String getTodayInHistoryInfo() {
// 获取网页源代码
String html = httpRequest("http://www.rijiben.com/");
// 从网页中抽取信息
String result = extract(html);
return result;
}
/**
* 封装历史上的今天查询方法,供外部调用
*
* @return
*/
public static String getTodayInHistoryInfoFromDB(String dayString) {
// 从网页中抽取信息
StringBuffer result = new StringBuffer(dayString + "\n");
result.append("========" + "\n");
List<History> list = HistoryDao.getHistoryList(dayString);
for (Iterator<History> iterator = list.iterator(); iterator.hasNext();) {
History history = iterator.next();
System.out.println(history.getDay() + ":" + history.getEvent());
result.append(history.getEvent() + "\n");
}
return result.toString();
}
/**
* 通过main在本地测试
*
* @param args
*/
public static void main(String[] args) {
// System.setProperty("http.proxySet", "true");
// System.setProperty("http.proxyHost", "proxy.jpn.hp.com");
// System.setProperty("http.proxyPort", "8080");
String info = getTodayInHistoryInfo();
System.out.println(info);
// System.out.println(DateUtil.getMonthDayMMdd(0));
}
}
核心服务类
更新代码后,能接受“历史MMDD”的输入;
- 如果只输入“历史”,则输出当前日期的历史;
- 如果输入“历史1022”,则输出“10月22日”的历史。
CoreService.java
package com.coderdream.service;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import com.coderdream.bean.Logging;
import com.coderdream.dao.LoggingDao;
import com.coderdream.model.Article;
import com.coderdream.model.NewsMessage;
import com.coderdream.model.TextMessage;
import com.coderdream.util.MessageUtil;
/**
* 核心服务类
*/
public class CoreService {
public static String TAG = "CoreService";
private Logger logger = Logger.getLogger(CoreService.class);
/**
* 处理微信发来的请求
*
* @param request
* @return xml
*/
public String processRequest(InputStream inputStream) {
logger.debug(TAG + " #1# processRequest");
SimpleDateFormat f_timestamp = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
Logging logging = new Logging(f_timestamp.format(Calendar.getInstance().getTime()), "DEBUG", TAG,
"#1# processRequest");
LoggingDao loggingDao = new LoggingDao();
loggingDao.addLogging(logging);
// xml格式的消息数据
String respXml = null;
// 默认返回的文本消息内容
String respContent = "未知的消息类型!";
try {
// 调用parseXml方法解析请求消息
Map<String, String> requestMap = MessageUtil.parseXml(inputStream);
// 发送方帐号
String fromUserName = requestMap.get("FromUserName");
// 开发者微信号
String toUserName = requestMap.get("ToUserName");
// 消息类型
String msgType = requestMap.get("MsgType");
String logStr = "#2# fromUserName: " + fromUserName + ", toUserName: " + toUserName + ", msgType: "
+ msgType;
logger.debug(TAG + logStr);
logging = new Logging(f_timestamp.format(Calendar.getInstance().getTime()), "DEBUG", TAG, logStr);
loggingDao.addLogging(logging);
// 回复文本消息
TextMessage textMessage = new TextMessage();
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(MessageUtil.MESSAGE_TYPE_TEXT);
logStr = "#3# textMessage: " + textMessage.toString();
logger.debug(TAG + logStr);
logging = new Logging(f_timestamp.format(Calendar.getInstance().getTime()), "DEBUG", TAG, logStr);
loggingDao.addLogging(logging);
// 文本消息
if (msgType.equals(MessageUtil.MESSAGE_TYPE_TEXT)) {
respContent = "您发送的是文本消息!";
// 接收用户发送的文本消息内容
String content = requestMap.get("Content");
// 创建图文消息
NewsMessage newsMessage = new NewsMessage();
newsMessage.setToUserName(fromUserName);
newsMessage.setFromUserName(toUserName);
newsMessage.setCreateTime(new Date().getTime());
newsMessage.setMsgType(MessageUtil.MESSAGE_TYPE_NEWS);
// newsMessage.setFuncFlag(0);
List<Article> articleList = new ArrayList<Article>();
// 如果以“历史”2个字开头
if (content.startsWith("历史")) {
// 将歌曲2个字及歌曲后面的+、空格、-等特殊符号去掉
String dayStr = content.substring(2);
// 如果只输入历史两个字,在输出当天的历史
if (null == dayStr || "".equals(dayStr.trim())) {
DateFormat df = new SimpleDateFormat("MMdd");
dayStr = df.format(Calendar.getInstance().getTime());
}
respContent = TodayInHistoryService.getTodayInHistoryInfoFromDB(dayStr);
textMessage.setContent(respContent);
// 将图文消息对象转换成xml字符串
return MessageUtil.messageToXml(textMessage);
}
// 单图文消息
else if ("1".equals(content)) {
Article article = new Article();
article.setTitle("微信公众帐号开发教程Java版");
article.setDescription("柳峰,80后,微信公众帐号开发经验4个月。为帮助初学者入门,特推出此系列教程,也希望借此机会认识更多同行!");
article.setPicUrl("http://wxquan.sinaapp.com/meal.jpg");
article.setUrl("http://blog.****.net/lyq8479?toUserName=" + fromUserName + "&toUserName="
+ toUserName);
articleList.add(article);
// 设置图文消息个数
newsMessage.setArticleCount(articleList.size());
// 设置图文消息包含的图文集合
newsMessage.setArticles(articleList);
// 将图文消息对象转换成xml字符串
return MessageUtil.messageToXml(newsMessage);
}
// 单图文消息---不含图片
else if ("2".equals(content)) {
Article article = new Article();
article.setTitle("微信公众帐号开发教程Java版");
// 图文消息中可以使用QQ表情、符号表情
article.setDescription("柳峰,80后,"
// + emoji(0x1F6B9)
+ ",微信公众帐号开发经验4个月。为帮助初学者入门,特推出此系列连载教程,也希望借此机会认识更多同行!\n\n目前已推出教程共12篇,包括接口配置、消息封装、框架搭建、QQ表情发送、符号表情发送等。\n\n后期还计划推出一些实用功能的开发讲解,例如:天气预报、周边搜索、聊天功能等。");
// 将图片置为空
article.setPicUrl("");
article.setUrl("http://blog.****.net/lyq8479?toUserName=" + fromUserName + "&toUserName="
+ toUserName);
articleList.add(article);
newsMessage.setArticleCount(articleList.size());
newsMessage.setArticles(articleList);
return MessageUtil.messageToXml(newsMessage);
}
// 多图文消息
else if ("3".equals(content)) {
Article article1 = new Article();
article1.setTitle("微信公众帐号开发教程\n引言");
article1.setDescription("");
article1.setPicUrl("http://wxquan.sinaapp.com/meal.jpg");
article1.setUrl("http://blog.****.net/lyq8479/article/details/8937622?toUserName=" + fromUserName
+ "&toUserName=" + toUserName);
Article article2 = new Article();
article2.setTitle("第2篇\n微信公众帐号的类型");
article2.setDescription("");
article2.setPicUrl("http://wxquan.sinaapp.com/meal.jpg");
article2.setUrl("http://blog.****.net/lyq8479/article/details/8941577?toUserName=" + fromUserName
+ "&toUserName=" + toUserName);
Article article3 = new Article();
article3.setTitle("关注页面");
article3.setDescription("关注页面");
article3.setPicUrl("http://wxquan.sinaapp.com/meal.jpg");
article3.setUrl("http://wxquan.sinaapp.com/follow.jsp?toUserName=" + fromUserName + "&toUserName="
+ toUserName);
articleList.add(article1);
articleList.add(article2);
articleList.add(article3);
newsMessage.setArticleCount(articleList.size());
newsMessage.setArticles(articleList);
return MessageUtil.messageToXml(newsMessage);
}
// 多图文消息---首条消息不含图片
else if ("4".equals(content)) {
Article article1 = new Article();
article1.setTitle("微信公众帐号开发教程Java版");
article1.setDescription("");
// 将图片置为空
article1.setPicUrl("");
article1.setUrl("http://blog.****.net/lyq8479");
Article article2 = new Article();
article2.setTitle("第4篇\n消息及消息处理工具的封装");
article2.setDescription("");
article2.setPicUrl("http://wxquan.sinaapp.com/meal.jpg");
article2.setUrl("http://blog.****.net/lyq8479/article/details/8949088?toUserName=" + fromUserName
+ "&toUserName=" + toUserName);
Article article3 = new Article();
article3.setTitle("第5篇\n各种消息的接收与响应");
article3.setDescription("");
article3.setPicUrl("http://wxquan.sinaapp.com/meal.jpg");
article3.setUrl("http://blog.****.net/lyq8479/article/details/8952173?toUserName=" + fromUserName
+ "&toUserName=" + toUserName);
Article article4 = new Article();
article4.setTitle("第6篇\n文本消息的内容长度限制揭秘");
article4.setDescription("");
article4.setPicUrl("http://wxquan.sinaapp.com/meal.jpg");
article4.setUrl("http://blog.****.net/lyq8479/article/details/8967824?toUserName=" + fromUserName
+ "&toUserName=" + toUserName);
articleList.add(article1);
articleList.add(article2);
articleList.add(article3);
articleList.add(article4);
newsMessage.setArticleCount(articleList.size());
newsMessage.setArticles(articleList);
return MessageUtil.messageToXml(newsMessage);
}
// 多图文消息---最后一条消息不含图片
else if ("5".equals(content)) {
Article article1 = new Article();
article1.setTitle("第7篇\n文本消息中换行符的使用");
article1.setDescription("");
article1.setPicUrl("http://wxquan.sinaapp.com/meal.jpg");
article1.setUrl("http://blog.****.net/lyq8479/article/details/9141467?toUserName=" + fromUserName
+ "&toUserName=" + toUserName);
Article article2 = new Article();
article2.setTitle("第8篇\n文本消息中使用网页超链接");
article2.setDescription("");
article2.setPicUrl("http://wxquan.sinaapp.com/meal.jpg");
article2.setUrl("http://blog.****.net/lyq8479/article/details/9157455?toUserName=" + fromUserName
+ "&toUserName=" + toUserName);
Article article3 = new Article();
article3.setTitle("如果觉得文章对你有所帮助,请通过博客留言或关注微信公众帐号xiaoqrobot来支持柳峰!");
article3.setDescription("");
// 将图片置为空
article3.setPicUrl("");
article3.setUrl("http://blog.****.net/lyq8479");
articleList.add(article1);
articleList.add(article2);
articleList.add(article3);
newsMessage.setArticleCount(articleList.size());
newsMessage.setArticles(articleList);
// respContent = messageUtil.messageToXml(newsMessage);
return MessageUtil.messageToXml(newsMessage);
}
}
// 图片消息
else if (msgType.equals(MessageUtil.MESSAGE_TYPE_IMAGE)) {
respContent = "您发送的是图片消息!";
}
// 语音消息
else if (msgType.equals(MessageUtil.MESSAGE_TYPE_VOICE)) {
respContent = "您发送的是语音消息!";
}
// 视频消息
else if (msgType.equals(MessageUtil.MESSAGE_TYPE_VIDEO)) {
respContent = "您发送的是视频消息!";
}
// 地理位置消息
else if (msgType.equals(MessageUtil.MESSAGE_TYPE_LOCATION)) {
respContent = "您发送的是地理位置消息!";
}
// 链接消息
else if (msgType.equals(MessageUtil.MESSAGE_TYPE_LINK)) {
respContent = "您发送的是链接消息!";
}
// 事件推送
else if (msgType.equals(MessageUtil.MESSAGE_TYPE_EVENT)) {
// 事件类型
String eventType = requestMap.get("Event");
// 关注
if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {
respContent = "谢谢您的关注!";
}
// 取消关注
else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {
// TODO 取消订阅后用户不会再收到公众账号发送的消息,因此不需要回复
}
// 扫描带参数二维码
else if (eventType.equals(MessageUtil.EVENT_TYPE_SCAN)) {
// TODO 处理扫描带参数二维码事件
}
// 上报地理位置
else if (eventType.equals(MessageUtil.EVENT_TYPE_LOCATION)) {
// TODO 处理上报地理位置事件
}
// 自定义菜单
else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {
// TODO 处理菜单点击事件
}
}
logStr = "#4# respContent: " + respContent;
logger.debug(TAG + logStr);
logging = new Logging(f_timestamp.format(Calendar.getInstance().getTime()), "DEBUG", TAG, logStr);
loggingDao.addLogging(logging);
// 设置文本消息的内容
textMessage.setContent(respContent);
// 将文本消息对象转换成xml
respXml = MessageUtil.messageToXml(textMessage);
logStr = "#5# respXml: " + respXml;
logger.debug(TAG + logStr);
logging = new Logging(f_timestamp.format(Calendar.getInstance().getTime()), "DEBUG", TAG, logStr);
loggingDao.addLogging(logging);
} catch (Exception e) {
e.printStackTrace();
}
return respXml;
}
}
上传本地代码到GitHub
将新增和修改过的代码上传到GitHub
上传工程WAR档至SAE
将eclipse中的工程导出为wxquan.war档,上传到SAE中,更新已有的版本。
微信客户端测试
登录微信网页版:https://wx.qq.com/
输入“历史1001”和“历史”,返回不同的图文信息。
参考文档
完整源代码