2017-03-27 13:28:41 caojie1008 阅读数 13650

微信小程序之解析XML数据

前言

博主本是Android开发者,由于公司业务需要开发一个微信小程序,起初并没有太在意解析XML这个问题,因为小程序是用的JS,所以直接用DOMParser解析就好了嘛,而且在微信开发者工具上也是能正常跑的,然后问题来了,部署到iphone7上运行的时候报了“thirdScriptError Can’t find variable:DOMParser”错误,What???,于是找了资料发现小程序不支持DOM,所以只能用第三方库去解析了,本文就告诉大家如何使用xmldom在小程序中解析XML。

准备工作

  • 下载xmldom库:https://github.com/jindw/xmldom
  • 新建一个lib文件夹,将dom.js、dom-parser.js、sax.js拷贝到里面
  • 将建好的lib文件夹放入项目中(与pages、utils平级)

示例

  • 1.在你需要解析的地方导入lib/xmldom/dom-parser

这里写图片描述

  • 2.为了demo方便,我随便虚拟一段XML文本,然后直接在onLaunch中解析 ,并输出解析结果

这里写图片描述

  • 3.打印的log如下:
  • userIdElement:1002
  • securityToken:1002-347365147-1001

这里写图片描述

部署到iphone7

  • 微信开发者工具-项目-预览-打开手机微信扫码
  • 手机微信-发现-小程序-YouApp-右上角菜单-打开调试

这里写图片描述

结束

希望本文能帮助大家,另外网上关于小程序的例子还比较少,请帮忙顶一下或评论一下或转发一下让更多的开发者能够解决问题,感谢!
最后要谢谢“初雪”给予我的帮助

2019-03-27 22:11:17 CSDN_XUWENHAO 阅读数 168

WXML(WeiXin Markup Language)是框架设计的一套标准语言,用于渲染界面,WXML的渲染原理和React Native思路一致,通过一套标记语言,在不同平台被解析为不用端的渲染文件,如图:

使用微信开发者工具时,在WXML中编写一些HTML标签或自定义标签仍然会被正常解析,这会给开发者造成一种小程序能直接支持HTML标签的误解。这是因为微信开发者工具内核是浏览器内核,同时小程序框架并没对WXML中的标签和WXSS中的内容进行强验证,所以HTML和CSS能直接被解析,但这种不合法的WXML在手机端微信中是不能正常显示的。开发过程中我们异地杠幺拿真机进行测试,保证程序能正常运行。WXML具有数据绑定、列表渲染、条件渲染、模板、事件等能力。

1.数据绑定

小程序中页面渲染时,框架会将WXML文件同时对应Page的data进行绑定,在页面中我们可以直接使用data中的属性。小程序的数据绑定使用Mustache语法(双大括号{{}})将变量或简单的运算规则抱起来,主要由以下几种渲染方式:

1)简单绑定

简单绑定是指我们使用Mustache语法(双大括号{{}})将变量包起来,在模板中直接作为字符串输出使用,可作用于内容、组件属性、控制属性、关键字等输出,其中关键字输出是将JavaScript中的关键字按其真值输出。

示例代码如下:

<view>{{content}}</view>
<view id='item-{{id}}' style='border:{{border}}'>作为属性渲染</view>
<view wx:if="{{showContent}}">作为属性渲染</view>
<view>{{2}}</view>
<checkbox checked='{{false}}'></checkbox>
Page({
  data: {
    border:'solid 1px #000',
    id:1,
    content:'内容',
    showContent:false 
  }
})

运行效果如下:

注意:组件属性为boolean类型时,不要直接写checked ="false",这样checked的值时一个false的字符串,转成boolean类型后代表为true,所以这种情况一定要使用关键字输出:checked="{{false}}"

2)运算

在{{}}内可以做一些简单的运算,支持的运算有三元运算、算术运算、逻辑判断、字符串运算,这些运算均符合JavaScript运算规则,示例如下:

Page({
  data: {
    showContent:false,
    num1:1,
    num2:2,
    num3:3,
    name:'weixin',
    myObject:{
      age:12
    },
    myArray:['arr1','arr2']
  }
});
<view>{{showContent ?'显示文本':'不显示文本'}}</view>
<view>{{num1+num2}}+1+{{num3}}=?</view>
<view>{{"name:"+name}}</view>
<view>{{num3>0}}</view>
<view>{{myObject.age}}{{myArray[1]}}</view>

执行结果如下:

3)组合

data中的数据可以在模板再次组合成新的数据结构,这种组合常常在数组或对象中使用,数组组合比较简单,可以直接将值放置到数组某个下标下:

<view>{{[myValue,2,3,'stringtype']}}</view>
Page(
  {
    data:{
      myValue:0
    }
  }
)

输出结果为:

对象组合有3种组合方式,这里我们以数据注入模板为例

第一种,直接将数据作为value值进行组合:

<template is="testTemp" data="{{name:myvalue1,age:myvalue2}}"></template>
Page(
  {
    data: {
      myValue1: 'value1',
      myValue2: 'value2'
    }
  }
)

最终组合成的对象为:{name:'vaue1',age:'value2'}

第二种,通过“...”将一个对象展开,把key-value值拷贝到新的结构中:

<template is ="testTemp" data="{{...myObj1,key5:5,...myObj2,key6:6}}"></template>
Page({
    data:{
        myObj1:{
            key1:1,
            key2:2
            },
        myObj2:{
            key3:3,
            key4:4
        }
    }
});

最终组合成的对象为:{key1:1,key2:2,key5:5,key3:3,key4:4,key6:6}

第三种,如果对象key和value相同,可以只写key值:

<template is="testTemp" data="{{key1,key2}}"></template>
Page({
    data:{
        key1:1,
        key2:2
}
});

最后的组合对象为:{key1:1,key2:2}

如果一个组合中有相同的属性名时,后面的属性将会覆盖前面的属性,如:

<template is="testTemp" data="{{...myObj,key1:3}}"></template>
Page({
    data:{
        key1:1,
        key2:2
}
});

最后的组合对象为:{key1:3,key2:2}

2.条件渲染

1)wx:if

除了简单的数据绑定,我们常常会使用逻辑分支,这时候可以使用wx:if="{{判断条件}}"来进行条件渲染,当条件成立时渲染该块代码:

<view wx:if="{{showContent}}">内容</view>
Page({
  data:{
    showContent:true /*若未false则不显示Content*/
  }
});

执行结果如下:

 

和普通的编程语言一样,WML也支持wx:elif和wx:else,如:

<view wx:if="{{false}}">1</view>
<view wx:elif="{{false}}">2</view>
<view wx:else>3</view>

2)block wx:if

wx:if是一个控制属性,可以添置在任何组件标签上,但如果我们需要包装多个组件,又不想影响布局,这时就需要使用<block/>标签将需要包装的组件放置在里面,通过wx:if做判断。<block/>不是一个组件,仅仅是一个包装元素,页面渲染过程中不做任何渲染,由属性控制,如下所示:

<block wx:if="{{true}}">
  <view>view组件</view>
  <image></image>
</block>

3)wx:if与hidden

除了wx:if组件,也有了通过hidden属性控制组件是否显示,开发者难免有疑问,这两种方式该怎样取舍,这里我们整理了两种方式的区别:

  • wx:if控制是否渲染条件块内的模板,当其条件值切换时,会触发布局渲染以确保条件快在切换时销毁或重新渲染。wx:if是惰性的,如果在初始渲染条件为false时,框架将生命也不做,在条件第一次为真时才局部渲染
  • hidden控制组件是否显示,组件始终会被渲染,只是简单控制显示与隐藏,并不会触发重新渲染和销毁。

在频繁切换状态的场景中,会产生更大的消耗,这时尽量使用hidden;

在运行时条件变动不大的场景中我们使用wx:if,这样能保证页面有更高效的渲染,而不用把所有组件渲染出来。

3.列表渲染

1)wx:for

组件的wx:for控制属性用于遍历数组,重复渲染该组件,遍历过程中当前项的下标变量名默认为index,数组当前项变量名默认为item,如:

<view wx:for="{{myArray}}">
{{index}}:{{item}}
</view>
Page({
  data:{
    myArray:['value1','value2']
  }
});

执行结果如下:

2)wx:for-index和wx:for-item的变量名修改

index、item变量名可以通过wx:for-index、wx:for-item属性修改,如:

<view wx:for="{{myArray}}"wx:for-index="myIndex"wx:for-item="myItem">
{{myIndex}}:{{myItem.name}}
</view>
Page({
  data:{
    myArray:[
      {name: 'value1'},
      {name: 'value2'}
    ]
  }
});

执行结果如下:

普遍遍历中我们没必要修改index、item变量名,当wx:for嵌套使用时,就有必要设置变量名,避免变量名冲突,下面我们遍历一个二维数组:

<view wx:for="{{myArray}}" wx:for-index="myIndex" wx:for-item="myItem">
<block wx:for="{{myItem}}" wx:for-index="subIndex" wx:for-item="subItem">{{subItem}}
</block>
</view>
Page({
  data:{
    myArray:[
     [1,2,3],
     [4,5,6],
     [7,8,9]
    ]
  }
});

执行结果如下:

在本示例中,我们使用了<block/>标签,和block wx:if一样,wx:for可以直接在<block/>标签上使用,以渲染一个包含多个节点的结构快。

4.模板

在项目过程中,常常会遇到某些相同的结构在不同的地方反复出现,这时可以将相同的布局代码片段放置到一个模板中,在不同的地方传入到对应的数据进行渲染,这样能避免重复开发,提升开发效率。

1)定义模板

定义模板非常简单,在<template/>内定义代码片段,设置<template/>的name属性,指定模板名称即可。如:

<template name="myTemplate">
    <view>内容</view>
    <view>{{content}}</view>
</template>

2)使用模板

使用模板时,设置is属性指定需要使用的模板,设置data属性,将模板所需的变量传入。模板拥有自己的作用域,只有使用data属性传入数据,而不是直接使用Page中的data数据,渲染时,<template/>标签将被模板中的代码块完全替换

示例代码如下:

<template name="myTemplate">
    <view>内容</view>
    <view>{{content}}</view>
    <view>{{name}}</view>
    <view>{{myObj.key1}}</view>
    <view>{{key2}}</view>
</template>
<template is="myTemplate" data="{{content:'内容',name,myObj,myObj2}}"/>
Page({
  data:{
    name:'myTemplate',
    myObj:{
      key1:'value1'
    },
    myObj2:{
      key2:'value2'
    }
  }
});

执行结果如下:

模板可以嵌套使用:

<template name="bTemplate">
  <view>b tempalte content</view>
</template>
<template name="aTemplate">
  <view>a template content</view>
  <template is="bTemplate"/>
</template>
<template is="aTemplate"/>

执行结果如下:

注意:模板is属性支持数据绑定,在项目过程中我们可以通过属性绑定动态决定使用哪个模板,如:

<template is="{{templateName}}" data="myData"/>

5.事件

 

WXML中的事件系统和HTML中DOM事件系统极其相似,也是通过在组件上设置“bind(或catch)+事件名”属性进行事件绑定,当触发事件时,框架会调用逻辑层中对应的事件处理函数,并将当前状态通过参数传递给事件处理函数,由于小程序中没有DOM节点概念,所以事件只能通过WXML绑定,不能通过逻辑层动态绑定。官方对WXML事件的定义如下:

  • 事件是视图层到逻辑层的通讯方式
  • 事件可以将用户的行为反馈到逻辑层进行处理
  • 书简可以绑定在组建上,当触发事件时,就会执行逻辑层中对应的事件处理函数
  • 事件对象可以携带额外信息,如id、dataset、touches

1)事件分类

  • 冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递
  • 非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递

有前端开发经验的开发者应该对事件冒泡都有一定了解,当一个事件被触发后,该事件会沿该组件向其父级对象传播,从里到外依次执行,直到节点最顶层,这个是个非常有用的特性,通常用于实现事件代理,具体实现方案将在下文中具体讨论。

WXML冒泡事件如下:

  • touchstart:手指触摸动作开始
  • touchmove:手指触摸后移动
  • touchcancel:手指触摸动作被打断,如来电提醒、弹窗
  • touchend:手指触摸动作结束
  • tap:手指触摸后马上离开
  • longtap:手指触摸后,超过350ms再离开

 

对于冒泡事件每个组件都是默认支持的,除上述事件之外的其他组件自定义事件如无特殊声明都是非冒泡事件,如:<form/>的submit事件,<scroll-view/>的scroll事件,详细信息请参考各组件文档。

2)事件绑定

在之前内容中,已经多次实现事件绑定,事件绑定的写法和组件属性一样,以key、value形式组织

  • key:以bind或catch开头,然后跟上事件类型,字母均小写,如:bindtap,catchtouchstart
  • value:事件函数名,对应Page中定义的同名函数。找不到同名函数会导致报错

绑定时bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定会阻止冒泡事件向上冒泡

冒泡示例如下:

<view bindtap='tap1'>
view1
<view catchtap='tap2'>
view2
<view bindlongtap='tap3'>
view3
</view>
</view>
</view>

如上述示例中,点击view3时会先触发tap3和tap2事件,有view2他用过catch阻止了tap事件冒泡,这时tap1将不会执行,点击view2只触发tap2,点击view1只触发tap1

3)事件对象

如果没有特殊说明,当组件触发事件时,逻辑层绑定该事件的事件处理函数会收到一个事件对象,如:

<view bindtap='myevent'>view</view>
Page({
myevent:function(e){
  console.log(e);
}
});

上述代码中,myevent参数e便是事件对象,这和JavaScript事件绑定特别像,上述代码执行后事件对象输出如下:

事件对象属性基本可以分为三类:BaseEvent、CustomEvent、TouchEvent

BaseEvent为基础事件对象属性,包括:

  • type:事件类型
  • timeStamp:事件生成时的时间戳,页面打开到触发所经过的毫秒数
  • target:触发事件源组件(即冒泡开始的组件)的相关属性集合,属性如下:
  1. id:事件源组件的id
  2. tagName:事件源组件的类型
  3. dataset:事件源组件上由data-开头的自定义属性组成的集合
  • currentTarget:事件绑定的当前组件的相关属性集合,属性如下:
  1. id:事件源组件的id
  2. tagName:当前组件的类型
  3. dataset:当前组件上由data-开头的自定义属性组成的集合

<canvas/>中的触摸事件不可冒泡,所以没有currentTarget

dataset是组件的自定义数据,通过这种方式可以将组件的自定义属性传递给逻辑层。书写方式为:以data-开头,多个单词由连字符“-”连接,属性名不能有大写(大写最终会被转为小写),最终在dataset中将连字符专程驼峰形式如:

Page({
myevent:function(e){
  console.log(e.currentTarget.dataset);
}
});
<view bindtap='myevent' data-my-name="weixin" data-myAge="12">
  dataset示例
</view>

执行结果如下:

CustomEvent为自定义事件对象(继承BaseEvent),只有一个属性:

  • detail:额外信息,通常传递数组特殊信息

detail没有统一格式,在<form/>的submit方法中它是{"vaue":{},"formid":""},在<swiper/>的change事件中它是{"current":current},具体内容参考组件相关文档。

TouchEvent为触摸事件对象(继承BaseEvent)属性如下所示:

  • touches:触摸事件,当前停留在屏幕中的触摸点信息的数组
  • changedTouched:触摸事件,当前变化的触摸点信息的数组,如从无变有(touchstart)、位置变化(touchmove)、从有变无(touchend、touchcancel)

由于支持多点触摸,所有touched和changedTouched都是数组格式,每个元素为一个Touch对象(canvas触摸事件中为CanvasTouch对象)

Touch对象相关属性如下:

  • identifier:触摸点的标识符
  • pageX,pageY:距离文档左上角的距离,文档的左上角为原点,横向为X轴,纵向为Y轴
  • clientX,clientY:距离页面可显示区域(屏幕除去导航条)左上角的距离,横向为X轴,纵向为Y轴

CanvasTouch对象相关属性如下:

  • identifier:触摸点的标识符
  • x、y:距离Canvas左上角的距离,Canvas的左上角为原点,横向为X轴,纵向为Y轴

6.引用

一个WXML可以通过Import或include引入其他WXML文件,两种方式都能引入WXML文件,区别在于import引入WXML文件后只接受模板定义,忽略模板定义之外的所有内容,而且使用过程中有作用域的概念,与improt相反,include则是引入文件中除<templaet/>以外的代码直接拷贝到<include/>位置,整体来说Import是引入模板定义,include是引入组件

1)import

<import/>的src属性是需要被引入文件的相对地址,<import/>引入会忽略引入文件中<template/>以外的内容,如下:

<import src="b.wxml"/>
<template is="bTemplate" data=""/>  <!--使用b.wxml中定义的模板-->
<view>内容</view> <!--import引用时会被忽略-->
<temmplate name="bTemplate">
<view>b Template content</view>
</template>
<template is="bTemplate"/> <!--import引用时会被忽略-->

import引用有作用域概念,只能直接使用引入的模板,而不能使用间接引入的定义模板,如下例:

<import src="b.wxml"/>
<template is="bTemplate"/>
<template is="cTemplate"/>    <!--不能直接调用c.wxml中的模板-->
<import src="c.wxml"/>
<view>b content</view>      <!--import时被忽略-->
<template name="bTemplate">
  <template is="cTemplate"/>
  <view>b tempalte conteng</view>
</template>
<template is="cTemplate"/>    <!--import时被忽略-->
<template name="cTemplate">
  <view>c template content</view>
</template>

2)include

include引入会将模板定义标签外的内容(含模板使用标签)直接赋值替换<include/>,我们基于上个案例进行修改,大家可以对比一下:

<include src="b.wxml"/>
<template is="bTemplate"/>  <!--不能调用b.wxml中的模板-->
<template is="cTemplate"/>    <!--不能调用c.wxml中的模板-->
<import src="c.wxml"/>
<view>b content</view>      <!--不会被忽略-->
<template name="bTemplate">
  <template is="cTemplate"/>   <!--不会调用c.wxml中的模板,引用时已经被忽略-->
  <view>b tempalte conteng{{name}}</view>
</template>
<template is="bTemplate" data="{{name}}"/> <!--没有被忽略,能正常调用自己文件中的模板-->
<template name="cTemplate">
  <view>c template content</view>
</template>

Page({
  data:{
    name:2 /**将数据注入到b.wxml中 */
  }
})

通过对比发现,Import更适合引用模板定义文件,include更适合引入组件文件,在项目中大家可以根据特性灵活使用。

2019-04-07 16:46:18 Abysscarry 阅读数 15429

背景:
过年前后做了个微信公众号项目,已经过去一段时间了,抽空回忆总结下基本流程吧,不然很快估计自己就忘了。。

微信公众平台官网:https://mp.weixin.qq.com



一、注册公众号

在这里插入图片描述
首先注册时可以看到公众号有三种类型,个人用户大多数选择订阅号,而企业用户一般选择服务号和企业号

我们平常大多数关注的都是订阅号,他们统一都放置在微信应用的订阅号消息列表中,没有微信支付等高级功能,只是用于发布文章等基础功能。
在这里插入图片描述

服务号企业号都在会话列表,和我们的微信好友是同级别的位置,具备微信支付等高级功能,一般是某个企业品牌的对外操作窗口,如海底捞火锅、顺丰速运等。
在这里插入图片描述

我们前期开发测试只需要注册个人订阅号即可,真正开发使用的是开发者工具里的测试号,具体下面会说。

真正生产的话,使用的都是经过微信认证的订阅号、服务号、企业号。


二、了解公众号管理页面

我们在微信公众平台扫码登录后可以发现管理页面左侧菜单栏有丰富的功能:
在这里插入图片描述
大概可以分为这几大模块:
首页功能小程序管理推广统计设置开发

作为开发人员,首先应该关注的是设置、开发模块;而作为产品运营人员,关注的是功能、管理、推广模块;作为数据分析人员,关注的是统计模块。

首先我们不妨各个功能模块都点击看一看,大概了解下我们能做些什么。可以确认的是,这个微信公众平台当然不只是给开发人员使用的,它提供了很多非技术人员可在UI界面上交互操作的功能模块。

如配置消息回复、自定义菜单、发布文章等:
在这里插入图片描述
这个时候我们可能会想:这些功能好像非技术人员都能随意操作,那么还需要我们技术人员去开发吗?

答案是: 如果只是日常简单的推送文章,就像我们关注的大多数公众号一样,那确实不需要技术人员去开发;但是,如果你想将你们的网站嵌入进去公众号菜单里(这里指的是把前端项目的首页链接配置在自定义菜单),并且实现微信端的独立登录认证、获取微信用户信息、微信支付等高级功能,或者觉得UI交互的配置方式无法满足你的需求,你需要更加自由、随心所欲的操作,那么我们就必须启用开发者模式了,通过技术人员的手段去灵活控制公众号。

这里有一点需要注意,如果我们决定技术人员开发公众号,必须启用服务器配置,而这将导致UI界面设置的自动回复和自定义菜单失效!

我们在 开发 - 基本配置 - 服务器配置 中点击启用
在这里插入图片描述
在这里插入图片描述
我们团队就遇到过这种情况:两个项目组共用一个公众号,结果一个启用了服务器配置,使另一个项目组手动配置的菜单失效了。所以要注意这点!

至于服务器配置中的选项代表什么意思、如何填写,我们下面再讲。


三、必备开发者工具的使用

在这里插入图片描述
我们进入 开发 - 开发者工具, 可以发现微信提供了六种开发者工具,其中前四种属于开发必备:开发者文档在线接口调试工具web开发者工具公众平台测试账号

1.开发者文档

在这里插入图片描述
这个不用说!在我们开发中属于最最最基础和重要的东西了,我们要想熟练开发公众号,首先必须熟读开发者文档!有些功能的开发甚至非要反复研读、咬文嚼字一番不可。PS:该文档吐槽的地方也不少,有些地方的确讲的不够明确!

2.在线接口调试工具

在这里插入图片描述
这个工具也算比较实用,包含大多数接口的在线调试,我们可以直接在上面输入参数,获取微信服务端的返回结果。

3.web开发者工具

在这里插入图片描述
这个工具是一款桌面应用,需要下载,它通过模拟微信客户端的UI使得开发者可以使用这个工具方便地在PC或者Mac上进行开发和调试工作,一般是前端使用该工具进行页面、接口调试。

4.公众平台测试账号

在这里插入图片描述
这个测试号工具对我们的重要性可以说是仅次于开发者文档。我们可以创建测试号无需申请、认证真实的公众帐号、可在测试帐号中体验并测试微信公众平台所有高级接口。并且所有的配置都可在一个页面上编辑,使开发测试变得极其便利。


四、细读开发者文档

文档地址:https://mp.weixin.qq.com/wiki

需要注意的是,细读开发者文档不是让你所有模块都去阅读,而是重点的重复细读,非重点的选择性阅读。
在这里插入图片描述
其中前两个模块:开始前必读开始开发,属于重点关注对象,也是整个微信开发的基石所在,需要多读几遍。其次是微信网页开发模块微信网页授权,比较难理解,需要特别注意。其他的模块则根据你们的项目功能需求,有选择性的阅读即可。

这里我就不多罗嗦了,大家看文档去吧!下面我会描述一些重点内容的实际操作情况以及代码,请确保你已经浏览过文档


五、开发流程重点解析


1.开发环境准备

这里所谓的开发环境准备主要指的是我们项目服务端和微信服务端的网络通讯环境准备。

我们平常开发可能只需要IP端口就能通讯,顶多配置下白名单放行,但微信公众号开发我们需要通过域名通讯(微信会访问我们配置的域名地址:服务器基本配置中的URL,下面会介绍),也就是我们各自开发环境需要拥有独立的域名,微信就能通过这个域名请求到我们的本地开发服务,各自进行开发测试。

而我们一般都是内网开发,整个内网只有一个对外域名,所以这时就需要 内网穿透 ,为我们每个开发人员配置各自开发机器的域名。

那如何进行内网穿透呢?你首先可以找下你们的网管,看他能不能帮你解决,如果不能,那就安装内网穿透工具,我们自己动手!

我选择的内网穿透工具是natapp,这个有免费版、收费版,免费版的域名会随机变化,而收费版可以拥有固定域名,建议选择收费版,9元每月并不贵;大家可以对照natapp的文档安装使用,并不难。
在这里插入图片描述
这样我们本地开发环境就拥有自己的域名啦!然后就可以在测试号管理页面配置本地访问地址URL了。

2.服务器基本配置

无论是在真实公众号开发 - 基本配置 - 服务器配置,还是在 测试号管理 中,我们都可以看到这几个基本参数:
开发者ID(AppID)、开发者密码(AppSecret)、服务器地址(URL)、令牌(Token)

AppID 是公众号唯一开发识别码,配合开发者密码可调用公众号的接口能力,大多数微信接口都需要附带该参数。

AppSecret 是校验公众号开发者身份的密码,具有极高的安全性。切记勿把密码直接交给第三方开发者或直接存储在代码中。如需第三方代开发公众号,请使用授权方式接入。其中获取accessToken就需要同时传入AppID和AppSecret获取。

URL 是开发者用来接收微信消息和事件的接口URL,也就是我们服务后端的入口地址,需要注意的是该地址必须以域名形式填写,且必须以http 或 https 开头,分别支持80端口和443端口。如:http://yuanj.natapp1.cc/wechat。

Token 可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性),也就是我们项目和微信服务端进行通信时,必须保证公众平台配置的Token和我们后台代码配置的Token保持一致,这样微信就能验证我们身份。

注:EncodingAESKey 参数由开发者手动填写或随机生成,将用作消息体加解密密钥,我们前期可以采用明文模式进行开发测试,暂时先不用关注。
在这里插入图片描述
我们点击提交时,微信会以GET请求的方式访问我们配置的URL地址,并附加几个参数进行验证,所以你需要在该地址对应的项目后端接口里对这几个参数进行加工处理返回微信需要的结果,这样就可以验证成功,使微信服务端认可你配置的URL和Token参数,后续就能互相通信了!
在这里插入图片描述
具体情况可以阅读微信文档 - 开始前必读 - 接入指南

这里附上该接口的Java代码:

/**
 * 微信对接验证接口
 * */
@RestController
@RequestMapping(value = "/wechat")
public class ValidateController {
    @Autowired
    WechatConfig wechatConfig;

   @RequestMapping(value = "", method = RequestMethod.GET)
   public void validate(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("-----开始校验签名-----");

        // 接收微信服务器发送请求时传递过来的参数
        String signature = req.getParameter("signature");
        String timestamp = req.getParameter("timestamp");
        String nonce = req.getParameter("nonce"); //随机数
        String echostr = req.getParameter("echostr");//随机字符串

        // 将token、timestamp、nonce三个参数进行字典序排序并拼接为一个字符串
        String TOKEN = wechatConfig.getToken();
        String sortStr = sort(TOKEN,timestamp,nonce);
        
        // 字符串进行shal加密
        String mySignature = WechatUtils.shal(sortStr);
        
        // 校验微信服务器传递过来的签名 和  加密后的字符串是否一致, 若一致则签名通过
        if(!"".equals(signature) && !"".equals(mySignature) && signature.equals(mySignature)){
            System.out.println("-----签名校验通过-----");
            try {
                resp.getWriter().write(echostr);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else {
            System.out.println("-----校验签名失败-----");
        }
    }
    
   /**
     * 参数排序
     * @param token
     * @param timestamp
     * @param nonce
     * @return
     */
    public static String sort(String token, String timestamp, String nonce) {
        String[] strArray = {token, timestamp, nonce};
        Arrays.sort(strArray);
        StringBuilder sb = new StringBuilder();
        for (String str : strArray) {
            sb.append(str);
        }
        return sb.toString();
    }
}


3.存取access_token参数

access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时(7200秒),需定时刷新重复获取将导致上次获取的access_token失效

access_token这个参数非常重要,几乎贯穿整个微信公关号项目开发,我们如何在有效期内定时刷新获取呢?
如果我们的微信公众号项目是单服务架构,可以直接作为静态变量存储在内存里;如果是多服务,可以用中间件存储Redis、数据库都可以。SpringBoot项目内部可以通过@Scheduled注解,执行定时任务,既然access_token有效期是2小时,那我们可以一小时刷新获取一次,将其存入Redis,覆盖之前的access_token。


4.公众号消息管理

在这里插入图片描述
很多公众号都可以通过消息发送来与其进行交互,那这样的功能如何代码实现呢?

具体我们可以在微信文档 - 消息管理 模块查阅:
在这里插入图片描述
在此我要提到的一点就 微信公众号的消息交互都是通过XML格式进行的!这点就很坑了。。现在我们前后端、服务端的消息传输基本都是Json格式了,也习惯了Json格式的解析处理,所以遇到XMl格式的处理又要多费些事了。

为什么微信采用XML格式呢?我个人猜测是几年前还是XML格式的天下,当时Json还没有这么流行,腾讯毕竟是产品业务驱动的,当然选择当时开发人员最熟悉的XML格式了开发,后面随着微信平台的普及,用户越来越多,想重构改成Json格式估计也十分困难,所以历史就遗留下来了呗。。

我在此推荐一个GitHub上一个微信开发 Java SDK,里面有整个微信开发平台很多功能模块造好的轮子,我们可以参考下直接使用:
https://github.com/Wechat-Group/WxJava
在这里插入图片描述
比如现在对于XMl消息解析这个需求,上面就提供了完整详尽的代码。


5.获取openid以及网页授权(重难点)

注意,这是公众号开发的重难点之一,请把技术文档中的微信网页授权模块多读两遍,然后带着疑问来看我的解析。

(1)先明确为什么需要网页授权?我们的目的是什么?

答:用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑。也就是通过这种授权机制,我们能获取微信用户信息,比如:头像、昵称、地区、个性签名等。

(2)既然目的是获取用户基本信息,微信不是提供了专门的接口吗?非要网页授权?

答:在文档的 用户管理 - 获取用户基本信息(UnionID机制) 模块可以看到的确有获取用户基本信息接口:
在这里插入图片描述
可以看到,这个接口只需要提供openid或者unionid,即可直接获取用户基本信息。那么问题来了,openid(unionid)又是如何获取呢?

微信平台提供了两种方式获取用户的openid

第一种方式:

用户与公众号产生消息交互时,会以POST请求的方式向我们配置的服务器URL地址发送XML格式的消息,并附带该用户对应公众号的openid!关于什么是消息交互我们可以查看文档中的消息管理模块,比如我们在公众号输入栏中发送文字图片语音等属于普通消息交互,我们关注、取关、点击自定义菜单等属于事件消息交互,每当前端用户进行这个操作时,微信服务端都会向我们项目后台发送POST请求给我们传达信息:
在这里插入图片描述
可以看到,这个推送数据包中就包含了用户的消息交互类型、时间以及我们需要的openid!也就是说,无论用户在公众号里干了啥操作,我们都能知道他这个操作干了啥,以及他是谁(openid),这时就能调用 用户管理 - 获取用户基本信息(UnionID机制) 接口获取用户基本信息了。

别高兴太早,这种通过消息交互获取用户信息的方式,用户占主动地位,我们项目后端服务被动接受,那么如果我有个基本需求:我想在自定义菜单 - 对应我们网站的前端页面上展示微信用户基本信息,能做到吗?你如何把后台接收到的消息和前端用户关联绑定?
可见,这种被动的方式并不能实现该功能,我们需要主动出击,在前端就能获取到当前操作用户的openid!

第二种方式:

这种方式就是通过网页授权机制主动出击!详情见下文。

(3)网页授权有哪几种机制?分别是怎样实现?应用于什么场景?

答:主要有两种机制,对应两种scope:

snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)。

snsapi_userinfo为scope发起的网页授权,是用来获取用户基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。

光看这两句解释你可能有一堆疑问,我们逐一分析:

两种机制的前面授权步骤相同,大概如下:

我们先要按照文档要求构造一个链接https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
其中重点参数是redirect_uri,这个参数填的既可以是前端项目url,也可以是后端接口url,然后点击这个链接后,微信服务端经过重定向到我们填写的redirect_uri,会在此redirect_uri后拼接上一个code参数!然后前端或者后端通过code参数就可以调微信接口https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code获取openid等信息了:
在这里插入图片描述
这里讲下 snsapi_basesnsapi_userinfo不同点

首先snsapi_base静默授权,什么意思呢?就是用户没有感知;与之对应的就是非静默授权snsapi_userinfo了,这个scope公众号会弹出一个小窗口需要用户手动点击授权,类似这种:
在这里插入图片描述
那么这两种scope授权的优劣势在哪呢?

snsapi_base 的优势在于用户无感知,体验好,方便快捷;劣势在于获取openid后只能通过用户管理 - 获取用户基本信息(UnionID机制) 接口获取用户基本信息,而这种方式需要确保用户已经关注,不然是没有相关信息的!
snsapi_userinfo 的优势在于无需用户关注公众号,只要用户点击了授权确认,即可通过access_token和openid调用专门的拉去用户信息接口获取信息,比较暴力。。;劣势在于需要用户手动授权,可能影响用户体验
在这里插入图片描述

在此说下,我们项目是通过snsapi_base静默授权的,其中redirect_uri配置的是前端项目首页地址(前后端分离),并将构造的这个链接封装起来,直接配置在自定义菜单里,那么用户点击菜单,就直接重定向到前端项目,然后前端获取code参数调用后端获取openid接口,将获取的openid缓存到客户端,以便后面使用。

(4)想要进行网页授权,我们需要在公众平台配置什么吗?

答:需要!
如果是测试号,需要在 测试号管理 - 体验接口权限表 - 网页服务 - 网页帐号 点击 修改
在这里插入图片描述
在这里插入图片描述
在这里配置的是回调页面redirect_uri的域名

如果是正式号(需要微信认证),需要在 开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息 的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头;

而且正式号其他配置的地方也和测试号不一样,比如多了IP白名单、域名根路径下的txt验证文件,这个稍微摸索下应该没啥问题的。


over 暂时就回忆这么多了。。。可能有遗漏大家可以提出哈 ~ 下一篇博客写几个开发时的小问题补充下吧

2017-08-24 22:05:42 u011549191 阅读数 277

2107微信小程序运行环境:

2107项目源码:下载地址

微信web开发者工具:下载地址

建议用tag v1.2.0 版本进行学习,因为结构比较清晰简单,下载成功后用微信web开发者工具打开,就可以实际动手修改试验查看。

系统架构图说明:


如图所示,程序service整体以es6-promise为基础,打造了两套请求方案,分别是HttpService和HttpResource,给程序提供更多选择,两者对比,前者更便向于传统服务,后者偏向于RESTful服务,请根据自己的需求使用。

微信小程序的入口和页面结构相差不大,.json后缀文件为配置文件,.js文件为逻辑文件, .wxss文件为样式文件。

请结合以上帮助查看源码,帮助学习,有问题欢迎留言来信讨论。

实际介面截图




## 上线示例


2019-09-10 19:01:45 weixin_44309374 阅读数 387

微信小程序苹果手机请求地址 报错404,安卓可以正常请求,电脑端的开发工具也可以请求到数据
只有苹果手机真机测试的时候,会报错404,Not Found错误

原因是:
在请求的地址后面多了一个空格,安卓和微信开发者工具不会解析地址中的空格,但是苹果手机就会解析空格,所以会出现404错误

没有更多推荐了,返回首页