本次讲解微信开发第三篇:获取用户地址位置信息,是非常常用的功能,特别是服务行业公众号,尤为需要该功能,本次讲解的就是如何调用微信JS-SDK接口,获取用户位置信息,并结合百度地铁,实现在线地图搜索,与在线导航。

官方文档地址:https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html

在这粘贴上二篇博文链接,方便大家访问:

微信公众号开发《一》OAuth2.0网页授权认证获取用户的详细信息,实现自动登陆

微信公众号开发《二》发送模板消息实现消息业务实时通知

1.何为JS-SDK:微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。简单来说:就是在自己公众平台后台配置后,可直接调用的功能接口。

那如何配置呢?下面讲解下配置步骤:示例讲解是基于测试公众号,如何使用测试公众号,可以参考第一篇文章

1.在公众号后台绑定域名:测试公众号登录就可看见如下图。正式公众号配置位置:“公众号设置”的“功能设置”里填写“JS接口安全域名”

2.页面中引入接口JS文件,下载地址:http://res.wx.qq.com/open/js/jweixin-1.2.0.js

注意:JS最新版本为1.2.0,为了适配IOS开发,最好使用最新版本号JS,1.1.0版本可能会造成有些功能调用失败,有兴趣的可以看看官方文档:https://mp.weixin.qq.com/advanced/wiki?t=t=resource/res_main&id=mp1483682025_enmey

3.获取必须参数:

  1. wx.config({
  2. debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
  3. appId: '', // 必填,公众号的唯一标识
  4. timestamp: , // 必填,生成签名的时间戳
  5. nonceStr: '', // 必填,生成签名的随机串
  6. signature: '',// 必填,签名
  7. jsApiList: [
  8. 'openLocation',
  9. 'getLocation'
  10. ] // 必填,需要使用的JS接口列表,更多接口可看官方文档
  11. });

看调用接口,可知,现在缺timestamp,signature,nonceStr。不用想的太复杂,还是那个原则,没什么获取什么,

获取signature签名,生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket。

写个工具类封装获取方法

  1. public class SHA1 { //sha算法
  2. private final int[] abcde = {
  3. 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
  4. };
  5. // 摘要数据存储数组
  6. private int[] digestInt = new int[5];
  7. // 计算过程中的临时数据存储数组
  8. private int[] tmpData = new int[80];
  9. // 计算sha-1摘要
  10. private int process_input_bytes(byte[] bytedata) {
  11. // 初试化常量
  12. System.arraycopy(abcde, 0, digestInt, 0, abcde.length);
  13. // 格式化输入字节数组,补10及长度数据
  14. byte[] newbyte = byteArrayFormatData(bytedata);
  15. // 获取数据摘要计算的数据单元个数
  16. int MCount = newbyte.length / 64;
  17. // 循环对每个数据单元进行摘要计算
  18. for (int pos = 0; pos < MCount; pos++) {
  19. // 将每个单元的数据转换成16个整型数据,并保存到tmpData的前16个数组元素中
  20. for (int j = 0; j < 16; j++) {
  21. tmpData[j] = byteArrayToInt(newbyte, (pos * 64) + (j * 4));
  22. }
  23. // 摘要计算函数
  24. encrypt();
  25. }
  26. return 20;
  27. }
  28. // 格式化输入字节数组格式
  29. private byte[] byteArrayFormatData(byte[] bytedata) {
  30. // 补0数量
  31. int zeros = 0;
  32. // 补位后总位数
  33. int size = 0;
  34. // 原始数据长度
  35. int n = bytedata.length;
  36. // 模64后的剩余位数
  37. int m = n % 64;
  38. // 计算添加0的个数以及添加10后的总长度
  39. if (m < 56) {
  40. zeros = 55 - m;
  41. size = n - m + 64;
  42. } else if (m == 56) {
  43. zeros = 63;
  44. size = n + 8 + 64;
  45. } else {
  46. zeros = 63 - m + 56;
  47. size = (n + 64) - m + 64;
  48. }
  49. // 补位后生成的新数组内容
  50. byte[] newbyte = new byte[size];
  51. // 复制数组的前面部分
  52. System.arraycopy(bytedata, 0, newbyte, 0, n);
  53. // 获得数组Append数据元素的位置
  54. int l = n;
  55. // 补1操作
  56. newbyte[l++] = (byte) 0x80;
  57. // 补0操作
  58. for (int i = 0; i < zeros; i++) {
  59. newbyte[l++] = (byte) 0x00;
  60. }
  61. // 计算数据长度,补数据长度位共8字节,长整型
  62. long N = (long) n * 8;
  63. byte h8 = (byte) (N & 0xFF);
  64. byte h7 = (byte) ((N >> 8) & 0xFF);
  65. byte h6 = (byte) ((N >> 16) & 0xFF);
  66. byte h5 = (byte) ((N >> 24) & 0xFF);
  67. byte h4 = (byte) ((N >> 32) & 0xFF);
  68. byte h3 = (byte) ((N >> 40) & 0xFF);
  69. byte h2 = (byte) ((N >> 48) & 0xFF);
  70. byte h1 = (byte) (N >> 56);
  71. newbyte[l++] = h1;
  72. newbyte[l++] = h2;
  73. newbyte[l++] = h3;
  74. newbyte[l++] = h4;
  75. newbyte[l++] = h5;
  76. newbyte[l++] = h6;
  77. newbyte[l++] = h7;
  78. newbyte[l++] = h8;
  79. return newbyte;
  80. }
  81. private int f1(int x, int y, int z) {
  82. return (x & y) | (~x & z);
  83. }
  84. private int f2(int x, int y, int z) {
  85. return x ^ y ^ z;
  86. }
  87. private int f3(int x, int y, int z) {
  88. return (x & y) | (x & z) | (y & z);
  89. }
  90. private int f4(int x, int y) {
  91. return (x << y) | x >>> (32 - y);
  92. }
  93. // 单元摘要计算函数
  94. private void encrypt() {
  95. for (int i = 16; i <= 79; i++) {
  96. tmpData[i] = f4(tmpData[i - 3] ^ tmpData[i - 8] ^ tmpData[i - 14] ^
  97. tmpData[i - 16], 1);
  98. }
  99. int[] tmpabcde = new int[5];
  100. for (int i1 = 0; i1 < tmpabcde.length; i1++) {
  101. tmpabcde[i1] = digestInt[i1];
  102. }
  103. for (int j = 0; j <= 19; j++) {
  104. int tmp = f4(tmpabcde[0], 5) +
  105. f1(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] +
  106. tmpData[j] + 0x5a827999;
  107. tmpabcde[4] = tmpabcde[3];
  108. tmpabcde[3] = tmpabcde[2];
  109. tmpabcde[2] = f4(tmpabcde[1], 30);
  110. tmpabcde[1] = tmpabcde[0];
  111. tmpabcde[0] = tmp;
  112. }
  113. for (int k = 20; k <= 39; k++) {
  114. int tmp = f4(tmpabcde[0], 5) +
  115. f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] +
  116. tmpData[k] + 0x6ed9eba1;
  117. tmpabcde[4] = tmpabcde[3];
  118. tmpabcde[3] = tmpabcde[2];
  119. tmpabcde[2] = f4(tmpabcde[1], 30);
  120. tmpabcde[1] = tmpabcde[0];
  121. tmpabcde[0] = tmp;
  122. }
  123. for (int l = 40; l <= 59; l++) {
  124. int tmp = f4(tmpabcde[0], 5) +
  125. f3(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] +
  126. tmpData[l] + 0x8f1bbcdc;
  127. tmpabcde[4] = tmpabcde[3];
  128. tmpabcde[3] = tmpabcde[2];
  129. tmpabcde[2] = f4(tmpabcde[1], 30);
  130. tmpabcde[1] = tmpabcde[0];
  131. tmpabcde[0] = tmp;
  132. }
  133. for (int m = 60; m <= 79; m++) {
  134. int tmp = f4(tmpabcde[0], 5) +
  135. f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] +
  136. tmpData[m] + 0xca62c1d6;
  137. tmpabcde[4] = tmpabcde[3];
  138. tmpabcde[3] = tmpabcde[2];
  139. tmpabcde[2] = f4(tmpabcde[1], 30);
  140. tmpabcde[1] = tmpabcde[0];
  141. tmpabcde[0] = tmp;
  142. }
  143. for (int i2 = 0; i2 < tmpabcde.length; i2++) {
  144. digestInt[i2] = digestInt[i2] + tmpabcde[i2];
  145. }
  146. for (int n = 0; n < tmpData.length; n++) {
  147. tmpData[n] = 0;
  148. }
  149. }
  150. // 4字节数组转换为整数
  151. private int byteArrayToInt(byte[] bytedata, int i) {
  152. return ((bytedata[i] & 0xff) << 24) | ((bytedata[i + 1] & 0xff) << 16) |
  153. ((bytedata[i + 2] & 0xff) << 8) | (bytedata[i + 3] & 0xff);
  154. }
  155. // 整数转换为4字节数组
  156. private void intToByteArray(int intValue, byte[] byteData, int i) {
  157. byteData[i] = (byte) (intValue >>> 24);
  158. byteData[i + 1] = (byte) (intValue >>> 16);
  159. byteData[i + 2] = (byte) (intValue >>> 8);
  160. byteData[i + 3] = (byte) intValue;
  161. }
  162. // 将字节转换为十六进制字符串
  163. private static String byteToHexString(byte ib) {
  164. char[] Digit = {
  165. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
  166. 'D', 'E', 'F'
  167. };
  168. char[] ob = new char[2];
  169. ob[0] = Digit[(ib >>> 4) & 0X0F];
  170. ob[1] = Digit[ib & 0X0F];
  171. String s = new String(ob);
  172. return s;
  173. }
  174. // 将字节数组转换为十六进制字符串
  175. private static String byteArrayToHexString(byte[] bytearray) {
  176. String strDigest = "";
  177. for (int i = 0; i < bytearray.length; i++) {
  178. strDigest += byteToHexString(bytearray[i]);
  179. }
  180. return strDigest;
  181. }
  182. // 计算sha-1摘要,返回相应的字节数组
  183. public byte[] getDigestOfBytes(byte[] byteData) {
  184. process_input_bytes(byteData);
  185. byte[] digest = new byte[20];
  186. for (int i = 0; i < digestInt.length; i++) {
  187. intToByteArray(digestInt[i], digest, i * 4);
  188. }
  189. return digest;
  190. }
  191. // 计算sha-1摘要,返回相应的十六进制字符串
  192. public String getDigestOfString(byte[] byteData) {
  193. return byteArrayToHexString(getDigestOfBytes(byteData));
  194. }
  195. public static void main(String[] args) {
  196. String data = "123456";
  197. System.out.println(data);
  198. String digest = new SHA1().getDigestOfString(data.getBytes());
  199. System.out.println(digest);
  200.  
  201. // System.out.println( ToMD5.convertSHA1(data).toUpperCase());
  202. }
  203. }
  1. /**
  2. * Ticket封装类
  3. * @author lh
  4. */
  5. public class Ticket {
  6. private String errcode;
  7. private String errmsg;
  8. private String ticket;
  9. private String expires_in;
  10. //省略get,set方法
  11. }
  12. /**
  13. * Signature封装类
  14. * @author lh
  15. */
  16. public class SignatureInfo {
  17. private String signature;
  18. private String timestamp;
  19. private String noncestr;
  20. private String url;
  21. //省略get,set方法
  22. } 

获取ticket

  1. /**
  2. * 获取ticket
  3. * @param accessToken
  4. * @return
  5. */
  6. public static Ticket getTicket(String accessToken){
  7. Ticket ticket = new Ticket();
  8. String getTicket = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
  9. String url = getTicket.replace("ACCESS_TOKEN",accessToken);
  10. JSONObject jsonObject = httpRequest(url, "POST", null);
  11. if (null != jsonObject) {
  12. if (0 != jsonObject.getInt("errcode")) {
  13. log.error("获取ticket失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
  14. }else{
  15. ticket.setErrcode(jsonObject.getString("errcode"));
  16. ticket.setErrmsg(jsonObject.getString("errmsg"));
  17. ticket.setExpires_in(jsonObject.getString("expires_in"));
  18. ticket.setTicket(jsonObject.getString("ticket"));
  19. }
  20. }
  21. return ticket;
  22. }

获取Signature方法

  1. /**
  2. * 签名算法
  3. * @param ticket
  4. * @return
  5. */
  6. public static SignatureInfo getSignature(SignatureInfo sign,Ticket ticket){
  7. String data = "jsapi_ticket="+ticket.getTicket()+"&noncestr="+sign.getNoncestr()+"×tamp="+sign.getTimestamp()+"&url="+sign.getUrl();
  8. String signature = new SHA1().getDigestOfString(data.getBytes());
  9. sign.setSignature(signature);
  10. log.info("signature="+sign.getSignature());
  11. return sign;
  12. }

最后综合上面方法,封装主函数

  1. public String jssdk_demo(HttpServletRequest request,HttpServletResponse response){
  2. String param = request.getQueryString();//获取请求参数
  3. String url = request.getServletPath();//获取请求路径(不带参数)
  4. if(param!=null){
  5. url = url+"?"+param;//组合成完整请求URL
  6. }
  7. String projectnameP = request.getContextPath();
  8. String projectName = projectnameP.substring(projectnameP.lastIndexOf('/')+1,projectnameP.length()); //获取工程名,如testW
  9. if(!"".equals(projectName)){
  10. projectName ="/"+projectName;
  11. }
  12. String port = String.valueOf(request.getServerPort());//获取端口号
  13. if(!"80".equals(port)){//不是80端口时需加端口号
  14. port = ":"+port;
  15. }else{
  16. port = "";
  17. }
  18. String strBackUrl = "http://" + request.getServerName()+port+projectName+url;//完整的请求路径http://192.168.1.117/testW/+路径
  19. AccessToken token = null;
  20. if(TimedTask.accessToken==null || TimedTask.accessToken.getToken()==""){//token失效,重新获取,获取方法参考第二篇博文,在这由于篇幅问题暂不列出
  21. token = WeixinUtil.getAccessToken(TimedTask.appid, TimedTask.appsecret);/
  22. }else{
  23. token = TimedTask.accessToken;
  24. }
  25. Ticket ticket = null;
  26. if(TimedTask.ticket ==null || TimedTask.ticket.getTicket()==""){
  27. ticket = WeixinUtil.getTicket(token.getToken());//获取ticket
  28. }else{
  29. ticket = TimedTask.ticket;
  30. }
  31. SignatureInfo siInfo = new SignatureInfo();
  32. siInfo.setNoncestr(RandomStringUtils.randomAlphanumeric(20));//随机字符串
  33. siInfo.setTimestamp(String.valueOf(System.currentTimeMillis()));//随机时间截
  34. siInfo.setUrl(strBackUrl);
  35. siInfo = WeixinUtil.getSignature(siInfo, ticket);
  36. request.setAttribute("siInfo",siInfo);
  37. return "weixin/jssdk_demo";
  38. }

到此需要准备的数据就已经全部完成了,现在我们看看前台jssdk_demo.jsp页面是如何调用的

  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
  3. <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
  4. <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
  5. <c:set var="BS" value="${pageContext.request.contextPath}"></c:set>
  6. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  7. <html>
  8. <head>
  9. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  10. <title>jssdk_demo</title>
  11. <script type="text/javascript" src="${BS}/js/jquery-1.7.2.min.js"></script>
  12. <script type="text/javascript" src="${BS}/js/weixin/jweixin-1.2.0.js"></script>
  13. <link href="${BS}/css/weixin/weixinStyle.css" type="text/css" rel="stylesheet" />
  14. <link href="${BS}/css/weixin/weixinmain.css" type="text/css" rel="stylesheet"/>
  15. //百度地图没有密匙的可以去官网申请
  16. <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=密匙"></script>
  17. <script type="text/javascript" src="http://developer.baidu.com/map/jsdemo/demo/convertor.js"></script>
  18. <script type="text/javascript" src="https://3gimg.qq.com/lightmap/components/geolocation/geolocation.min.js"></script>
  19. </head>
  20. <input type="hidden" id="timestamp" value="${siInfo.timestamp}">
  21. <input type="hidden" id="nonceStr" value="${siInfo.noncestr}">
  22. <input type="hidden" id="signature" value="${siInfo.signature}">
  23. <input type="hidden" id="longitude" value="">
  24. <input type="hidden" id="latitude" value="">
  25. <input type="hidden" id="weixinOperId" value="微信appid">
  26. <script type="text/javascript">
  27. var phoneWidth = parseInt(window.screen.width);
  28. var phoneScale = phoneWidth/640;
  29. var ua = navigator.userAgent;
  30. if (/Android (\d+\.\d+)/.test(ua)){
  31. var version = parseFloat(RegExp.$1);
  32. if(version>2.3){
  33. document.write("<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0, minimum-scale = 1.0, maximum-scale = "+phoneScale+", target-densitydpi=device-dpi\">");
  34. }else{
  35. document.write("<meta name=\"viewport\" content=\"width=device-width, target-densitydpi=device-dpi\">");
  36. }
  37. }else{
  38. document.write("<meta name=\"viewport\" content=\"width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,target-densitydpi=device-dpi\">");
  39. }
  40. $(function(){
  41. $(".nav a").click(function(){
  42. $('.nav a').removeClass('active');
  43. $(this).addClass('active');
  44. var nav = $(this).attr("nav");
  45. $("section div[class='desc']").each(function(i,val){
  46. if($(this).attr("nav")==nav){
  47. $(this).show();
  48. }else{
  49. $(this).hide();
  50. }
  51. });
  52. });
  53. });
  54. var signature = $("#signature").val();
  55. var nonceStr = $("#nonceStr").val();
  56. var timestamp = $("#timestamp").val();
  57. var weixinOperId = $("#weixinOperId").val();
  58. wx.config({
  59. debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
  60. appId: weixinOperId, // 必填,公众号的唯一标识
  61. timestamp:timestamp, // 必填,生成签名的时间戳
  62. nonceStr: nonceStr, // 必填,生成签名的随机串
  63. signature:signature,// 必填,签名
  64. jsApiList: [
  65. 'openLocation',
  66. 'getLocation'
  67. ] // 必填,需要使用的JS接口列表,所有JS接口列表见官方文档附录2
  68. });
  69. wx.ready(function(){
  70. getLocation();
  71. });
  72. wx.error(function(res){
  73. //alert("error");
  74. });
  75. </script>
  76. <script type="text/javascript">
  77. $(function () {
  78. $("#wdialogTitle2").text("信息提示");
  79. $("#wdialogConfirm2").click(function(i,val){
  80. $("#wdialog2").hide();
  81. });
  82. $(".warn_message").text("");
  83. //刷新定位
  84. $(".SelectCityWrap .cityTit .r").click(function () {
  85. $(this).addClass("hover");
  86. getLocation();
  87. });
  88. $("b.search").click(function () {
  89. searchMap($("#indexSearchBox").val());
  90. return false;
  91. });
  92. });
  93.  
  94. var latitude,longitude;
  95. //获取当前地址
  96. function getLocation(){
  97. wx.getLocation({
  98. type: 'gcj02', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
  99. success: function (res) {
  100. latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
  101. longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。
  102. var speed = res.speed; // 速度,以米/每秒计
  103. var accuracy = res.accuracy; // 位置精度
  104. getAddressInfo2(longitude,latitude);
  105. },cancel: function (res){
  106. $("#wdialogContent2").text("用户拒绝授权获取地理位置");
  107. $("#wdialog2").show();
  108. }
  109. });
  110. }
  111.  
  112. var addId = "choseAdd";
  113. var longiText = "longitude";
  114. var latiText = "latitude";
  115. //打开百度地图并标记当前定位地址
  116. function showMapArea(){
  117. var myGeo = new BMap.Geocoder();
  118. var pt = new BMap.Point(longitude,latitude);
  119. translateCallback2 = function (point){
  120. createBaiduMap(point.lng,point.lat,1);
  121. };
  122. setTimeout(function(){
  123. BMap.Convertor.translate(pt,2,translateCallback2); //火星经纬度转成百度坐标,2变成0时,则是默认的wgs84的gps坐标转换成百度坐标
  124. }, 100);
  125. }
  126. //调用百度地图API,经纬度转化成实际地址
  127. function getAddressInfo2(lon,lat) {
  128. var myGeo = new BMap.Geocoder();
  129. var pt = new BMap.Point(lon,lat);
  130. translateCallback2 = function (point){
  131. myGeo.getLocation(point, function(rs) {
  132. var addComp = rs.addressComponents;
  133. var addr = addComp.province+ addComp.city + addComp.district+ addComp.street+ addComp.streetNumber;
  134. $("#nowAdd").text(addr);
  135. });
  136. };
  137. setTimeout(function(){
  138. BMap.Convertor.translate(pt,2,translateCallback2); //火星经纬度转成百度坐标
  139. }, 100);
  140. }
  141. function returnAdd(){
  142. $("#addressArea").show();
  143. $("#mapArea").hide();
  144. }
  145. function confirmC(){
  146. var address = $("#choseAdd").text();
  147. var longiText = $("#longitude").val();
  148. var latiText = $("#latitude").val();
  149. if(latiText=="" || longitude==""){
  150. $("#wdialogContent2").text("请先选择您当前位置");
  151. $("#wdialog2").show();
  152. }
  153. }
  154. function getNavi(){
  155. wx.openLocation({
  156. latitude: latitude, // 纬度,浮点数,范围为90 ~ -90
  157. longitude: longitude, // 经度,浮点数,范围为180 ~ -180。
  158. name: '我现在在这里', // 位置名
  159. address: $("#nowAdd").text(), // 地址详情说明
  160. scale: 20, // 地图缩放级别,整形值,范围从1~28。默认为最大
  161. infoUrl: 'https://www.baidu.com/' // 在查看位置界面底部显示的超链接,可点击跳转
  162. });
  163. }
  164. </script>
  165. <body>
  166. <div id="addressArea" style="min-height:526px;">
  167. <section class="SelectCityWrap" style="width:98%;">
  168. <h3 class="cityTit" style="width:100%;background:#DDDDDD;">
  169. <span class="l left" style="max-width:80%;height:45px;overflow:hidden;">当前地址:<span class="val" style="height:45px;max-height:45px;overflow:hidden;" id="nowAdd">${nowAdd}</span></span>
  170. <span class="r right"></span>
  171. </h3>
  172. <section class="content">
  173. <div class="nav">
  174. <a class="" nav="nav_1" onclick="getNavi()">当前地址导航</a>
  175. <a nav="nav_2" onclick="showMapArea()">地图选择</a>
  176. </div>
  177. <div class="desc" nav="nav_1">
  178. </div>
  179. <div class="desc" nav="nav_2" style="display:none;width:100%;">
  180. <section class="SelectCityWrap" style="width:100%;">
  181. <h3 class="cityTit" style="text-align:left;width:100%;background:#DDDDDD;">
  182. <span class="" style="padding-left:5px;">已选地址:<span class="val" id="choseAdd">点击地图可选择地址</span></span>
  183. </h3>
  184. <!-- 搜索 -->
  185. <div style="height:auto;" class="indexSearch">
  186. <div class="content search">
  187. <input type="search" id="indexSearchBox" placeholder="点击地图可选择地址" style="height: 38px;line-height:35px;width:100%;max-width:570px;padding-left:10px;font-size: 16px;" class="left">
  188. <span></span>
  189. <b class="search"></b>
  190. </div>
  191. </div>
  192. <!-- 搜索 end-->
  193. <div id="container" style="width:100%;height:300px;"></div >
  194. <section id="r_content" style="margin-bottom:55px;">
  195. <div class="r_shadow">
  196. <div class="r_searchlist positiolist" id="search-result"></div>
  197. </div>
  198. </section>
  199. </section>
  200. </div>
  201. </section>
  202. </section>
  203. </div>
  204. <div id="mapArea" style="min-height:526px;display:none;">
  205. <header id="r_header" class="r_title">
  206. <a class="r_returnbk" onclick="returnAdd()">
  207. <img src="${BS}/images/weixin/r_icon7.png" alt="">
  208. </a>
  209. <a style="float:right;padding-right:12px;" onclick="confirmC()">确定</a>
  210. </header>
  211. <section class="SelectCityWrap">
  212. <!-- 搜索 -->
  213. <div style="height:auto;" class="indexSearch">
  214. <div class="content search">
  215. <input type="search" id="indexSearchBox" placeholder="点击地图可选择地址" style="height: 38px;line-height:35px;width:100%;max-width:570px;padding-left:10px;font-size: 16px;" class="left">
  216. <span></span>
  217. <b class="search"></b>
  218. </div>
  219. </div>
  220. <!-- 搜索 end-->
  221. <div id="container" style="width:100%;height:300px;"></div >
  222. <section id="r_content">
  223. <div class="r_shadow">
  224. <div class="r_searchlist positiolist" id="search-result">
  225. </div>
  226. </div>
  227. </section>
  228. </section>
  229. </div>
  230. <script type="text/javascript" src="${BS}/js/weixin/mapLocation.js"></script>
  231. </body>
  232. </html>

mapLocation.js,为封装好的百度地图的方法,具体看各自需求可进行修改:

  1. function getHtml5Location() {
  2. if(navigator.geolocation) {
  3. // navigator.geolocation.watchPosition(updateLocation, handleLocationError, {
  4. navigator.geolocation.getCurrentPosition(updateLocation, handleLocationError,{
  5. // 指示浏览器获取高精度的位置,默认为false
  6. enableHighAcuracy: true,
  7. // 指定获取地理位置的超时时间,默认不限时,单位为毫秒
  8. //timeout: 5000,
  9. // 最长有效期,在重复获取地理位置时,此参数指定多久再次获取位置。
  10. maximumAge: 20000
  11. });
  12. }else{
  13. $("#wdialogContent2").text("无法获取您当前地理位置");
  14. $("#wdialog2").show();
  15. }
  16. }
  17. function updateLocation(position) {
  18. var latitude = position.coords.latitude;
  19. var longitude = position.coords.longitude;
  20. var accuracy = position.coords.accuracy;
  21. // 如果accuracy的值太大,我们认为它不准确,不用它计算距离
  22. if (accuracy >= 1000) {
  23. return;
  24. }
  25. var pt = new BMap.Point(longitude,latitude);
  26. setTimeout(function(){
  27. BMap.Convertor.translate(pt,0,translateCallback); //真实经纬度转成百度坐标
  28. }, 100);
  29. translateCallback = function (point){
  30. createBaiduMap(point.lat,point.lng,1);
  31. };
  32. }
  33.  
  34. function handleLocationError(error) {
  35. switch (error.code) {
  36. case 0:
  37. $("#wdialogContent2").text("尝试获取您的位置信息时发生错误:"+ error.message);
  38. $("#wdialog2").show();
  39. break;
  40. case 1:
  41. $("#wdialogContent2").text("用户拒绝了获取位置信息请求");
  42. $("#wdialog2").show();
  43. break;
  44. case 2:
  45. $("#wdialogContent2").text("浏览器无法获取您的位置信息:"+ error.message);
  46. $("#wdialog2").show();
  47. break;
  48. case 3:
  49. $("#wdialogContent2").text("获取您位置信息超时");
  50. $("#wdialog2").show();
  51. break;
  52. }
  53. }
  54. /**
  55. * 传人坐标获得详细地址
  56. * @param lat
  57. * @param lon
  58. */
  59. function getAddressInfo(lon,lat,type) {
  60. var myGeo = new BMap.Geocoder();
  61. var pt = new BMap.Point(lon,lat);
  62. translateCallback2 = function (point){
  63. myGeo.getLocation(point, function(rs) {
  64. var addComp = rs.addressComponents;
  65. //rs.surroundingPois;//附近地址
  66. var addr = addComp.province+ addComp.city + addComp.district+ addComp.street+ addComp.streetNumber;
  67. searchMap(addr);
  68. });
  69. };
  70. setTimeout(function(){
  71. if(type==1){
  72. BMap.Convertor.translate(pt,0,translateCallback2); //真实经纬度转成百度坐标
  73. }else{
  74. translateCallback2(pt);
  75. }
  76. }, 100);
  77. }
  78. var map = null;
  79. function setMapEvent(){
  80. map.enableDragging();//启用地图拖拽事件,默认启用(可不写)
  81. map.enableScrollWheelZoom();//启用地图滚轮放大缩小
  82. map.enableDoubleClickZoom();//启用鼠标双击放大,默认启用(可不写)
  83. map.enableKeyboard();//启用键盘上下左右键移动地图
  84. }
  85. var marker = null;
  86. function createBaiduMap(longitude, latitude,type) {
  87. if(map==null){
  88. map =new BMap.Map("container");
  89. }
  90. setMapEvent();
  91. mSearchManager.clear();
  92. var pt= new BMap.Point(longitude,latitude);
  93. translateCallback = function (point){
  94. var point= new BMap.Point(point.lng, point.lat);
  95. map.setCenter(point);
  96. map.centerAndZoom(point, 16);
  97. // 添加带有定位的导航控件
  98. var navigationControl = new BMap.NavigationControl({
  99. // 靠左上角位置
  100. anchor: BMAP_ANCHOR_TOP_LEFT,
  101. // LARGE类型
  102. type: BMAP_NAVIGATION_CONTROL_LARGE,
  103. // 启用显示定位
  104. enableGeolocation: true
  105. });
  106. map.addControl(navigationControl);
  107. marker = new BMap.Marker(point); //标注
  108. marker.enableDragging();
  109. marker.addEventListener("dragend",getAttr);
  110. function getAttr(){
  111. var p = marker.getPosition(); //获取marker的位置
  112. getAddressInfo(p.lng,p.lat);
  113. }
  114. map.clearOverlays();
  115. map.addOverlay(marker);
  116. map.addEventListener("click", function(e){
  117. var gc = new BMap.Geocoder();
  118. var pt = new BMap.Point(e.point.lng,e.point.lat);
  119. document.getElementById(longiText).value = e.point.lng;
  120. document.getElementById(latiText).value = e.point.lat;
  121. window.map.removeOverlay(marker);
  122. marker = new BMap.Marker(e.point);//创建一个覆盖物
  123. map.addOverlay(marker);//增加一个标示到地图上
  124. var dress = gc.getLocation(pt, function(rs){
  125. var addComp = rs.addressComponents;
  126. var address = addComp.province+addComp.city+addComp.district+addComp.street+addComp.streetNumber;
  127. if(typeof(addId)!="undefined" && addId !=null){
  128. $("#"+addId).text(address);
  129. }
  130. searchMap(address);
  131. });
  132. });
  133. // 添加定位控件
  134. // var geolocationControl = new BMap.GeolocationControl();
  135. // geolocationControl.addEventListener("locationSuccess", function(e){
  136. // window.map.removeOverlay(marker);
  137. // marker = new BMap.Marker(e.point);//创建一个覆盖物
  138. // map.addOverlay(marker);//增加一个标示到地图上
  139. // map.panTo(e.point);
  140. // 定位成功事件
  141. // var address = '';
  142. // address += e.addressComponent.province;
  143. // address += e.addressComponent.city;
  144. // address += e.addressComponent.district;
  145. // address += e.addressComponent.street;
  146. // address += e.addressComponent.streetNumber;
  147. // searchMap(address);
  148. //getLocation();
  149. // });
  150. // geolocationControl.addEventListener("locationError",function(e){
  151. // // 定位失败事件
  152. // alert(e.message);
  153. // });
  154. //地图拖动事件
  155. /*map.addEventListener("dragging", function(evt){
  156. var offsetPoint = new BMap.Pixel(evt.offsetX, evt.offsetY);
  157. });*/
  158. // map.addControl(geolocationControl);
  159. // 添加带有定位的导航控件
  160. };
  161. setTimeout(function(){
  162. if(type==1){
  163. translateCallback(pt);
  164. }else{
  165. BMap.Convertor.translate(pt,0,translateCallback); //真实经纬度转成百度坐标
  166. }
  167. }, 100);
  168. }
  169. var mSearchManager = new SearchManager();
  170. var isR = false;
  171. function SearchManager(){
  172. this.SearchResultList = new Array();
  173. this.showSearchResult = function(poi){
  174. var index = this.SearchResultList.length;
  175. var marker = new BMap.Marker(poi.point);
  176. var a=document.createElement("a");
  177. var p=document.createElement("P");
  178. this.SearchResultList[index] = new KzSearchResult( marker , poi , a , p);
  179. var address = "";
  180. if(this.SearchResultList[index].poi.province!=undefined && this.SearchResultList[index].poi.province!=null
  181. && this.SearchResultList[index].poi.province !=""){
  182. address = this.SearchResultList[index].poi.province;
  183. }
  184. if(this.SearchResultList[index].poi.city!=undefined && this.SearchResultList[index].poi.city!=null
  185. && this.SearchResultList[index].poi.city !=""){
  186. address +=this.SearchResultList[index].poi.city;
  187. }
  188. var div = document.getElementById("search-result");
  189. a.href="javascript:mSearchManager.zoomto("+index+")";
  190. var $a = $("<a style=\"padding-left:10px;\" href=\"javascript:mSearchManager.zoomto("+index+")\"></a>");
  191. var section = $("<section class=\"listbox nobg list\" style=\"height:60px;\"></section>");
  192. var div1 = $("<div class=\"jobname\" style=\"height:25px;line-height:25px;\">"+poi.title+"</div>");
  193. var div2 = $("<div class=\"time\" style=\"height:25px;line-height:25px;color:#026AFF;\"></div>");
  194. var div3 = $("<div class=\"box1\" style=\"height:35px;line-height:35px;\">"+address+poi.address+"</div>");
  195. $a.append(div1).append(div2).append(div3);
  196. section.append($a);
  197. $("#search-result").append(section);
  198. };
  199. this.clear = function(){
  200. var div = $("#search-result section");
  201. div.remove();
  202. window.map.removeOverlay(marker);
  203. this.SearchResultList.length = 0;
  204. };
  205. this.clear2 = function(){
  206. var div = $("#search-result section");
  207. div.remove();
  208. this.SearchResultList.length = 0;
  209. };
  210. this.zoomto = function (index){
  211. $(".time").each(function(i,val){
  212. if(i==index){
  213. $(this).text("当前位置");
  214. }else{
  215. $(this).text("");
  216. }
  217. });
  218. window.map.removeOverlay(marker);
  219. marker = new BMap.Marker(this.SearchResultList[index].poi.point);
  220. window.map.addOverlay(marker);
  221. window.map.centerAndZoom(this.SearchResultList[index].poi.point, 16);
  222. document.getElementById(longiText).value = this.SearchResultList[index].poi.point.lng;
  223. document.getElementById(latiText).value = this.SearchResultList[index].poi.point.lat;
  224. if(typeof(addId)!="undefined" && addId !=null){
  225. document.getElementById(addId).innerHTML = this.SearchResultList[index].poi.title;
  226. }
  227. };
  228. }
  229. function KzSearchResult(m , b ,a , p){
  230. this.marker = m;
  231. this.poi = b;
  232. this.a = a;
  233. this.p = p;
  234. }
  235. function searchMap(area) {
  236. if(map==null){
  237. map =new BMap.Map("container");
  238. }
  239. var ls = new BMap.LocalSearch(map);
  240. ls.setSearchCompleteCallback(function(rs) {
  241. mSearchManager.clear2();
  242. if(ls.getStatus() == BMAP_STATUS_SUCCESS) {
  243. for(var index=0;index<rs.getCurrentNumPois();index++){
  244. var poi = rs.getPoi(index);
  245. if (poi) {
  246. mSearchManager.showSearchResult(poi);
  247. }
  248. }
  249. }
  250. });
  251. ls.search(area);
  252. }

本文也发布到另外一个网站,如果只有那边才有帐号的,有需要的可以收藏一下微信JS-SDK之地理位置的获取,集成百度地图实现在线地图搜索

到此该篇博文已经讲解完毕,如有问题,欢迎大家指出,一起探讨

微信公众号开发《三》微信JS-SDK之地理位置的获取,集成百度地图实现在线地图搜索的更多相关文章

  1. C#微信公众号开发-高级接口-之网页授权oauth2.0获取用户基本信息(二)

    C#微信公众号开发之网页授权oauth2.0获取用户基本信息(一) 中讲解了如果通过微信授权2.0snsapi_base获取已经关注用户的基本信息,然而很多情况下我们经常需要获取非关注用户的信息,方法 ...

  2. c#微信公众号开发一----基本设置,服务器配置token验证,获取timestamp/nonce/signature

    一.c#微信公众号开发----基本设置 参考微信官方文档 https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Acce ...

  3. 微信公众号开发总结(Node.js + express + winston)

    关于订阅号.服务号.企业号 官方定位 订阅号:主要偏于为用户传达资讯(类似报纸杂志),认证后每天可以群发一条消息,可达到宣传效果,构建与读者之间更好的沟通和管理模式. 服务号:主要偏于服务交互(类似银 ...

  4. 微信公众号开发 [05] 微信支付功能开发(网页JSAPI调用)

    1.微信支付的流程 如下三张手机截图,我们在微信网页端看到的支付,表面上看到的是 "点击支付按钮 - 弹出支付框 - 支付成功后出现提示页面",实际上的核心处理过程是: 点击支付按 ...

  5. Java 微信公众号开发--- 接入微信

    开发微信公众号在没有正式的公众平台账号时,我们可以使用测试平台账号--- 测试平台申请地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandb ...

  6. 微信公众号开发之微信JSSDK

    概述 微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包. 通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照.选图.语音.位置等手机系统的能力,同时可以直接使用微 ...

  7. VopSdk一个高逼格微信公众号开发SDK(源码下载)

    看之前回复很多说明大家很有热情&文章被误删掉了,不想让有的朋友错失这个高逼格的东西,现在重新发布,这次就直接放出源码,文章最末下载地址. 看之前回复很多说明大家很有热情&文章被误删掉了 ...

  8. VopSdk一个高逼格微信公众号开发SDK:自动化生产(装逼模式开启)

    VopSdk一个高逼格微信公众号开发SDK(源码下载) VopSdk一个高逼格微信公众号开发SDK:自动化生产(装逼模式开启) 针对第一版,我们搞了第二版本,老规矩先定个目标. 一 我们的目标 a.移 ...

  9. 微信公众号开发《三》微信JS-SDK之地理位置的获取与在线导航,集成百度地图实现在线地图搜索

    本次讲解微信开发第三篇:获取用户地址位置信息,是非常常用的功能,特别是服务行业公众号,尤为需要该功能,本次讲解的就是如何调用微信JS-SDK接口,获取用户位置信息,并结合百度地铁,实现在线地图搜索,与 ...

随机推荐

  1. Sublime Text 3常用插件

    操作:按下Ctrl+Shift+P调出命令面板 输入install 调出 Install Package 选项并回车,然后在列表中选中要安装的插件. 常用插件: 1---- Bracket Highl ...

  2. 手机自动化测试:appium源码分析之bootstrap十一

    手机自动化测试:appium源码分析之bootstrap十一   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣 ...

  3. js控制滚动条默认在底部

    html: <div id="chat_content" class="chat_content">                    < ...

  4. Redis基础学习(三)—Key操作

    一.key的相关操作 1.删除 del key1 key2 ... Keyn 作用: 删除1个或多个键. 返回值: 不存在的key忽略掉,返回真正删除的key的数量.   2.重命名 rename k ...

  5. WebService基础学习(二)—三要素

    一.Java中WebService规范      JAVA 中共有三种WebService 规范,分别是JAX-WS.JAX-RS.JAXM&SAAJ(废弃).   1.JAX-WS规范    ...

  6. JSTL标签分类

    <c:>核心标签库:共有13个,功能分4类 1.表达式控制标签: out.set.remove.catch 2.流程控制标签: if.choose.when.otherwise 3.循环标 ...

  7. Kubernetes环境下的各种调试方法

    作者:Jack47 转载请保留作者和原文出处 欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 本文介绍在Kubernetes环境下的调试方法,希望对读者有用.如果关 ...

  8. 【redis专题(8)】命令语法介绍之通用KEY

    select num 数据库选择 默认有16[0到15]个数据库,默认自动选择0号数据库 move key num 移动key到num服务器 del key [key ...] 删除给定的一个或多个 ...

  9. ROS使用常见问题

    1.Q:查看ros版本 A:先在终端输入roscore,打开新终端,再输入,rosparam list,再输入rosparam get /rosdistro,就能得到版本. 2.Q:运行命令$ ros ...

  10. 函数求值(swust oj0274)

    函数求值(0274) Time limit(ms): 1000 Memory limit(kb): 65535 Submission: 1767 Accepted: 324 Accepted 14级卓 ...