本文主要是介绍微信公众平台开发实战(08) 基于地理信息的服务(LBS),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
转自:http://coderdream.iteye.com/blog/2147716
微信公众平台开发实战(08) 基于地理信息的服务(LBS)
- 博客分类:
- 微信
- 移动开发
实现查找附近功能;
1)发送地理位置;
点击窗口底部的“+”按钮,选择“位置”,点“发送”
2)指定关键词搜索;
格式:附近+关键词\n例如:附近ATM、附近KTV、附近厕所
目录结构
- 项目结构图
- 增加和修改相关源代码
- 百度地点类
- 用户位置类
- 用户位置访问类
- 百度地图工具类
- 地图网页文件
-
核心Service
- 消息处理工具类
- Maven项目文件
- 上传本地代码到GitHub
- 上传工程WAR档至SAE
- 微信客户端测试
- 参考文档
- 完整项目源代码
项目结构图
源代码文件说明
序号 | 文件名 | 说明 | 操作 |
1 | BaiduPlace.java | 百度地点类 | 新增 |
2 | UserLocation.java | 用户位置类 | 新增 |
3 | UserLocationDao.java | 用户位置访问类 | 新增 |
4 | BaiduMapUtil.java | 百度地图工具类 | 新增 |
5 | route.jsp | 导航页面 | 新增 |
6 | CoreService.java | 核心服务类,新增处理各种输入,返回不同图文信息 | 更新 |
7 | MessageUtil.java | 新增生成图文信息的方法 | 更新 |
8 | pom.xml | 新增json和Base64等jar | 更新 |
增加和修改相关源代码
百度地点类
BaiduPlace.java
- package com.coderdream.model;
- /**
- * 地址信息
- *
- */
- public class BaiduPlace implements Comparable<BaiduPlace> {
- /**
- * 名称
- */
- private String name;
- /**
- * 详细地址
- */
- private String address;
- /**
- * 经度
- */
- private String lng;
- /**
- * 纬度
- */
- private String lat;
- /**
- * 联系电话
- */
- private String telephone;
- /**
- * 距离
- */
- private int distance;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getAddress() {
- return address;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- public String getLng() {
- return lng;
- }
- public void setLng(String lng) {
- this.lng = lng;
- }
- public String getLat() {
- return lat;
- }
- public void setLat(String lat) {
- this.lat = lat;
- }
- public String getTelephone() {
- return telephone;
- }
- public void setTelephone(String telephone) {
- this.telephone = telephone;
- }
- public int getDistance() {
- return distance;
- }
- public void setDistance(int distance) {
- this.distance = distance;
- }
- public int compareTo(BaiduPlace baiduPlace) {
- return this.distance - baiduPlace.getDistance();
- }
- }
用户位置类
UserLocation.java
- package com.coderdream.model;
- /**
- * 用户地理位置
- */
- public class UserLocation {
- private String openId;
- /**
- * 经度
- */
- private String lng;
- /**
- * 纬度
- */
- private String lat;
- /**
- * 百度地图经度
- */
- private String bd09Lng;
- /**
- * 百度地图纬度
- */
- private String bd09Lat;
- public String getOpenId() {
- return openId;
- }
- public void setOpenId(String openId) {
- this.openId = openId;
- }
- public String getLng() {
- return lng;
- }
- public void setLng(String lng) {
- this.lng = lng;
- }
- public String getLat() {
- return lat;
- }
- public void setLat(String lat) {
- this.lat = lat;
- }
- public String getBd09Lng() {
- return bd09Lng;
- }
- public void setBd09Lng(String bd09Lng) {
- this.bd09Lng = bd09Lng;
- }
- public String getBd09Lat() {
- return bd09Lat;
- }
- public void setBd09Lat(String bd09Lat) {
- this.bd09Lat = bd09Lat;
- }
- }
用户位置访问类
UserLocationDao.java
- package com.coderdream.dao;
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import com.coderdream.model.UserLocation;
- import com.coderdream.util.DBUtil;
- /**
- *
- */
- public class UserLocationDao {
- /**
- * 保存用户地理位置
- *
- * @param request
- * 请求对象
- * @param openId
- * 用户的OpenID
- * @param lng
- * 用户发送的经度
- * @param lat
- * 用户发送的纬度
- * @param bd09_lng
- * 经过百度坐标转换后的经度
- * @param bd09_lat
- * 经过百度坐标转换后的纬度
- */
- public int saveUserLocation(String openId, String lng, String lat, String bd09_lng, String bd09_lat) {
- String sql = "insert into user_location(open_id, lng, lat, bd09_lng, bd09_lat) values (?, ?, ?, ?, ?)";
- int count = 0;
- Connection con = null;
- PreparedStatement ps = null;
- try {
- con = DBUtil.getConnection();
- ps = con.prepareStatement(sql);
- ps.setString(1, openId);
- ps.setString(2, lng);
- ps.setString(3, lat);
- ps.setString(4, bd09_lng);
- ps.setString(5, bd09_lat);
- count = ps.executeUpdate();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- // 释放资源
- DBUtil.close(ps);
- DBUtil.close(con);
- }
- return count;
- }
- /**
- * 获取用户最后一次发送的地理位置
- *
- * @param request
- * 请求对象
- * @param openId
- * 用户的OpenID
- * @return UserLocation
- */
- public UserLocation getLastLocation(String openId) {
- UserLocation userLocation = null;
- String sql = "select open_id, lng, lat, bd09_lng, bd09_lat from user_location where open_id=? order by id desc limit 0,1";
- Connection con = null;
- PreparedStatement pre = null;
- ResultSet rs = null;
- try {
- con = DBUtil.getConnection();
- pre = con.prepareStatement(sql);
- pre.setString(1, openId);
- rs = pre.executeQuery();
- if (rs.next()) {
- userLocation = new UserLocation();
- userLocation.setOpenId(rs.getString("open_id"));
- userLocation.setLng(rs.getString("lng"));
- userLocation.setLat(rs.getString("lat"));
- userLocation.setBd09Lng(rs.getString("bd09_lng"));
- userLocation.setBd09Lat(rs.getString("bd09_lat"));
- }
- // 释放资源
- rs.close();
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- DBUtil.close(rs);
- DBUtil.close(pre);
- DBUtil.close(con);
- }
- return userLocation;
- }
- }
百度地图工具类
BaiduMapUtil.java
- package com.coderdream.util;
- import it.sauronsoftware.base64.Base64;
- import java.io.BufferedReader;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.UnsupportedEncodingException;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import java.net.URLEncoder;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
- import net.sf.json.JSONObject;
- import org.dom4j.Document;
- import org.dom4j.DocumentHelper;
- import org.dom4j.Element;
- import com.coderdream.model.Article;
- import com.coderdream.model.BaiduPlace;
- import com.coderdream.model.UserLocation;
- /**
- * 百度地图操作类 javabase64-1.3.1.jar
- *
- */
- public class BaiduMapUtil {
- /**
- * 圆形区域检索
- *
- * @param query
- * 检索关键词
- * @param lng
- * 经度
- * @param lat
- * 纬度
- * @return List<BaiduPlace>
- * @throws UnsupportedEncodingException
- */
- public static List<BaiduPlace> searchPlace(String query, String lng, String lat) throws Exception {
- // 拼装请求地址
- String requestUrl = "http://api.map.baidu.com/place/v2/search?&query=QUERY&location=LAT,LNG&radius=2000&output=xml&scope=2&page_size=10&page_num=0&ak=CA21bdecc75efc1664af5a195c30bb4e";
- requestUrl = requestUrl.replace("QUERY", URLEncoder.encode(query, "UTF-8"));
- requestUrl = requestUrl.replace("LAT", lat);
- requestUrl = requestUrl.replace("LNG", lng);
- // 调用Place API圆形区域检索
- String respXml = httpRequest(requestUrl);
- // 解析返回的xml
- List<BaiduPlace> placeList = parsePlaceXml(respXml);
- return placeList;
- }
- /**
- * 发送http请求
- *
- * @param requestUrl
- * 请求地址
- * @return String
- */
- public static String httpRequest(String requestUrl) {
- StringBuffer buffer = new StringBuffer();
- try {
- URL url = new URL(requestUrl);
- HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
- httpUrlConn.setDoInput(true);
- httpUrlConn.setRequestMethod("GET");
- httpUrlConn.connect();
- // 将返回的输入流转换成字符串
- InputStream inputStream = httpUrlConn.getInputStream();
- InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
- BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
- String str = null;
- while ((str = bufferedReader.readLine()) != null) {
- buffer.append(str);
- }
- bufferedReader.close();
- inputStreamReader.close();
- // 释放资源
- inputStream.close();
- inputStream = null;
- httpUrlConn.disconnect();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return buffer.toString();
- }
- /**
- * 根据百度地图返回的流解析出地址信息
- *
- * @param inputStream
- * 输入流
- * @return List<BaiduPlace>
- */
- @SuppressWarnings("unchecked")
- private static List<BaiduPlace> parsePlaceXml(String xml) {
- List<BaiduPlace> placeList = null;
- try {
- Document document = DocumentHelper.parseText(xml);
- // 得到xml根元素
- Element root = document.getRootElement();
- // 从根元素获取<results>
- Element resultsElement = root.element("results");
- // 从<results>中获取<result>集合
- List<Element> resultElementList = resultsElement.elements("result");
- // 判断<result>集合的大小
- if (resultElementList.size() > 0) {
- placeList = new ArrayList<BaiduPlace>();
- // POI名称
- Element nameElement = null;
- // POI地址信息
- Element addressElement = null;
- // POI经纬度坐标
- Element locationElement = null;
- // POI电话信息
- Element telephoneElement = null;
- // POI扩展信息
- Element detailInfoElement = null;
- // 距离中心点的距离
- Element distanceElement = null;
- // 遍历<result>集合
- for (Element resultElement : resultElementList) {
- nameElement = resultElement.element("name");
- addressElement = resultElement.element("address");
- locationElement = resultElement.element("location");
- telephoneElement = resultElement.element("telephone");
- detailInfoElement = resultElement.element("detail_info");
- BaiduPlace place = new BaiduPlace();
- place.setName(nameElement.getText());
- place.setAddress(addressElement.getText());
- place.setLng(locationElement.element("lng").getText());
- place.setLat(locationElement.element("lat").getText());
- // 当<telephone>元素存在时获取电话号码
- if (null != telephoneElement)
- place.setTelephone(telephoneElement.getText());
- // 当<detail_info>元素存在时获取<distance>
- if (null != detailInfoElement) {
- distanceElement = detailInfoElement.element("distance");
- if (null != distanceElement)
- place.setDistance(Integer.parseInt(distanceElement.getText()));
- }
- placeList.add(place);
- }
- // 按距离由近及远排序
- Collections.sort(placeList);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return placeList;
- }
- /**
- * 根据Place组装图文列表
- *
- * @param placeList
- * @param bd09Lng
- * 经度
- * @param bd09Lat
- * 纬度
- * @return List<Article>
- */
- public static List<Article> makeArticleList(List<BaiduPlace> placeList, String bd09Lng, String bd09Lat) {
- // 项目的根路径
- String basePath = "http://1.wxquan.sinaapp.com/";
- List<Article> list = new ArrayList<Article>();
- BaiduPlace place = null;
- for (int i = 0; i < placeList.size(); i++) {
- place = placeList.get(i);
- Article article = new Article();
- article.setTitle(place.getName() + "\n距离约" + place.getDistance() + "米");
- // P1表示用户发送的位置(坐标转换后),p2表示当前POI所在位置
- article.setUrl(String.format(basePath + "route.jsp?p1=%s,%s&p2=%s,%s", bd09Lng, bd09Lat, place.getLng(),
- place.getLat()));
- // 将首条图文的图片设置为大图
- if (i == 0)
- article.setPicUrl(basePath + "images/poisearch.png");
- else
- article.setPicUrl(basePath + "images/navi.png");
- list.add(article);
- }
- return list;
- }
- /**
- * 将微信定位的坐标转换成百度坐标(GCJ-02 -> Baidu)
- *
- * @param lng
- * 经度
- * @param lat
- * 纬度
- * @return UserLocation
- */
- public static UserLocation convertCoord(String lng, String lat) {
- // 百度坐标转换接口
- String convertUrl = "http://api.map.baidu.com/ag/coord/convert?from=2&to=4&x={x}&y={y}";
- convertUrl = convertUrl.replace("{x}", lng);
- convertUrl = convertUrl.replace("{y}", lat);
- UserLocation location = new UserLocation();
- try {
- String jsonCoord = httpRequest(convertUrl);
- JSONObject jsonObject = JSONObject.fromObject(jsonCoord);
- // 对转换后的坐标进行Base64解码
- location.setBd09Lng(Base64.decode(jsonObject.getString("x"), "UTF-8"));
- location.setBd09Lat(Base64.decode(jsonObject.getString("y"), "UTF-8"));
- } catch (Exception e) {
- location = null;
- e.printStackTrace();
- }
- return location;
- }
- }
导航页面
route.jsp
- <%@ page language="java" pageEncoding="UTF-8"%>
- <%
- String path = request.getContextPath();
- String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
- %>
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <base href="<%=basePath%>">
- <title>步行导航</title>
- <meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=0;">
- <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
- <style type="text/css">
- body, html,#allmap {width: 100%;height: 100%;overflow: hidden;margin:0;}
- </style>
- <script type="text/javascript" src="http://api.map.baidu.com/api?v=1.5&ak=CA21bdecc75efc1664af5a195c30bb4e"></script>
- </head>
- <%
- String p1 = request.getParameter("p1");
- String p2 = request.getParameter("p2");
- %>
- <body>
- <div id="allmap"></div>
- </body>
- <script type="text/javascript">
- // 创建起点、终点的经纬度坐标点
- var p1 = new BMap.Point(<%=p1%>);
- var p2 = new BMap.Point(<%=p2%>);
- // 创建地图、设置中心坐标和默认缩放级别
- var map = new BMap.Map("allmap");
- map.centerAndZoom(new BMap.Point((p1.lng+p2.lng)/2, (p1.lat+p2.lat)/2), 17);
- // 右下角添加缩放按钮
- map.addControl(new BMap.NavigationControl({anchor: BMAP_ANCHOR_BOTTOM_RIGHT, type: BMAP_NAVIGATION_CONTROL_ZOOM}));
- // 步行导航检索
- var walking = new BMap.WalkingRoute(map, {renderOptions:{map: map, autoViewport: true}});
- walking.search(p1, p2);
- </script>
- </html>
核心服务类
更新代码后,能实现查找附近功能;
1)发送地理位置;
点击窗口底部的“+”按钮,选择“位置”,点“发送”
2)指定关键词搜索;
格式:附近+关键词\n例如:附近ATM、附近KTV、附近厕所。
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.dao.UserLocationDao;
- import com.coderdream.model.Article;
- import com.coderdream.model.BaiduPlace;
- import com.coderdream.model.Music;
- import com.coderdream.model.MusicMessage;
- import com.coderdream.model.NewsMessage;
- import com.coderdream.model.TextMessage;
- import com.coderdream.model.UserLocation;
- import com.coderdream.util.BaiduMapUtil;
- import com.coderdream.util.MessageUtil;
- /**
- * 核心服务类
- */
- public class CoreService {
- public static String TAG = "CoreService";
- private Logger logger = Logger.getLogger(CoreService.class);
- private LoggingDao loggingDao = new LoggingDao(this.getClass().getName());
- private UserLocationDao userLocationDao = new UserLocationDao();
- /**
- * 处理微信发来的请求
- *
- * @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.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();
- }
- // 如果以“歌曲”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();
- } 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);
- 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);
- }
- // 周边搜索
- else if (content.startsWith("附近")) {
- String keyWord = content.replaceAll("附近", "").trim();
- // 获取用户最后一次发送的地理位置
- UserLocation location = userLocationDao.getLastLocation(fromUserName);
- // 未获取到
- if (null == location) {
- respContent = getLocationUsage();
- } else {
- // 根据转换后(纠偏)的坐标搜索周边POI
- List<BaiduPlace> placeList = BaiduMapUtil.searchPlace(keyWord, location.getBd09Lng(),
- location.getBd09Lat());
- // 未搜索到POI
- if (null == placeList || 0 == placeList.size()) {
- respContent = String.format("/难过,您发送的位置附近未搜索到“%s”信息!", keyWord);
- } else {
- articleList = BaiduMapUtil.makeArticleList(placeList, location.getBd09Lng(),
- location.getBd09Lat());
- // 回复图文消息
- newsMessage = new NewsMessage();
- newsMessage.setToUserName(fromUserName);
- newsMessage.setFromUserName(toUserName);
- newsMessage.setCreateTime(new Date().getTime());
- newsMessage.setMsgType(MessageUtil.MESSAGE_TYPE_NEWS);
- newsMessage.setArticles(articleList);
- newsMessage.setArticleCount(articleList.size());
- return MessageUtil.messageToXml(newsMessage);
- }
- }
- }
- // 单图文消息
- 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);
- return MessageUtil.messageToXml(newsMessage);
- }
- // 其他,弹出帮助信息
- else {
- respContent = getUsage();
- }
- }
- // 图片消息
- 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 = "您发送的是地理位置消息!";
- // 用户发送的经纬度
- String lng = requestMap.get("Location_Y");
- String lat = requestMap.get("Location_X");
- // 坐标转换后的经纬度
- String bd09Lng = null;
- String bd09Lat = null;
- // 调用接口转换坐标
- UserLocation userLocation = BaiduMapUtil.convertCoord(lng, lat);
- if (null != userLocation) {
- bd09Lng = userLocation.getBd09Lng();
- bd09Lat = userLocation.getBd09Lat();
- }
- logger.info("lng= " + lng + "; lat= " + lat);
- logger.info("bd09Lng= " + bd09Lng + "; bd09Lat= " + bd09Lat);
- // 保存用户地理位置
- int count = userLocationDao.saveUserLocation(fromUserName, lng, lat, bd09Lng, bd09Lat);
- loggingDao.debug("fromUserName" + fromUserName + "lng= " + lng + "; lat= " + lat + "bd09Lng= "
- + bd09Lng + "; bd09Lat= " + bd09Lat + "count" + count);
- StringBuffer buffer = new StringBuffer();
- buffer.append("[愉快]").append("成功接收您的位置!").append("\n\n");
- buffer.append("您可以输入搜索关键词获取周边信息了,例如:").append("\n");
- buffer.append(" 附近ATM").append("\n");
- buffer.append(" 附近KTV").append("\n");
- buffer.append(" 附近厕所").append("\n");
- buffer.append("必须以“附近”两个字开头!");
- respContent = buffer.toString();
- }
- // 链接消息
- 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 = "谢谢您的关注!/n";
- respContent += getSubscribeMsg();
- }
- // 取消关注
- 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();
- }
- /**
- * 歌曲点播使用指南
- *
- * @return
- */
- public static String getUsage() {
- StringBuffer buffer = new StringBuffer();
- buffer.append("历史年月(历史0403)").append("\n");
- buffer.append("歌曲歌名(歌曲)").append("\n");
- buffer.append("翻译词语(翻译明天)-支持中英日语").append("\n");
- buffer.append("回复“?”显示主菜单");
- return buffer.toString();
- }
- /**
- * 关注提示语
- *
- * @return
- */
- public static String getSubscribeMsg() {
- StringBuffer buffer = new StringBuffer();
- buffer.append("您是否有过出门在外四处找ATM或厕所的经历?").append("\n\n");
- buffer.append("您是否有过出差在外搜寻美食或娱乐场所的经历?").append("\n\n");
- buffer.append("周边搜索为您的出行保驾护航,为您提供专业的周边生活指南,回复“附近”开始体验吧!");
- return buffer.toString();
- }
- /**
- * 使用说明
- *
- * @return
- */
- public static String getLocationUsage() {
- StringBuffer buffer = new StringBuffer();
- buffer.append("周边搜索使用说明").append("\n\n");
- buffer.append("1)发送地理位置").append("\n");
- buffer.append("点击窗口底部的“+”按钮,选择“位置”,点“发送”").append("\n\n");
- buffer.append("2)指定关键词搜索").append("\n");
- buffer.append("格式:附近+关键词\n例如:附近ATM、附近KTV、附近厕所");
- return buffer.toString();
- }
- }
消息处理工具类
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;
- }
- }
Maven工程配置文件
pom.xml
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.coderdream</groupId>
- <artifactId>wxquan</artifactId>
- <packaging>war</packaging>
- <version>0.0.1-SNAPSHOT</version>
- <name>wxquan Maven Webapp</name>
- <url>http://maven.apache.org</url>
- <properties>
- <junit.version>4.11</junit.version>
- <servlet.api.version>2.5</servlet.api.version>
- <jsp.api.version>2.1</jsp.api.version>
- <slf4j.version>1.7.5</slf4j.version>
- <dom4j.version>1.6.1</dom4j.version>
- <xstream.version>1.4.7</xstream.version>
- <mysql.version>5.1.17</mysql.version>
- <dbunit.version>2.4.9</dbunit.version>
- <gson.version>2.2.4</gson.version>
- <json.version>2.4</json.version>
- <javabase.version>1.3.1</javabase.version>
- </properties>
- <dependencies>
- <!-- 测试的时候用到,打包的时候没有 -->
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>${junit.version}</version>
- <scope>test</scope>
- </dependency>
- <!-- 编译的时候用到,打包的时候没有 -->
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>${servlet.api.version}</version>
- <scope>provided</scope>
- </dependency>
- <!-- 编译的时候用到,打包的时候没有 -->
- <dependency>
- <groupId>javax.servlet.jsp</groupId>
- <artifactId>jsp-api</artifactId>
- <version>${jsp.api.version}</version>
- <scope>provided</scope>
- </dependency>
- <!-- 日志包 -->
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>${slf4j.version}</version>
- </dependency>
- <!-- 打包的时候剔除 xml-apis-1.0.b2.jar SAE中不支持 -->
- <dependency>
- <groupId>dom4j</groupId>
- <artifactId>dom4j</artifactId>
- <version>${dom4j.version}</version>
- <exclusions>
- <exclusion>
- <groupId>xml-apis</groupId>
- <artifactId>xml-apis</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <!-- 打包的时候剔除 xml-apis-1.0.b2.jar SAE中不支持 -->
- <!-- 这个jar必须用1.4.7的高版本,否则SAE不支持 -->
- <!-- 详细原因:http://blog.csdn.net/lyq8479/article/details/38878543 -->
- <dependency>
- <groupId>com.thoughtworks.xstream</groupId>
- <artifactId>xstream</artifactId>
- <version>${xstream.version}</version>
- </dependency>
- <!-- 编译的时候用到,打包的时候没有,SAE已包含此jar -->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>${mysql.version}</version>
- <scope>provided</scope>
- </dependency>
- <!-- 测试的时候用到,打包的后WAR里没有 -->
- <dependency>
- <groupId>org.dbunit</groupId>
- <artifactId>dbunit</artifactId>
- <version>${dbunit.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.google.code.gson</groupId>
- <artifactId>gson</artifactId>
- <version>${gson.version}</version>
- </dependency>
- <dependency>
- <groupId>net.sf.json-lib</groupId>
- <artifactId>json-lib</artifactId>
- <version>${json.version}</version>
- </dependency>
- <dependency>
- <groupId>it.sauronsoftware</groupId>
- <artifactId>javabase64</artifactId>
- <version>${javabase.version}</version>
- </dependency>
- </dependencies>
- <build>
- <finalName>wxquan</finalName>
- </build>
- </project>
上传本地代码到GitHub
将新增和修改过的代码上传到GitHub
上传工程WAR档至SAE
将eclipse中的工程导出为wxquan.war档,上传到SAE中,更新已有的版本。
微信客户端测试
登录微信网页版:https://wx.qq.com/
先提交位置信息,然后输入“附近咖啡厅”,返回附近咖啡厅的图文信息。
参考文档
完整源代码
这篇关于微信公众平台开发实战(08) 基于地理信息的服务(LBS)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!