微信内嵌H5(uniapp)获取用户位置信息及打开内置地图

1. 开发前的准备(下面无先后顺序)

  • 在微信后台配置js安全域名,添加IP白名单等;
  • 下载jweixin.js
  • 申请腾讯地图开发平台账号并创建应用,配置相关信息(注意:H5不需要qqmap-wx-jssdk.min.js,因为H5的经纬度解析在后端(前端会跨越));

2. 后端开发(下面有先后顺序)

  1. 通过appId和appSecret获取access_token(注意:不能多次请求,需要缓存,过期时间7200秒
public ResponseResult getAccessToken() {
     String accessTokenStr = redisHelper.getStr("access_token_expires_in");
     if (StringUtils.isNotEmpty(accessTokenStr)) {
         logger.info("access_token已缓存:" + accessTokenStr);
         return new ResponseResult(ResponseResult.SUCCESS, "成功", accessTokenStr);
     }

	 //h5AccessTokenUrl:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
     String url = h5AccessTokenUrl.replace("APPID", "appId").replace("APPSECRET", "appSecret");
     String result = HttpRequest.get(url).timeout(6000).execute().body();
     logger.info("获取accessToken的返回:" + result);
     if (StringUtils.isEmpty(result)) {
         return new ResponseResult(ResponseResult.ERROR_400,"获取accessToken失败");
     }

     JSONObject data = JSON.parseObject(result);
     if (data.containsKey("access_token")) {
         //说明返回成功
         if (data.containsKey("expires_in")) {
             //微信官方的默认过期时间应该是7200秒,我们这里设置一定要小于7200秒,但是不能太小,请求太频繁,会被微信拦截掉
             redisHelper.setStr("access_token_expires_in", data.getString("access_token"), 3600, TimeUnit.SECONDS);
         }
         return new ResponseResult(ResponseResult.SUCCESS, "成功", data.getString("access_token"));
     }

     if (data.containsKey("errcode")) {
         return new ResponseResult(ResponseResult.ERROR_400, data.getString("errmsg"));
     }

     return new ResponseResult(ResponseResult.ERROR_400, "获取accessToken失败");
}
  1. 通过access_token获取jsapi_ticket(注意:不能多次请求,需要缓存,过期时间7200秒
public ResponseResult getJsApiTicket() {
	 String jsApiTicketStr = redisHelper.getStr("jsapi_ticket_expires_in");
	 if (StringUtils.isNotEmpty(jsApiTicketStr)) {
	     logger.info("jsapi_ticket已缓存:" + jsApiTicketStr);
	     return new ResponseResult(ResponseResult.SUCCESS, "成功", jsApiTicketStr);
	 }
	
	 ResponseResult responseResult = this.getAccessToken();
	 if (ResponseResult.SUCCESS != responseResult.getCode() || null == responseResult.getData()) {
	     return new ResponseResult(ResponseResult.ERROR_400, "获取TICKET失败");
	 }
	
	 String accessToken = String.valueOf(responseResult.getData());
	 //h5JsApiTicketUrl:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
	 String url = h5JsApiTicketUrl.replace("ACCESS_TOKEN", accessToken);
	 String result = HttpRequest.get(url).timeout(6000).execute().body();
	 logger.info("获取jsApiTicket的返回:" + result);
	 if (StringUtils.isEmpty(result)) {
	     return new ResponseResult(ResponseResult.ERROR_400,"获取TICKET失败");
	 }
	
	 JSONObject data = JSON.parseObject(result);
	 if (0 != data.getIntValue("errcode") && !data.containsKey("ticket")) {
	     return new ResponseResult(ResponseResult.ERROR_400,"获取TICKET失败");
	 }
	
	 //说明返回成功
	 if (data.containsKey("expires_in")) {
	     //微信官方的默认过期时间应该是7200秒,我们这里设置一定要小于7200秒,但是不能太小,请求太频繁,会被微信拦截掉
	     redisHelper.setStr("jsapi_ticket_expires_in", data.getString("ticket"), 3600, TimeUnit.SECONDS);
	 }
	
	 return new ResponseResult(ResponseResult.SUCCESS,"成功", data.getString("ticket"));
}
  1. 通过jsapi_ticket获取signature(注意:是sha1签名)
public ResponseResult getH5Signature(String hrefURL) {
    ResponseResult responseResult = this.getJsApiTicket();
    if (ResponseResult.SUCCESS != responseResult.getCode() || null == responseResult.getData()) {
        return new ResponseResult(ResponseResult.ERROR_400,"获取签名失败");
    }

    String jsApiTicket = String.valueOf(responseResult.getData());
    String nonceStr = StringUtil.getRandom(10);
    //需要注意的是,这里的时间戳是秒级时间戳(10位),不是毫秒级(13位)
    String timestamp = String.valueOf(System.currentTimeMillis() / 1000);//时间戳

    try {
        String url = URLDecoder.decode(hrefURL, "UTF-8");
        String signature = DigestUtil.sha1Hex("jsapi_ticket=" + jsApiTicket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + url);
        logger.info("获取到的signature:" + signature);
        if (StringUtils.isEmpty(signature)) {
            return new ResponseResult(ResponseResult.ERROR_400,"获取签名失败");
        }

        Map<String, Object> data = new HashMap<>(4);
        data.put("appId", h5AppId);
        data.put("nonceStr", nonceStr);
        data.put("timestamp", timestamp);
        data.put("signature", signature);

        logger.info("data数据:" + JSONUtil.toJsonStr(data));
        return new ResponseResult(ResponseResult.SUCCESS,"成功", data);
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    return new ResponseResult(ResponseResult.ERROR_400,"未知错误");
}


3. 前端开发
引入jweixin.js

 import jweixin from '@/common/jweixin';
 import wechat from '@/utils/wechat'

在onLoad()中初始化(获取经纬度)

onLoad() {
	//如果是打开地图,点击的时候调用this.lcationHandleH5_01('open')
	this.lcationHandleH5_01('init');
}

以下是代码实现

async lcationHandleH5_01(flag) {
	const _this = this;
	
	console.log('是否是微信客户端', wechat.isWechat());
	if (!wechat.isWechat()) {
		_this.$mHelper.toast('请在微信客户端打开');
		return;
	}
	
	const hrefURL = window.location.href;
	const signURL = encodeURIComponent(hrefURL.indexOf("#") > -1 ? hrefURL.split('#')[0] : hrefURL);
	wechat.getH5Sign(signURL).then(res => {
		console.log('wechat.getH5Sign()结果', res);
		_this.lcationHandleH5_02(flag, res);
	}).catch(err => {
		_this.$mHelper.toast(`${err}`);
	});
},
lcationHandleH5_02(flag, signData) {
	const _this = this;
	
	jweixin.config({
		debug: true,
		...signData,
		jsApiList: ['openLocation', 'getLocation']
	});
	
	jweixin.error(err => {
		console.error('jweixin配置出错======>', err);
	});
	
	jweixin.ready(() => {
		if ('init' === flag) {
			_this.lcationHandleH5_02_init();
		} else {
			_this.lcationHandleH5_02_choose();
		}
	});
	},
	lcationHandleH5_02_init() {
	const _this = this;
	
	jweixin.getLocation({
		//type: 'gcj02', //wgs84返回gps坐标,gcj02返回可用于wx.getLocation 的坐标
		success(res) {
			console.log('jweixin.getLocation结果========>', JSON.stringify(res));
			wechat.formatLocationH5(res.latitude, res.longitude).then(res3 => {
				_this.curAddress = res3;
			}).catch(err3 => {
				_this.$mHelper.toast(`${err3}`);
			});
		},
		fail(err) {
			console.error('获取位置信息失败=======>', err);
			_this.$mHelper.toast(`${err}`);
		}
	});
},
lcationHandleH5_02_choose() {
	const _this = this;
	jweixin.getLocation({
		//type: 'gcj02', //wgs84返回gps坐标,gcj02返回可用于wx.getLocation 的坐标
		success(res) {
			jweixin.openLocation({
				latitude: res.latitude,
				longitude: res.longitude,
				name: '我的位置',
				success(res2) {
					console.log('获取位置信息成功=======>', res2);
					wechat.formatLocationH5(res2.latitude, res2.longitude).then(res3 => {
						_this.curAddress = res3;
					}).catch(err3 => {
						_this.$mHelper.toast(`${err3}`);
					});
				},
				fail(err2) {
					console.error('获取位置信息失败=======>', err2);
					_this.$mHelper.toast(`${err2}`);
				}
			});
		},
		fail(err) {
			console.error('获取位置信息失败=======>', err);
			_this.$mHelper.toast(`${err}`);
		}
	});
}

下面是wechat.js

import jweixin from '@/common/jweixin.js';
import constData from '@/static/const/serverConfig.json';
import wxMap from '@/common/qqmap-wx-jssdk.min.js';
import helper from '@/utils/helper.js';
import store from '@/store/index.js';
import {http} from '@/utils/request';
import {getH5Signature, parseH5LatLng} from '@/api/basicApi';
/* eslint-disable */

//判断是否公众号(微信H5)
const isWechat = () => {
	// #ifdef H5
	const ua = window.navigator.userAgent.toLowerCase();
	//注意,下面的判断不能用===判断,只能用==判断
	return ua.match(/micromessenger/i) == 'micromessenger'
	// #endif
};
//获取H5签名
const getH5Sign = hrefURL => new Promise((resolve, reject) => {
	const _this = this;
	http.get(getH5Signature, {hrefURL}).then(res => {
		console.log('查询到的签名结果', JSON.stringify(res));
		if (200 === res.code) {
			resolve(res.data);
		} else {
			_this.$mHelper.toast('初始化位置信息失败', 2000);
			reject('初始化位置信息失败');
		}
	}).catch(err => {
		reject(`初始化位置信息失败:${err}`);
	});
});
//格式化位置
const formatLocationH5 = (latitude, longitude) => new Promise((resolve, reject) => {
	const _this = this;
	
	if (!latitude || !longitude) {
		reject('参数不能为空');
	}
	
	http.get(parseH5LatLng, {lat: latitude, lng: longitude}).then(res => {
		console.log('解析经纬度返回结果', JSON.stringify(res));
		if (200 === res.code) {
			resolve(res.data);
		} else {
			_this.$mHelper.toast('解析位置信息失败', 2000);
			reject('解析位置信息失败');
		}
	}).catch(err => {
		reject(`解析位置信息失败:${err}`);
	});
});


export default {
	isWechat,
	getH5Sign,
	formatLocationH5
};

3. 后端开发-解析经纬度获取位置信息(H5解析经纬度在后端)

public ResponseResult parseH5LatLng(String lat, String lng) {
        if (StringUtils.isEmpty(lat) || StringUtils.isEmpty(lng)) {
            return new ResponseResult(ResponseResult.ERROR_400,"经纬度不能为空");
        }

        try {
        	//txApiMapUrl:https://apis.map.qq.com/ws/geocoder/v1/?coord_type=5&get_poi=0&output=json&key=API_KEY&location=LOCATION_LATLNG
            String url = txApiMapUrl.replace("API_KEY", txApiKey).replace("LOCATION_LATLNG", URLEncoder.encode(lat + "," + lng, "UTF-8"));
            String result = HttpRequest.get(url).timeout(6000).execute().body();
            if (StringUtils.isEmpty(result)) {
                return new ResponseResult(ResponseResult.ERROR_400,"解析位置失败");
            }

            JSONObject jsonObject = JSON.parseObject(result);
            if (null == jsonObject || 0 != jsonObject.getIntValue("status") || null == jsonObject.get("result")) {
                return new ResponseResult(ResponseResult.ERROR_400,"解析位置失败");
            }

            JSONObject data = JSON.parseObject(jsonObject.getString("result"));
            Map<String, Object> dataMap = new HashMap<>(5);

            JSONObject location = JSON.parseObject(data.getString("location"));
            dataMap.put("latitude", location.getBigDecimal("lat"));
            dataMap.put("longitude", location.getBigDecimal("lng"));

            dataMap.put("fullAddress", data.getString("address"));

            JSONObject addressComponent = JSON.parseObject(data.getString("address_component"));
            dataMap.put("address", addressComponent.getString("district") + addressComponent.getString("street"));

            return new ResponseResult(ResponseResult.SUCCESS,"成功", dataMap);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return new ResponseResult(ResponseResult.ERROR_400,"位置错误");
}

你可能感兴趣的:(vue,java,微信公众号,java,微信公众平台,前端框架)