实现查找百度音乐中的歌曲功能;
接受“歌曲歌名”的输入,返回百度音乐中的歌曲;
目录结构
- 项目结构图
- 增加和修改相关源代码
- 音乐类
- 音乐消息类
- 百度音乐服务类
- 消息基类
-
核心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/
输入“歌曲小苹果”,返回百度音乐中的小苹果。
参考文档
完整源代码
相关推荐
微信公众号平台发开书籍与实例文档 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
微信公众平台应用开发实战-完整扫描版 pdf 版本。 微信公众平台应用开发实战-完整扫描版 pdf 文档。 微信公众平台应用开发实战-完整扫描版.pdf 全书一共9章,在逻辑上分为四大部分:第一部分(第1章)介绍了微信公众...
微信开发实例 微信公众平台开发教程-深入浅出微信公众平台实战开发(微网站、LBS云、Api接口调用、服务号高级接口)1.微信接口前期准备。由北风网提供,微信开发实例微信公众平台基础篇: 1)微信公众平台简介:开发...
第二部分(第2、3章)介绍了进行微信公众平台开发所需的准备工作及将应用接入微信公众平台的方法;第三部分(第4、5章)详细介绍了微信公众平台已开放的API,通过实战项目对开发框架进行了系统讲解,读者甚至可以...
刘捷版微信公众平台企业应用开发实战 Sample源码以及相关SDK
本书是微信公众平台应用开发方面的书籍,作者是腾讯公司的软件开发工程师,而且是微信公众平台应用开发的先驱者之一。本书全面介绍了微信公众平台应用开发所需的各项技术,系统解读了微信公众平台开放的API和各项...
对微信公众平台开发有兴趣的同学 对ASP.NET MVC开发有兴趣的同学 有志进入开发行业的所有同学 课程特色: 最前沿ASP.NET MVC 5、Entity Framework 6、微信公众平台5.2 最全6大功能19个接口用法大揭秘 零基础快速...
《微信公众平台应用开发实战》是微信公众平台应用开发领域的经典著作,作者是腾讯公司的资深软件开发工程师,而且是微信公众平台应用开发的先驱者之一。本书全面介绍了微信公众平台应用开发所需的各项技术,系统解读...
《企业微信公众平台开发实战:再小的个体也有自己的品牌》方倍工作室,2015年,配套源码。
ASP.NET MVC 5 微信公众平台整合开发实战第三部
《微信公众平台开发实战》(php版),手打完美书签,方便导航入阅读
微信公众平台应用开发实战-完整扫描版 PDF扫描版,放心下载。
本书是微信公众平台应用开发领域的经典著作,作者是腾讯公司的资深软件开发工程师,而且是微信公众平台应用开发的先驱者之一。本书全面介绍了微信公众平台应用开发所需的各项技术,系统解读了微信公众平台开放的API...
PHP微信公众平台开发,内容丰富,涵盖了多个PHP微信公众平台开发的方面,适合于初学者来学习借鉴。
微信公众平台开发入门教程
第二部分(第2、3章)介绍了进行微信公众平台开发所需的准备工作及将应用接入微信公众平台的方法;第三部分(第4、5章)详细介绍了微信公众平台已开放的API,通过实战项目对开发框架进行了系统讲解,读者甚至可以...
微信小程序点餐系统微信小程序开发实战项目源码+后台+数据库(毕业设计)微信小程序点餐系统微信小程序开发实战项目源码+后台+数据库(毕业设计)微信小程序点餐系统微信小程序开发实战项目源码+后台+数据库(毕业...
对微信公众平台开发有兴趣的同学 对ASP.NET MVC开发有兴趣的同学 有志进入开发行业的所有同学 课程特色: 最前沿ASP.NET MVC 5、Entity Framework 6、微信公众平台5.2 最全6大功能19个接口用法大揭秘 零基础快速...