• 微信JS-SDK坐标位置转换为百度地图坐标


    微信JS-SDK开发过程中,使用getLocation获取坐标位置,如何将微信获取的坐标直接应用到百度地图中,显示以下效果:

    IMG_7621

    说明:红色图标是从微信转换过来的位置,蓝色图标是周边位置。首先从微信开发流程讲解。

    1、微信JS-SDK开发文档

    首先进入官网的帮助文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN

    可对文档进行详细的研读,要获取位置信息,分以下步骤:

    第一步:绑定域名

    进入微信公众号,找到“公众号设置”菜单,进入“功能设置”面板,

    image

    点击“设置”可设置引用js的相关域名:

    image

    第二步:引用官方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=" 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>
    页面效果:

    IMG_7622IMG_7623

    注意事项:

    (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 = {
                     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 = {
                     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;  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/?

    image

    文档有详细的说明,不再赘述哦。

    (2)百度地图技术二:根据坐标获取位置

    官网网址:http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding

    geocoding.png

    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

    image

    注意事项:

    (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

    image

    提示:承接微信应用开发,有意者QQ联系2339698190

  • 相关阅读:
    python 冒泡排序
    数组
    git用法
    Leetcode 344. 反转字符串
    Leetcode 83. 删除排序链表中的重复元素
    【第一部分】01Leetcode刷题
    【C++ Primer | 07】常用算法
    【第一部分】10Leetcode刷题
    【第一部分】09Leetcode刷题
    【第一部分】07Leetcode刷题
  • 原文地址:https://www.cnblogs.com/zsy/p/5492799.html
Copyright © 2020-2023  润新知