微信JS-SDK開發過程中,使用getLocation擷取坐标位置,如何将微信擷取的坐标直接應用到百度地圖中,顯示以下效果:
說明:紅色圖示是從微信轉換過來的位置,藍色圖示是周邊位置。首先從微信開發流程講解。1、微信JS-SDK開發文檔
首先進入官網的幫助文檔:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
可對文檔進行詳細的研讀,要擷取位置資訊,分以下步驟:
第一步:綁定域名
進入微信公衆号,找到“公衆号設定”菜單,進入“功能設定”面闆,
點選“設定”可設定引用js的相關域名:
第二步:引用官方js類庫
在需要調用JS接口的頁面引入如下JS檔案,(支援https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js 。
引用頁面是location.aspx,如下:
<%@ Page Title="擷取位置" Language="C#" AutoEventWireup="true" MasterPageFile="~/wxcrm/Site.Master" CodeFile="location.aspx.cs" Inherits="DTcms.Web.wxcrm.location" %>
<asp:Content ID="Content1" ContentPlaceHolderID="cphHead" runat="server">
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript">
$("#mask").show();
wx.config({
debug: false, //開啟調試模式,如為true,則彈出每個js函數調用情況
appId: '<%= ResultJsData.GetValue("appid") %>', //必填,公衆号的唯一辨別
timestamp: <%= ResultJsData.GetValue("timestamp") %>, //必填,生成簽名的時間戳
nonceStr: '<%= ResultJsData.GetValue("noncestr") %>', //必填,生成簽名的随機串
signature: '<%= ResultJsData.GetValue("signature") %>', //必填,簽名
jsApiList: [
'checkJsApi',
'onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo',
'hideMenuItems',
'showMenuItems',
'hideAllNonBaseMenuItem',
'showAllNonBaseMenuItem',
'translateVoice',
'startRecord',
'stopRecord',
'onRecordEnd',
'playVoice',
'pauseVoice',
'stopVoice',
'uploadVoice',
'downloadVoice',
'chooseImage',
'previewImage',
'uploadImage',
'downloadImage',
'getNetworkType',
'openLocation',
'getLocation',
'hideOptionMenu',
'showOptionMenu',
'closeWindow',
'scanQRCode',
'chooseWXPay',
'openProductSpecificView',
'addCard',
'chooseCard',
'openCard'
]
});
wx.ready(function(){
wx.checkJsApi({
jsApiList: [
'getNetworkType',
'previewImage',
'getLocation'
],
success: function (res) {
}
});
wx.getLocation({
type: 'wgs84', // 預設為wgs84的gps坐标,如果要傳回直接給openLocation用的火星坐标,可傳入'gcj02'
success: function (res) {
try {
var latitude = res.latitude; // 緯度,浮點數,範圍為90 ~ -90
var longitude = res.longitude; // 經度,浮點數,範圍為180 ~ -180。
var speed = res.speed; // 速度,以米/每秒計
var accuracy = res.accuracy; // 位置精度
//alert(JsonUti.convertToString(res));
//wx.openLocation({
// latitude: res.latitude, // 緯度,浮點數,範圍為90 ~ -90
// longitude: res.longitude, // 經度,浮點數,範圍為180 ~ -180。
// name: '目前位置', // 位置名
// address: '點選檢視', // 位址詳情說明
// scale: 28, // 地圖縮放級别,整形值,範圍從1~28。預設為最大
// infoUrl: "location1.aspx?m=Home&c=Index&a=getlocation&latitude="+latitude+"&longitude="+longitude // 在檢視位置界面底部顯示的超連結,可點選跳轉
//});
//alert(latitude+"-"+longitude);
$("#mask").hide();
window.location.href = "location1.aspx?m=Home&c=Index&a=getlocation&latitude=" +
latitude +
"&longitude=" +
longitude +
"&=speed" +
speed +
"&accuracy=" +
accuracy;
} catch (e) {
alert(e.message);
}
},
cancel: function (res) {
window.location.href="none.aspx?msg=拒絕擷取地理位置&r=" + Math.random();//拒絕
},
fail:function() {
alert("未能擷取地理位置!首先檢查手機是否啟用微信定位。");
}
});
});
wx.error(function(res) {
// config資訊驗證失敗會執行error函數,如簽名過期導緻驗證失敗,具體錯誤資訊可以打開config的debug模式檢視,也可以在傳回的res參數中檢視,對于SPA可以在這裡更新簽名。
});
wx.fail(function(res) {
});
</script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="cphTitle" runat="server">
擷取位置
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="cphContainer" runat="server">
<br />
<br />
<center style="display: block;">
<i class="weui_icon_msg weui_icon_info"></i>
<div class="input_errow" style="width: 60%; height: 60%; text-align: center;">
正在擷取地理位置資訊...
</div>
</center>
<div class="mask" style="display: none;">
<span>
<img src="/templates/txwap/images/mask.gif" />
</span>
</div>
</asp:Content>
頁面效果:
注意事項:
(1)如果手機設定不允許微信擷取位置資訊,則提示以上資訊。
(2)上圖參數擷取的是GPS坐标,如使用百度地圖,要做一定轉換,将在location1.aspx中展現。
(3)所有需要使用JS-SDK的頁面必須先注入配置資訊,否則将無法調用。
對應location.aspx.cs實作:
using Payment.WxWebHlper;
using Payment.WxWebHlper.Actions;
using System;
using System.Globalization;
using WxJsSDK;
using WxPayAPI;
namespace DTcms.Web.wxcrm
{
public partial class location : PageBase
{
protected string appId { get; set; }
protected string timestamp { get; set; }
protected string nonceStr { get; set; }
protected string signature { get; set; }
public static string WxJsApiParam { get; set; }
public WxJsData ResultJsData { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
JudgeCode();
var webAuthorize = new WebAuthorizeAction();
Code2TokenResult = webAuthorize.Code2Token(Request["code"]);
if (Code2TokenResult.HasError())
{
Response.Redirect(Urls.PageOfLocation);
GotoNonePage("擷取使用者憑證失敗,請重新擷取");
return;
}
GetUserInfoResult = webAuthorize.GetUserInfo(Code2TokenResult.access_token);
if (GetUserInfoResult.HasError())
{
GotoNonePage("擷取使用者資訊失敗,請重新擷取");
}
var userid = wxOperation.HasBind(GetUserInfoResult.openid);
if (userid.Equals(Guid.Empty))
{
Response.Redirect(Urls.Oauth2Url);
GotoNonePage("微信使用者未綁定");
}
appId = WxPayConfig.APPID;
timestamp = WxPayApi.GenerateTimeStamp();
nonceStr = WxPayApi.GenerateNonceStr();
//以下實作将在3、核心代碼實作 展現
var jsApi = new JsApi(this);
ResultJsData = jsApi.GetJsData();
WxJsApiParam = jsApi.GetJsApiParameters();//擷取H5調起JS API參數
}
}
}
2、将微信GPS坐标轉換為百度坐标
微信擷取坐标成功後,頁面自動跳轉到location1.aspx,處理流程如下:
微信坐标—>轉換為百度地圖坐标—>根據百度地圖API擷取位置資訊—>根據百度地圖API顯示坐标
<%@ Page Title="線上簽到" Language="C#" MasterPageFile="~/wxcrm/Site.Master" AutoEventWireup="true" CodeFile="location1.aspx.cs" Inherits="DTcms.Web.wxcrm.location1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="cphHead" runat="server">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
#allmap { width: 100%; height: 300px; }
</style>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=dhRLKMR9QUO4wHmnnSZTarta"></script>
<script type="text/javascript">
//GPS坐标
var yy = <%= this.Request["longitude"] %>; //經度,浮點數,範圍為180 ~ -180。
var xx = <%= this.Request["latitude"] %>; //緯度,浮點數,範圍為90 ~ -90
var gpsPoint = new BMap.Point(xx,yy);
var bxx = 0.0;
var byy = 0.0;
/*
* http://lbsyun.baidu.com/index.php?title=webapi/guide/changeposition
*/
var PositionUrl = "http://api.map.baidu.com/geoconv/v1/?";
function changePosition(){
var str = "coords="+yy+","+xx+"&from=1&to=5";
var url = PositionUrl + str;
$("#positionUrl").html(url+"&ak=dhRLKMR9QUO4wHmnnSZTartg");
var script = document.createElement('script');
script.src = url + '&ak=dhRLKMR9QUO4wHmnnSZTarta&callback=dealResult';
document.getElementsByTagName("head")[0].appendChild(script);
}
function dealResult(msg){
if(msg.status != 0){
alert("無正确的傳回結果。");
$("#mask").hide();
return;
}
//JsonUti.convertToString(msg);
bxx = msg.result[0].x;
byy = msg.result[0].y;
doOptions();
}
function getBaiduPosition() {
var url ="http://api.map.baidu.com/geoconv/v1/?coords="+yy+","+xx+"&from=1&to=5&ak=dhRLKMR9QUO4wHmnnSZTarta";
$.ajax({
url: url,
success: function(data,status,xhr) {
alert(status);
alert(data.status);
},
dataType: json
});
}
var ADVANCED_POST = '';
var advancedOptions = '';
var address;
var map;
function renderOption(response) {
var html = '';
if (response.status ) {
$("#mask").hide();
var text = "無正确的傳回結果!";
alert(text);
return;
}
var result = response.result;
var location = response.result.location;
var uri = 'http://api.map.baidu.com/marker?location='+ location.lat+','+location.lng +'&title='+response.result.level+'&content='+address+'&output=html';
var staticimageUrl = "http://api.map.baidu.com/staticimage?center=" + location.lng+','+location.lat + "&markers=" + location.lng+','+location.lat;
html = '<p>坐标:緯度: ' + location.lat + " 經度: " + location.lng+'<br />';
html += '精度: '+response.result.precise+'<br />' ;
html += '可信度: '+response.result.confidence +'<br />';
html += '位址類型: '+response.result.level+'</p>' ;
html += '<p><img src="' + staticimageUrl + '" /></p>' ;
html += '<p>分享該點: <a href="' + uri + '" target="_blank">' + uri + '</a></p>'; //将該連結設定成可單擊
// 百度地圖API功能
map = new BMap.Map("allmap");
var point = new BMap.Point(bxx, byy);
var marker = new BMap.Marker(point); // 建立标注
map.addOverlay(marker); // 将标注添加到地圖中
map.centerAndZoom(point, 100);
var opts = {
width: 200, // 資訊視窗寬度
height: 100, // 資訊視窗高度
title: "我的位置", // 資訊視窗标題
enableMessage: true,//設定允許資訊窗發送短息
message: result.formatted_address
}
$("#divPo").html("目前位置:" + result.formatted_address);
var infoWindow = new BMap.InfoWindow(result.formatted_address, opts); // 建立資訊視窗對象
marker.addEventListener("click", function () {
map.openInfoWindow(infoWindow, point); //開啟資訊視窗
});
var myIcon = new BMap.Icon("http://api.map.baidu.com/img/markers.png", new BMap.Size(23, 25), {
offset: new BMap.Size(10, 25), // 指定定位位置
imageOffset: new BMap.Size(0, 0 - 10 * 25) // 設定圖檔偏移
});
var pois = result.pois;
for(var i=0;i<pois.length;i++){
var marker = new BMap.Marker(new BMap.Point(pois[i].point.x,pois[i].point.y),{icon:myIcon}); // 建立标注
var name = pois[i].name;
var addr = pois[i].addr;
map.addOverlay(marker); // 将标注添加到地圖中
addClickHandler(name,addr,marker);
}
$("#mask").hide();
$("#btnSign").show();
return;
}
function addClickHandler(name,addr,marker){
marker.addEventListener("click",function(e){
openInfo(name,addr,e)}
);
}
function openInfo(name,addr,e){
var p = e.target;
var point = new BMap.Point(p.getPosition().lng, p.getPosition().lat);
var opts = {
width: 200, // 資訊視窗寬度
height: 100, // 資訊視窗高度
title: name, // 資訊視窗标題
enableMessage: true,//設定允許資訊窗發送短息
message: addr
}
var infoWindow = new BMap.InfoWindow(addr,opts); // 建立資訊視窗對象
map.openInfoWindow(infoWindow,point); //開啟資訊視窗
}
function doOptions() {
var script = document.createElement('script');
script.type = 'text/javascript';
ADVANCED_POST ="http://api.map.baidu.com/geocoder/v2/?ak=dhRLKMR9QUO4wHmnnSZTartg&callback=renderOption&location=" + byy + ","+bxx+ "&output=json&pois=2";
script.src = ADVANCED_POST;
document.body.appendChild(script);
};
$(function () {
$("#mask").show();
$("#btnSign").hide();
changePosition();
});
</script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="cphTitle" runat="server">
線上簽到
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="cphContainer" runat="server">
<form id="frmLocation" runat="server">
<div class="box mb50">
<div class="hd"><span>位置資訊</span></div>
<div class="bd" style="padding-left: 0">
<ul class="stipx" style="height: 300px;">
<div id="allmap"></div>
</ul>
</div>
<div class="bd" style="padding-left: 0">
<ul class="stipx">
<div id="divPo"></div>
</ul>
</div>
</div>
<div class="next_btn" style="text-align: center; margin-top: -50px;">
<input id="btnSign" type="button" value="我要簽到" style="cursor: pointer; width: 210px; height: 50px; border-radius: 15px; background-color: #00CD00; border: 0px #FE6714 solid; cursor: pointer; color: white; font-size: 16px;" />
</div>
<div class="mask" style="display: none;">
<span>
<img src="/templates/txwap/images/mask.gif" />
</span>
</div>
</form>
</asp:Content>
本頁面主要涉及到百度地圖開放平台,要申請百度地圖ag。否則調用js則提示:APP不存在,AK有誤請重新檢查在重試。
(1)百度地圖技術一:坐标轉換API
官網位址:http://lbsyun.baidu.com/index.php?title=webapi/guide/changeposition
API服務位址:http://api.map.baidu.com/geoconv/v1/?
文檔有詳細的說明,不再贅述哦。
(2)百度地圖技術二:根據坐标擷取位置
官網網址:http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding
Geocoding API包括位址解析和逆位址解析功能:地理編碼:即位址解析,由詳細到街道的結構化位址得到百度經緯度資訊,例如:“北京市海澱區中關村南大街27号”位址解析的結果是“lng:116.31985,lat:39.959836”。同時,地理編碼也支援名勝古迹、标志性建築名稱直接解析傳回百度經緯度,例如:“百度大廈”位址解析的結果是“lng:116.30815,lat:40.056885” ,通用的POI檢索需求,建議使用Place API。
逆地理編碼:即逆位址解析,由百度經緯度資訊得到結構化位址資訊,例如:“lat:31.325152,lng:120.558957”逆位址解析的結果是“江蘇省蘇州市虎丘區塔園路318号”。
API服務位址:http://api.map.baidu.com/geocoder/v2/
具體參數可檢視官方文檔。
示例:http://api.map.baidu.com/geocoder/v2/?ak=申請的百度KEY&location=34.79563,114.23075222912&callback=showLocation&output=xml&pois=1
(1)百度開發者key申請
(2)百度地圖坐标系統與微信的坐标系統不同
(3)api調用位址及參數說明
(4)api回調函數意義
(5)了解json與jsonp的含義,詳情檢視:http://kb.cnblogs.com/page/139725/
3、微信JS-SDK核心代碼
(1)JsAPI.cs生成相關JS-SDK配置參數
using System;
using System.Globalization;
using System.Linq;
using System.Web.Security;
using System.Web.UI;
using WxPayAPI;
namespace WxJsSDK
{
public class JsApi
{
/// <summary>
/// 儲存頁面對象,因為要在類的方法中使用Page的Request對象
/// </summary>
private Page page { get; set; }
public WxJsData ResultJsData { get; set; }
/// <summary>
///
/// </summary>
/// <param name="page"></param>
public JsApi(Page page)
{
this.page = page;
}
public WxJsData GetJsData()
{
var data = new WxJsData();
data.SetValue("appid", WxPayConfig.APPID);//公衆賬号ID
data.SetValue("timestamp", WxPayApi.GenerateTimeStamp());
data.SetValue("noncestr", WxPayApi.GenerateNonceStr());//随機字元串
var url = GetUrl();
data.SetValue("url", url);
var jsToken = GetJsApiTicket();
data.SetValue("jsapi_ticket", jsToken);
var signature = MakeSignature(jsToken, data.GetValue("noncestr").ToString(), data.GetValue("timestamp").ToString(), url);
data.SetValue("signature", signature);
ResultJsData = data;
return data;
}
private string MakeSignature(string jsapiTicket, string noncestr, string timestamp, string url)
{
string[] arrayList =
{
"jsapi_ticket=" + jsapiTicket,
"timestamp=" + timestamp,
"noncestr=" + noncestr,
"url=" + url
};
Array.Sort(arrayList);
var signature = string.Join("&", arrayList);
signature = FormsAuthentication.HashPasswordForStoringInConfigFile(signature, "SHA1").ToLower();
return signature;
}
private string GetJsApiTicket()
{
var jsAuth = new JsAuthorizeAction();
var token = jsAuth.GetToken();
var nd = DateTime.Now - token.CreateDate;
Log.Error(this.GetType().ToString(), token.access_token);
Log.Error(this.GetType().ToString(), token.IsValid().ToString());
if (token.IsValid())
return jsAuth.GetJsApiTicket(token.access_token).ticket;
return "";
}
private string GetUrl()
{
string host = page.Request.Url.Host;
string path = page.Request.Path;
string queryString = page.Request.Url.Query;
//這個地方要注意,參與簽名的是網頁授權擷取使用者資訊時微信背景回傳的完整url
string url = "http://" + host + path + queryString;
return url;
}
public string GetJsApiParameters()
{
Log.Debug(this.GetType().ToString(), "JsApi ::GetJsApiParam is processing...");
string parameters = ResultJsData.ToJson();
Log.Debug(this.GetType().ToString(), "Get JsApi : " + parameters);
return parameters;
}
}
}
(2)JsAuthorizeAction.cs微信JS-SDK相關API調用函數
using Payment.WxWebHlper;
using Payment.WxWebHlper.Results;
using System;
using WxPayAPI;
namespace WxJsSDK
{
public class JsAuthorizeAction
{
private static TokenResult Token = new TokenResult() { errcode = -1 };
private static JsApiTicketResult JsApiTicket = new JsApiTicketResult() { errcode = -1 };
public TokenResult GetToken()
{
Log.Error(this.GetType().ToString(), "GetToken");
if (!Token.IsValid())
{
Token = GeTokenResult();
Log.Error(this.GetType().ToString(), Token.ToString());
}
return Token;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public TokenResult GeTokenResult()
{
var result = new TokenResult();
try
{
var webUtils = new WebUtils();
var url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", WxPayConfig.APPID, WxPayConfig.APPSECRET);
var strRtn = webUtils.Get(url);
result = Tools.JsonStringToObj<TokenResult>(strRtn);
}
catch (Exception ex)
{
Log.Error(this.GetType().ToString(), ex.Message);
result = new TokenResult() { errcode = -1086 };
}
return result;
}
/// <summary>
///
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public JsApiTicketResult GetJsApiTicket(string token)
{
Log.Error(this.GetType().ToString(), "GetJsApiTicket傳入token:" + token);
if (!JsApiTicket.IsValid())
{
JsApiTicket = GetJsApiTicketResult(token);
}
return JsApiTicket;
}
/// <summary>
///
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public JsApiTicketResult GetJsApiTicketResult(string token)
{
JsApiTicketResult result;
try
{
var webUtils = new WebUtils();
var url = string.Format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi", token);
var strRtn = webUtils.Get(url);
result = Tools.JsonStringToObj<JsApiTicketResult>(strRtn);
}
catch (Exception ex)
{
Log.Error(this.GetType().ToString(), ex.Message);
result = new JsApiTicketResult() { errcode = -1086 };
}
return result;
}
}
public class JsApiTicketResult : ReturnResult
{
/// <summary>
/// 構造函數
/// </summary>
public JsApiTicketResult()
{
CreateDate = DateTime.Now;
}
/// <summary>
///
/// </summary>
public string ticket { get; set; }
/// <summary>
/// access_token接口調用憑證逾時時間,機關(秒)
/// </summary>
public int expires_in { get; set; }
/// <summary>
/// 建立時間
/// </summary>
public DateTime CreateDate { get; set; }
/// <summary>
/// 判斷是否有效
/// </summary>
/// <returns></returns>
public bool IsValid()
{
if (this.errcode != 0)
return false;
var nd = DateTime.Now - CreateDate;
return nd.Seconds < 7200;
}
}
public class TokenResult : ReturnResult
{
/// <summary>
/// 構造函數
/// </summary>
public TokenResult()
{
CreateDate = DateTime.Now;
}
/// <summary>
/// 網頁授權接口調用憑證,注意:此access_token與基礎支援的access_token不同
/// </summary>
public string access_token { get; set; }
/// <summary>
/// access_token接口調用憑證逾時時間,機關(秒)
/// </summary>
public int expires_in { get; set; }
/// <summary>
/// 建立時間
/// </summary>
public DateTime CreateDate { get; set; }
/// <summary>
/// 判斷是否有效
/// </summary>
/// <returns></returns>
public bool IsValid()
{
if (this.errcode != 0)
return false;
var nd = DateTime.Now - CreateDate;
return nd.Seconds < 7200;
}
}
}
(3)WxJsData.cs微信JS-SDK參數類
using LitJson;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
using WxPayAPI;
namespace WxJsSDK
{
public class WxJsData
{
private SortedDictionary<string, object> m_values = new SortedDictionary<string, object>();
/**
* 設定某個字段的值
* @param key 字段名
* @param value 字段值
*/
public void SetValue(string key, object value)
{
m_values[key] = value;
}
/**
* 根據字段名擷取某個字段的值
* @param key 字段名
* @return key對應的字段值
*/
public object GetValue(string key)
{
object o = null;
m_values.TryGetValue(key, out o);
return o;
}
/**
* 判斷某個字段是否已設定
* @param key 字段名
* @return 若字段key已被設定,則傳回true,否則傳回false
*/
public bool IsSet(string key)
{
object o = null;
m_values.TryGetValue(key, out o);
if (null != o)
return true;
return false;
}
/**
* @将Dictionary轉成xml
* @return 經轉換得到的xml串
* @throws WxPayException
**/
public string ToXml()
{
//資料為空時不能轉化為xml格式
if (0 == m_values.Count)
{
Log.Error(this.GetType().ToString(), "WxPayData資料為空!");
throw new WxPayException("WxPayData資料為空!");
}
string xml = "<xml>";
foreach (KeyValuePair<string, object> pair in m_values)
{
//字段值不能為null,會影響後續流程
if (pair.Value == null)
{
Log.Error(this.GetType().ToString(), "WxPayData内部含有值為null的字段!");
throw new WxPayException("WxPayData内部含有值為null的字段!");
}
if (pair.Value.GetType() == typeof(int) || pair.Value.GetType() == typeof(decimal))
{
xml += "<" + pair.Key + ">" + pair.Value.ToString() + "</" + pair.Key + ">";
}
else if (pair.Value.GetType() == typeof(string))
{
xml += "<" + pair.Key + ">" + "<![CDATA[" + pair.Value + "]]></" + pair.Key + ">";
}
else//除了string和int類型不能含有其他資料類型
{
Log.Error(this.GetType().ToString(), "WxPayData字段資料類型錯誤!");
throw new WxPayException("WxPayData字段資料類型錯誤!");
}
}
xml += "</xml>";
return xml;
}
/**
* @将xml轉為WxPayData對象并傳回對象内部的資料
* @param string 待轉換的xml串
* @return 經轉換得到的Dictionary
* @throws WxPayException
*/
public SortedDictionary<string, object> FromXml(string xml)
{
if (string.IsNullOrEmpty(xml))
{
Log.Error(this.GetType().ToString(), "将空的xml串轉換為WxPayData不合法!");
throw new WxPayException("将空的xml串轉換為WxPayData不合法!");
}
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
XmlNode xmlNode = xmlDoc.FirstChild;//擷取到根節點<xml>
XmlNodeList nodes = xmlNode.ChildNodes;
foreach (XmlNode xn in nodes)
{
XmlElement xe = (XmlElement)xn;
m_values[xe.Name] = xe.InnerText;//擷取xml的鍵值對到WxPayData内部的資料中
}
try
{
//2015-06-29 錯誤是沒有簽名
if (m_values["return_code"] != "SUCCESS")
{
return m_values;
}
CheckSign();//驗證簽名,不通過會抛異常
}
catch (WxPayException ex)
{
throw new WxPayException(ex.Message);
}
return m_values;
}
/**
* @Dictionary格式轉化成url參數格式
* @ return url格式串, 該串不包含sign字段值
*/
public string ToUrl()
{
string buff = "";
foreach (KeyValuePair<string, object> pair in m_values)
{
if (pair.Value == null)
{
Log.Error(this.GetType().ToString(), "WxPayData内部含有值為null的字段!");
throw new WxPayException("WxPayData内部含有值為null的字段!");
}
if (pair.Key != "sign" && pair.Value.ToString() != "")
{
buff += pair.Key + "=" + pair.Value + "&";
}
}
buff = buff.Trim('&');
return buff;
}
/**
* @Dictionary格式化成Json
* @return json串資料
*/
public string ToJson()
{
string jsonStr = JsonMapper.ToJson(m_values);
return jsonStr;
}
/**
* @values格式化成能在Web頁面上顯示的結果(因為web頁面上不能直接輸出xml格式的字元串)
*/
public string ToPrintStr()
{
string str = "";
foreach (KeyValuePair<string, object> pair in m_values)
{
if (pair.Value == null)
{
Log.Error(this.GetType().ToString(), "WxPayData内部含有值為null的字段!");
throw new WxPayException("WxPayData内部含有值為null的字段!");
}
str += string.Format("{0}={1}<br>", pair.Key, pair.Value.ToString());
}
Log.Debug(this.GetType().ToString(), "Print in Web Page : " + str);
return str;
}
/**
* @生成簽名,詳見簽名生成算法
* @return 簽名, sign字段不參加簽名
*/
public string MakeSign()
{
//轉url格式
string str = ToUrl();
//在string後加入API KEY
str += "&key=" + WxPayConfig.KEY;
//MD5加密
var md5 = MD5.Create();
var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
var sb = new StringBuilder();
foreach (byte b in bs)
{
sb.Append(b.ToString("x2"));
}
//所有字元轉為大寫
string result = sb.ToString().ToUpper();
return result;
}
public string MakeAppSign()
{
//轉url格式
string str = ToUrl();
//在string後加入API KEY
str += "&key=" + WxPayConfig.KEYofAPP;
//MD5加密
var md5 = MD5.Create();
var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
var sb = new StringBuilder();
foreach (byte b in bs)
{
sb.Append(b.ToString("x2"));
}
//所有字元轉為大寫
string result = sb.ToString().ToUpper();
return result;
}
/**
*
* 檢測簽名是否正确
* 正确傳回true,錯誤抛異常
*/
public bool CheckSign()
{
//如果沒有設定簽名,則跳過檢測
if (!IsSet("sign"))
{
Log.Error(this.GetType().ToString(), "WxPayData簽名存在但不合法!");
throw new WxPayException("WxPayData簽名存在但不合法!");
}
//如果設定了簽名但是簽名為空,則抛異常
if (GetValue("sign") == null || GetValue("sign").ToString() == "")
{
Log.Error(this.GetType().ToString(), "WxPayData簽名存在但不合法!");
throw new WxPayException("WxPayData簽名存在但不合法!");
}
//擷取接收到的簽名
string return_sign = GetValue("sign").ToString();
//在本地計算新的簽名
string cal_sign = MakeSign();
if (cal_sign == return_sign)
{
return true;
}
Log.Error(this.GetType().ToString(), "WxPayData簽名驗證錯誤!");
throw new WxPayException("WxPayData簽名驗證錯誤!");
}
/**
* @擷取Dictionary
*/
public SortedDictionary<string, object> GetValues()
{
return m_values;
}
}
}
提示資訊:相關解析思路可參考微信公衆号支付官方SDK,下載下傳位址:https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=11_1。
提示:承接微信應用開發,有意者QQ聯系2339698190