实现查找百度音乐中的歌曲功能;
接受“歌曲歌名”的输入,返回百度音乐中的歌曲;
目录结构
- 项目结构图
- 增加和修改相关源代码
- 音乐类
- 音乐消息类
- 百度音乐服务类
- 消息基类
-
核心Service
- 消息处理工具类
- 上传本地代码到GitHub
- 上传工程WAR档至SAE
- 微信客户端测试
- 参考文档
- 完整项目源代码
项目结构图
源代码文件说明
序号 | 文件名 | 说明 | 操作 |
1 | Music.java | 音乐类 | 新增 |
2 | MusicMessage.java | 音乐消息类 | 新增 |
3 | BaiduMusicService.java | 百度音乐服务类 | 新增 |
4 | BaseMessage.java | 消息基类 | 更新 |
5 | CoreService.java | 核心服务类,新增处理输入“音乐歌名” | 更新 |
6 | MessageUtil.java | 新增生成音乐消息的方法 | 更新 |
增加和修改相关源代码
音乐类
Music.java
package com.coderdream.model;
/**
* <pre>
* 音乐model
* 1)参数Title:标题,本例中可以设置为歌曲名称;
*
* 2)参数Description:描述,本例中可以设置为歌曲的演唱者;
*
* 3)参数MusicUrl:普通品质的音乐链接;
*
* 4)参数HQMusicUrl:高品质的音乐链接,在WIFI环境下会优先使用
* 该链接播放音乐;
*
* 5)参数ThumbMediaId:缩略图的媒体ID,通过上传多媒体文件获得;
* 它指向的是一张图片,最终会作为音乐消息左侧绿色方形区域的背景图片。
*
* 上述5个参数中,最为重要的是MusicUrl和HQMusicUrl,这也是本文
* 的重点,如何根据歌曲名称获得歌曲的链接。如果读者只能得到歌曲的一个
* 链接,可以将MusicUrl和HQMusicUrl设置成一样的。至于
* ThumbMediaId参数,必须是通过微信认证的服务号才能得到,
* 普通的服务号与订阅号可以忽略该参数,也就是说,
* 在回复给微信服务器的XML中可以不包含ThumbMediaId参数。
* (如果没有通过认证,就不要加入这个参数!!!)
*
* <pre>
*/
public class Music {
/**
* 音乐标题
*/
private String Title;
/**
* 音乐描述
*/
private String Description;
/**
* 音乐链接
*/
private String MusicUrl;
/**
* 高质量音乐链接,WIFI环境优先使用该链接播放音乐
*/
private String HQMusicUrl;
// 缩略图的媒体id,通过上传多媒体文件得到的id
// private String ThumbMediaId;
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public String getMusicUrl() {
return MusicUrl;
}
public void setMusicUrl(String musicUrl) {
MusicUrl = musicUrl;
}
public String getHQMusicUrl() {
return HQMusicUrl;
}
public void setHQMusicUrl(String musicUrl) {
HQMusicUrl = musicUrl;
}
// public String getThumbMediaId() {
// return ThumbMediaId;
// }
//
// public void setThumbMediaId(String thumbMediaId) {
// ThumbMediaId = thumbMediaId;
// }
}
音乐消息类
MusicMessage.java
package com.coderdream.model;
/**
* 音乐消息
*
*/
public class MusicMessage extends BaseMessage {
/**
* 音乐
*/
private Music Music;
public Music getMusic() {
return Music;
}
public void setMusic(Music music) {
Music = music;
}
}
百度音乐服务类
BaiduMusicService.java
package com.coderdream.service;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.coderdream.model.Music;
/**
* 百度音乐搜索API操作类
*
*/
public class BaiduMusicService {
private static Logger logger = LoggerFactory.getLogger(BaiduMusicService.class);
/**
* 根据名称和作者搜索音乐
*
* @param musicTitle
* 音乐名称
* @param musicAuthor
* 音乐作者
* @return Music
*/
public static Music searchMusic(String musicTitle, String musicAuthor) {
logger.info("searchMusic begin");
// 百度音乐搜索地址
String requestUrl = "http://box.zhangmen.baidu.com/x?op=12&count=1&title={TITLE}$${AUTHOR}$$$$";
// 对音乐名称、作者进URL编码
requestUrl = requestUrl.replace("{TITLE}", urlEncodeUTF8(musicTitle));
requestUrl = requestUrl.replace("{AUTHOR}", urlEncodeUTF8(musicAuthor));
// 处理名称、作者中间的空格
requestUrl = requestUrl.replaceAll("\\+", "%20");
// 查询并获取返回结果
InputStream inputStream = httpRequest(requestUrl);
// 从返回结果中解析出Music
Music music = parseMusic(inputStream);
// 如果music不为null,设置标题和描述
if (null != music) {
music.setTitle(musicTitle);
// 如果作者不为"",将描述设置为作者
if (!"".equals(musicAuthor))
music.setDescription(musicAuthor);
else
music.setDescription("来自百度音乐");
}
return music;
}
/**
* UTF-8编码
*
* @param source
* @return
*/
private static String urlEncodeUTF8(String source) {
String result = source;
try {
result = java.net.URLEncoder.encode(source, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
/**
* 发送http请求取得返回的输入流
*
* @param requestUrl
* 请求地址
* @return InputStream
*/
private static InputStream httpRequest(String requestUrl) {
InputStream inputStream = null;
try {
URL url = new URL(requestUrl);
HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
httpUrlConn.setDoInput(true);
httpUrlConn.setRequestMethod("GET");
httpUrlConn.connect();
// 获得返回的输入流
inputStream = httpUrlConn.getInputStream();
} catch (Exception e) {
e.printStackTrace();
}
return inputStream;
}
/**
* 解析音乐参数
*
* @param inputStream
* 百度音乐搜索API返回的输入流
* @return Music
*/
@SuppressWarnings("unchecked")
private static Music parseMusic(InputStream inputStream) {
Music music = null;
try {
// 使用dom4j解析xml字符串
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// count表示搜索到的歌曲数
String count = root.element("count").getText();
// 当搜索到的歌曲数大于0时
if (!"0".equals(count)) {
// 普通品质
List<Element> urlList = root.elements("url");
// 高品质
List<Element> durlList = root.elements("durl");
// 普通品质的encode、decode
String urlEncode = urlList.get(0).element("encode").getText();
String urlDecode = urlList.get(0).element("decode").getText();
// 普通品质音乐的URL
String url = urlEncode.substring(0, urlEncode.lastIndexOf("/") + 1) + urlDecode;
if (-1 != urlDecode.lastIndexOf("&"))
url = urlEncode.substring(0, urlEncode.lastIndexOf("/") + 1)
+ urlDecode.substring(0, urlDecode.lastIndexOf("&"));
// 默认情况下,高音质音乐的URL 等于 普通品质音乐的URL
String durl = url;
// 判断高品质节点是否存在
Element durlElement = durlList.get(0).element("encode");
if (null != durlElement) {
// 高品质的encode、decode
String durlEncode = durlList.get(0).element("encode").getText();
String durlDecode = durlList.get(0).element("decode").getText();
// 高品质音乐的URL
durl = durlEncode.substring(0, durlEncode.lastIndexOf("/") + 1) + durlDecode;
if (-1 != durlDecode.lastIndexOf("&"))
durl = durlEncode.substring(0, durlEncode.lastIndexOf("/") + 1)
+ durlDecode.substring(0, durlDecode.lastIndexOf("&"));
}
music = new Music();
// 设置普通品质音乐链接
music.setMusicUrl(url);
// 设置高品质音乐链接
music.setHQMusicUrl(durl);
}
} catch (Exception e) {
e.printStackTrace();
}
return music;
}
// 测试方法
public static void main(String[] args) {
System.setProperty("http.proxySet", "true");
System.setProperty("http.proxyHost", "web-proxy.chn.hp.com");
System.setProperty("http.proxyPort", "8080");
Music music = searchMusic("相信自己", "零点乐队");
System.out.println("音乐名称:" + music.getTitle());
System.out.println("音乐描述:" + music.getDescription());
System.out.println("普通品质链接:" + music.getMusicUrl());
System.out.println("高品质链接:" + music.getHQMusicUrl());
}
}
核心服务类
更新代码后,实现查找百度音乐中的歌曲功能;接受“歌曲歌名”的输入,返回百度音乐中的歌曲;
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.Music;
import com.coderdream.model.MusicMessage;
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) {
LoggingDao loggingDao = new LoggingDao();
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.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").trim();
// 创建图文消息
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>();
if (content.startsWith("翻译")) {
String keyWord = content.replaceAll("^翻译", "").trim();
if ("".equals(keyWord)) {
textMessage.setContent(getTranslateUsage());
} else {
textMessage.setContent(BaiduTranslateService.translate(keyWord));
}
respContent = textMessage.getContent();
// 设置文本消息的内容
textMessage.setContent(respContent);
// 将文本消息对象转换成xml
respXml = MessageUtil.messageToXml(textMessage);
}
// 如果以“歌曲”2个字开头
else if (content.startsWith("歌曲")) {
// 将歌曲2个字及歌曲后面的+、空格、-等特殊符号去掉
String keyWord = content.replaceAll("^歌曲[\\+ ~!@#%^-_=]?", "");
// 如果歌曲名称为空
if ("".equals(keyWord)) {
logging = new Logging(f_timestamp.format(Calendar.getInstance().getTime()), "DEBUG", TAG,
"#歌曲名称为空#");
loggingDao.addLogging(logging);
respContent = getMusicUsage();
logging = new Logging(f_timestamp.format(Calendar.getInstance().getTime()), "DEBUG", TAG,
"#respContent# " + respContent);
loggingDao.addLogging(logging);
textMessage.setContent(respContent);
logging = new Logging(f_timestamp.format(Calendar.getInstance().getTime()), "DEBUG", TAG,
"#textMessage# " + textMessage);
loggingDao.addLogging(logging);
// 将图文消息对象转换成xml字符串
respXml = MessageUtil.messageToXml(textMessage);
logging = new Logging(f_timestamp.format(Calendar.getInstance().getTime()), "DEBUG", TAG,
"#respXml# " + respXml);
loggingDao.addLogging(logging);
} else {
String[] kwArr = keyWord.split("@");
// 歌曲名称
String musicTitle = kwArr[0];
// 演唱者默认为空
String musicAuthor = "";
if (2 == kwArr.length) {
musicAuthor = kwArr[1];
}
// 搜索音乐
Music music = BaiduMusicService.searchMusic(musicTitle, musicAuthor);
// 未搜索到音乐
if (null == music) {
respContent = "对不起,没有找到你想听的歌曲<" + musicTitle + ">。";
logging = new Logging(f_timestamp.format(Calendar.getInstance().getTime()), "DEBUG", TAG,
"#未搜索到音乐 respContent# " + respContent);
loggingDao.addLogging(logging);
} else {
// 音乐消息
logger.info("找到 " + musicTitle + " 了!!!");
MusicMessage musicMessage = new MusicMessage();
musicMessage.setToUserName(fromUserName);
musicMessage.setFromUserName(toUserName);
musicMessage.setCreateTime(new Date().getTime());
musicMessage.setMsgType(MessageUtil.MESSAGE_TYPE_MUSIC);
musicMessage.setMusic(music);
newsMessage.setFuncFlag(0);
respXml = MessageUtil.messageToXml(musicMessage);
logging = new Logging(f_timestamp.format(Calendar.getInstance().getTime()), "DEBUG", TAG,
"#return respXml# " + respXml);
loggingDao.addLogging(logging);
}
}
logging = new Logging(f_timestamp.format(Calendar.getInstance().getTime()), "DEBUG", TAG,
"#return respXml# " + respXml);
loggingDao.addLogging(logging);
return respXml;
}
// 如果以“历史”2个字开头
else 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.csdn.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.csdn.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.csdn.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.csdn.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.csdn.net/lyq8479");
Article article2 = new Article();
article2.setTitle("第4篇\n消息及消息处理工具的封装");
article2.setDescription("");
article2.setPicUrl("http://wxquan.sinaapp.com/meal.jpg");
article2.setUrl("http://blog.csdn.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.csdn.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.csdn.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.csdn.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.csdn.net/lyq8479/article/details/9157455?toUserName=" + fromUserName
+ "&toUserName=" + toUserName);
Article article3 = new Article();
article3.setTitle("如果觉得文章对你有所帮助,请通过博客留言或关注微信公众帐号xiaoqrobot来支持柳峰!");
article3.setDescription("");
// 将图片置为空
article3.setPicUrl("");
article3.setUrl("http://blog.csdn.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;
}
/**
* 翻译使用指南
*
* @return
*/
public static String getTranslateUsage() {
StringBuffer buffer = new StringBuffer();
// buffer.append(XiaoqUtil.emoji(0xe148)).append("Q译通使用指南").append("\n\n");
buffer.append("Q译通为用户提供专业的多语言翻译服务,目前支持以下翻译方向:").append("\n");
buffer.append(" 中 -> 英").append("\n");
buffer.append(" 英 -> 中").append("\n");
buffer.append(" 日 -> 中").append("\n\n");
buffer.append("使用示例:").append("\n");
buffer.append(" 翻译我是中国人").append("\n");
buffer.append(" 翻译dream").append("\n");
buffer.append(" 翻译さようなら").append("\n\n");
buffer.append("回复“?”显示主菜单");
return buffer.toString();
}
/**
* 歌曲点播使用指南
*
* @return
*/
public static String getMusicUsage() {
StringBuffer buffer = new StringBuffer();
buffer.append("歌曲点播操作指南").append("\n\n");
buffer.append("回复:歌曲+歌名").append("\n");
buffer.append("例如:歌曲存在").append("\n");
buffer.append("或者:歌曲存在@汪峰").append("\n\n");
buffer.append("回复“?”显示主菜单");
return buffer.toString();
}
}
消息基类
BaseMessage.java
package com.coderdream.model;
/**
* 请求消息基类(普通用户 -> 公众帐号)
*
*/
public class BaseMessage {
/**
* 开发者微信号
*/
private String ToUserName;
/**
* 发送方帐号(一个OpenID)
*/
private String FromUserName;
/**
* 消息创建时间 (整型)
*/
private long CreateTime;
/**
* 消息类型
*/
private String MsgType;
/**
* 消息ID,64位整型
*/
private long MsgId;
private long FuncFlag;
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 long getMsgId() {
return MsgId;
}
public void setMsgId(long msgId) {
MsgId = msgId;
}
public long getFuncFlag() {
return FuncFlag;
}
public void setFuncFlag(long funcFlag) {
FuncFlag = funcFlag;
}
}
消息处理工具类
MessageUtil.java
package com.coderdream.util;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.coderdream.model.Article;
import com.coderdream.model.MusicMessage;
import com.coderdream.model.NewsMessage;
import com.coderdream.model.TextMessage;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
/**
* 消息处理工具类
*
*/
public class MessageUtil {
public static String TAG = "MessageUtil";
private static Logger logger = Logger.getLogger(MessageUtil.class);
/**
* 请求消息类型:文本
*/
public static final String MESSAGE_TYPE_TEXT = "text";
/**
* 请求消息类型:图片
*/
public static final String MESSAGE_TYPE_IMAGE = "image";
/**
* 请求消息类型:语音
*/
public static final String MESSAGE_TYPE_VOICE = "voice";
/**
* 请求消息类型:视频
*/
public static final String MESSAGE_TYPE_VIDEO = "video";
/**
* 请求消息类型:地理位置
*/
public static final String MESSAGE_TYPE_LOCATION = "location";
/**
* 请求消息类型:链接
*/
public static final String MESSAGE_TYPE_LINK = "link";
/**
* 请求消息类型:事件推送
*/
public static final String MESSAGE_TYPE_EVENT = "event";
/**
* 事件类型:subscribe(订阅)
*/
public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
/**
* 事件类型:unsubscribe(取消订阅)
*/
public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
/**
* 事件类型:scan(用户已关注时的扫描带参数二维码)
*/
public static final String EVENT_TYPE_SCAN = "scan";
/**
* 事件类型:LOCATION(上报地理位置)
*/
public static final String EVENT_TYPE_LOCATION = "LOCATION";
/**
* 事件类型:CLICK(自定义菜单)
*/
public static final String EVENT_TYPE_CLICK = "CLICK";
/**
* 响应消息类型:图文
*/
public static final String MESSAGE_TYPE_NEWS = "news";
/**
* 响应消息类型:音乐
*/
public static final String MESSAGE_TYPE_MUSIC = "music";
/**
* 解析微信发来的请求(XML)
*
* @param request
* @return Map<String, String>
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static Map<String, String> parseXml(InputStream inputStream) throws Exception {
// 将解析结果存储在HashMap中
Map<String, String> map = new HashMap<String, String>();
logger.debug(TAG + " begin");
// 从request中取得输入流
// InputStream inputStream = request.getInputStream();
// 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
logger.debug(TAG + " read inputStream");
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List<Element> elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList) {
map.put(e.getName(), e.getText());
logger.debug(TAG + " ###### log4j debug" + e.getName() + " : " + e.getText());
}
// 释放资源
inputStream.close();
inputStream = null;
return map;
}
/**
* 扩展xstream使其支持CDATA
*/
private static XStream xstream = new XStream(new XppDriver() {
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// 对所有xml节点的转换都增加CDATA标记
boolean cdata = true;
@SuppressWarnings("rawtypes")
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
}
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
/**
* 文本消息对象转换成xml
*
* @param textMessage
* 文本消息对象
* @return xml
*/
public static String messageToXml(TextMessage textMessage) {
xstream.alias("xml", textMessage.getClass());
return xstream.toXML(textMessage);
}
/**
* 图文消息对象转换成xml
*
* @param newsMessage
* 图文消息对象
* @return xml
*/
public static String messageToXml(NewsMessage newsMessage) {
xstream.alias("xml", newsMessage.getClass());
xstream.alias("item", new Article().getClass());
return xstream.toXML(newsMessage);
}
/**
* 音乐消息对象转换成xml
*
* @param musicMessage
* 音乐消息对象
* @return xml
*/
public static String messageToXml(MusicMessage musicMessage) {
xstream.alias("xml", musicMessage.getClass());
String musicString = xstream.toXML(musicMessage);
return musicString;
}
}
上传本地代码到GitHub
将新增和修改过的代码上传到GitHub
上传工程WAR档至SAE
将eclipse中的工程导出为wxquan.war档,上传到SAE中,更新已有的版本。
微信客户端测试
登录微信网页版:https://wx.qq.com/
输入“歌曲小苹果”,返回百度音乐中的小苹果。
参考文档
完整源代码