zoukankan      html  css  js  c++  java
  • 微信公众号H5开发笔记

    来源:https://blog.csdn.net/chou342175867/article/details/62429354

    利用H5开发微信公众号

    一、 首先授权配置

    1.  
      公众号设置 --》功能设置
    2.  
      设置业务域名!
    • 1
    • 2
    • 3

    自定义菜单 
    这里的MP_verify_w7tdZrafqhkK9Mcj.txt文件,需要放到你项目的根目录下,例子:你的项目war包叫 test.war ,里面包含了src,WEB-INFO两个文件夹,则把MP_verify_w7tdZrafqhkK9Mcj.txt放到这两个文件夹的同级目录下;即现在test.war下有两个文件夹一个txt文件:src,WEB-INFO,MP_verify_w7tdZrafqhkK9Mcj.txt. 
    后面就需要配置JS接口安全域名和网页授权域名了,最好和业务域名配置为一样就好了。 
    二、开发中的配置 
    在开发目录下的基本配置中进行配置。 
    基本配置–》开发者ID–》AppID(应用ID),AppSecret(应用密钥); 
    基本配置–》微信开放平台账号绑定 
    这里需要绑定微信开放平台,若不绑定,在获取用户信息的时候就只能获取到用户的openId,不能获取到unionId. 
    自定义菜单
    注意:定义菜单的时候有讲究了, 
    如果你想在用户点这个菜单的时候就拿到用户的微信基本信息(性别,昵称,openId,unionId),这里直接可以配置成为授权链接,授权链接回调url直接写成你后台的一个接口地址,然后由这个接口来跳转到其它页面. 
    例子:H5授权的链接: 
    http://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxxxxxx&redirect_uri=http://xxxx.com/test/login&response_type=code&scope=snsapi_userinfo&state=xxx&connect_redirect=1#wechat_redirect 
    微信回调的url是一个接口地址:http://xxxx.com/test/login,不能回调网页,因为存在跨域错误。 
    state的值是可以自定义的。 
    这里的scope是用的snsapi_userinfo,这样可以直接在后台拿到用户信息。 
    微信回调这个接口的时候会把code和state的值返回,接口就可以通过code去拿用户的信息了。 
    若要用code去拿用户的信息,又会去做一堆事情,这些事情确实麻烦;推荐直接使用第三方的jar包,一步就拿到了。 
    推荐的jar包:weixin-java-mp-2.5.0.jar,weixin-java-common-2.5.0.jar; 
    maven地址

    1.  
      <dependency>
    2.  
      <groupId>com.github.binarywang</groupId>
    3.  
      <artifactId>weixin-java-mp</artifactId>
    4.  
      <version>2.5.0</version>
    5.  
      </dependency>
    • 1
    • 2
    • 3
    • 4
    • 5
    1.  
      在做微信支付的时候有可能会用到xstream的包,有需要也拿去
    2.  
      xstream-1.4.7.jar,xxp3_min-1.1.4.jar,xmlpull-1.1.3.1.jar
    3.  
      maven地址
    • 1
    • 2
    • 3
    • 4
    1.  
      <dependency>
    2.  
      <groupId>com.thoughtworks.xstream</groupId>
    3.  
      <artifactId>xstream</artifactId>
    4.  
      <version>1.4.7</version>
    5.  
      </dependency>
    6.  
      <dependency>
    7.  
      <groupId>xpp3</groupId>
    8.  
      <artifactId>xpp3</artifactId>
    9.  
      <version>1.1.4c</version>
    10.  
      </dependency>
    11.  
      <dependency>
    12.  
      <groupId>xmlpull</groupId>
    13.  
      <artifactId>xmlpull</artifactId>
    14.  
      <version>1.1.3.1</version>
    15.  
      </dependency>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这里说下weixin-java-mp-2.5.0.jar的使用方法, 
    1.weixin-java-mp-2.5.0.jar里面最重要的类是 
    WxMpInMemoryConfigStorage和WxMpService; 
    WxMpInMemoryConfigStorage是用来存微信公众号的基本信息的, 
    在Spring+SpringMvc中的使用方法例子:

    1.  
      @Configuration
    2.  
      @PropertySource(
    3.  
      value={"classpath:wxProperties.properties"},
    4.  
      ignoreResourceNotFound = true)
    5.  
      //@DependsOn("propertyPlaceholderConfigurer")
    6.  
      public class WeixinConfig {
    7.  
      //直接获取资源文件中的配置的值
    8.  
      @Value("${wxProperties.appid}")
    9.  
      private String appid;//appId
    10.  
       
    11.  
      @Value("${wxProperties.appsecret}")
    12.  
      private String appsecret;//Appsecret
    13.  
       
    14.  
      @Value("${wxProperties.token}")
    15.  
      private String token;//Token
    16.  
       
    17.  
      @Value("${wxProperties.aeskey}")
    18.  
      private String aesKey;//aeskey,有就填,没有就不填
    19.  
       
    20.  
      @Value("${wxProperties.partener_id}")
    21.  
      private String partenerId;//商户号
    22.  
       
    23.  
      @Value("${wxProperties.partener_key}")
    24.  
      private String partenerKey;//商户秘钥
    25.  
       
    26.  
      @Value("${wxProperties.notify_url}")
    27.  
      private String notifyUrl;//支付后台通知接口地址
    28.  
       
    29.  
      @Bean
    30.  
      public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    31.  
      PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
    32.  
      ppc.setIgnoreUnresolvablePlaceholders(true);
    33.  
      return ppc;
    34.  
      }
    35.  
       
    36.  
      @Bean
    37.  
      public WxMpConfigStorage wxMpConfigStorage() {
    38.  
      WxMpInMemoryConfigStorage configStorage = new WxMpInMemoryConfigStorage();
    39.  
      configStorage.setAppId(this.appid);
    40.  
      configStorage.setSecret(this.appsecret);
    41.  
      configStorage.setToken(this.token);
    42.  
      configStorage.setAesKey(this.aesKey);
    43.  
      configStorage.setPartnerId(this.partenerId);
    44.  
      configStorage.setPartnerKey(this.partenerKey);
    45.  
      configStorage.setNotifyURL(this.notifyUrl);
    46.  
      return configStorage;
    47.  
      }
    48.  
       
    49.  
      @Bean
    50.  
      public WxMpService wxMpService() {
    51.  
      WxMpService wxMpService = new WxMpServiceImpl();
    52.  
      wxMpService.setWxMpConfigStorage(wxMpConfigStorage());
    53.  
      return wxMpService;
    54.  
      }
    55.  
       
    56.  
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    这里是配置微信公众号的基本信息,其它地方要使用就直接使用:

    1.  
      @Autowired
    2.  
      protected WxMpService wxMpService;
    • 1
    • 2

    2.获取微信用户基本信息示例代码:

    1.  
      WxMpOAuth2AccessToken accessToken;
    2.  
      WxMpUser wxMpUser = null;
    3.  
      accessToken = this.wxMpService.oauth2getAccessToken(code);
    4.  
      wxMpUser = this.wxMpService.getUserService().userInfo(accessToken.getOpenId(), null);
    5.  
      //用户的基本信息就在wxMpUser中了,需要的就拿去用了。(注意:微信用户的性别:0:未知,1:男 2:女)
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.H5若要使用微信封装好的js,则需要一些基本的配置信息,完全可以从后天台获取然后返回,示例代码:

    1.  
      public StatusResult<Map<String, Object>> createJsapiSignature(String url) {
    2.  
      Map<String, Object> result = new HashMap<String, Object>();
    3.  
      try {
    4.  
      WxJsapiSignature wxJsapiSignature = wxMpService.createJsapiSignature(url);
    5.  
      String getJsapiTicket = wxMpService.getJsapiTicket();
    6.  
      result.put("wxJsapiSignature", wxJsapiSignature);
    7.  
      return StatusResult.success(result, "");
    8.  
      } catch (WxErrorException e) {
    9.  
      return StatusResult.failed("未知错误出现", result);
    10.  
      }
    11.  
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    这里的url是H5用js代码获取的:

    var url = location.href.split('#')[0];
    • 1

    4.公众号支付 
    流程: 
    页面发起–>后台下单后返回前端所需要的参数–>页面发起支付–>用户输入密码付款成功–>微信回调后台通知接口–>业务处理完成 
    H5页面发起支付: 
    微信公众号的页面支付首先要配置微信公众号: 
    微信支付–>开发配置–>支付授权目录(正式、测试的目录必须要不一样,否则有你好看的,) 
    注意:设置授权目录的时候必须要精确到需要支付页面的目录文件夹; 
    例子:需要支付的H5页面 http://xxxxx.com/test/html/pay/pay.html 
    则授权目录配置为 http://xxxxx.com/test/html/pay/ 
    配置完成后就可以发起下单了, 
    后台下单代码示例:

    1.  
      public StatusResult<Map<String, String>> getJSSDKPayInfo(HttpServletResponse response,
    2.  
      HttpServletRequest request) {
    3.  
      StatusResult<Map<String, String>> result = null;
    4.  
      String spbill_create_ip = request.getRemoteAddr();//订单生成的机器 IP
    5.  
      Map<String, String> map = new HashMap<String, String>();
    6.  
      WxMpConfigStorage wx= wxMpService.getWxMpConfigStorage();
    7.  
      WxPayUnifiedOrderRequest prepayInfo = new WxPayUnifiedOrderRequest();
    8.  
      //TODO change all request parameters to a VO class
    9.  
      prepayInfo.setOpenid("openId");
    10.  
      prepayInfo.setOutTradeNo("out_trade_no");//设置订单商户号
    11.  
      int total_fee = 0.01 * 100;
    12.  
      total_fee = 1;
    13.  
      prepayInfo.setTotalFee(Integer.valueOf(total_fee));//设置支付金额 单位为分
    14.  
      prepayInfo.setBody("xxxxx");//支付的内容简介
    15.  
      prepayInfo.setTradeType("JSAPI");//渠道:公众号支付
    16.  
      prepayInfo.setSpbillCreateIp(spbill_create_ip);//终端ip
    17.  
      //TODO(user) 填写通知回调地址
    18.  
      prepayInfo.setNotifyURL(wx.getNotifyURL());
    19.  
      try {
    20.  
      两种下单方式,如果报错请先仔细检查微信配置的各种参数
    21.  
      //WxPayUnifiedOrderResult wxPayUnifiedOrderResult= wxMpService.getPayService().unifiedOrder(prepayInfo);
    22.  
      Map<String, String> payInfo = this.wxMpService.getPayService().getPayInfo(prepayInfo);
    23.  
      if(payInfo != null){
    24.  
      //业务代码
    25.  
      }
    26.  
      result = StatusResult.success(payInfo);
    27.  
      return result;
    28.  
      } catch (WxErrorException e) {
    29.  
      log.error(e.getError().toString());
    30.  
      map.put("error", e.getError().toString());
    31.  
      return StatusResult.failed("微信下单失败",map);
    32.  
      }
    33.  
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    H5页面支付js代码(需要引入微信js哈):

    1.  
      function callPay(){
    2.  
      if (typeof WeixinJSBridge == "undefined"){
    3.  
      if( document.addEventListener ){
    4.  
      document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
    5.  
      }else if (document.attachEvent){
    6.  
      document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
    7.  
      document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
    8.  
      }
    9.  
      }else{
    10.  
      onBridgeReady();
    11.  
      }
    12.  
      }
    13.  
      function onBridgeReady(){
    14.  
      WeixinJSBridge.invoke(
    15.  
      'getBrandWCPayRequest', {
    16.  
      "appId":appId, //公众号名称,由商户传入
    17.  
      "timeStamp":timeStamp, //时间戳,自1970年以来的秒数
    18.  
      "nonceStr":nonceStr, //随机串
    19.  
      "package":package,
    20.  
      "signType":"MD5", //微信签名方式:
    21.  
      "paySign":paySign //微信签名
    22.  
      },
    23.  
      function(res){
    24.  
      if (res.err_msg == "get_brand_wcpay_request:ok") {
    25.  
      alert("微信支付成功!");
    26.  
      } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
    27.  
      alert("用户取消支付!");
    28.  
      } else {
    29.  
      alert("支付失败!");
    30.  
      } // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
    31.  
      }
    32.  
      );
    33.  
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    微信回调后台通知接口代码示例:

    1.  
      public void getJSSDKCallbackData(HttpServletRequest request,
    2.  
      HttpServletResponse response) {
    3.  
      try {
    4.  
      synchronized (this) {
    5.  
      Map<String, String> kvm = XMLUtil.parseRequestXmlToMap(request);
    6.  
      System.out.println("微信通知返回结果: "+kvm.toString());
    7.  
      WxPayOrderQueryResult wxPayOrderQueryResult = wxMpService.getPayService().queryOrder("", kvm.get("out_trade_no"));//用订单号去查询订单状态,冗余代码可看可删
    8.  
      // if (this.wxMpService.getPayService().checkSign(kvm, kvm.get("sign"))) {
    9.  
      System.out.println("查询订单返回结果: "+wxPayOrderQueryResult.getTradeState());
    10.  
      if ("SUCCESS".equals(wxPayOrderQueryResult.getTradeState())) {
    11.  
      if (kvm.get("result_code").equals("SUCCESS")) {
    12.  
      //TODO(user) 微信服务器通知此回调接口支付成功后,通知给业务系统做处理
    13.  
      log.info("out_trade_no: " + kvm.get("out_trade_no") + " pay SUCCESS!");
    14.  
      String out_trade_no = kvm.get("out_trade_no"); //支付订单号,接下来写业务代码
    15.  
      }
    16.  
      }
    17.  
      }
    18.  
      log.info("已经支付的订单详情 "+aleadyPayOrder);
    19.  
      response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[ok]]></return_msg></xml>");
    20.  
      } else {
    21.  
      log.error("out_trade_no: "
    22.  
      + kvm.get("out_trade_no") + " result_code is FAIL");
    23.  
      response.getWriter().write(
    24.  
      "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[result_code is FAIL]]></return_msg></xml>");
    25.  
      }
    26.  
      } else {
    27.  
      response.getWriter().write(
    28.  
      "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[check signature FAIL]]></return_msg></xml>");
    29.  
      log.error("out_trade_no: " + kvm.get("out_trade_no")
    30.  
      + " check signature FAIL");
    31.  
      }
    32.  
      }
    33.  
      } catch (Exception e) {
    34.  
      e.printStackTrace();
    35.  
      }
    36.  
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    到此为止公众号支付完成。

    三、微信js中接口使用 
    分享等很常见的,需要初始化微信的js,需要利用到上面写的createJsapiSignature后台接口。 
    公众号的分享给朋友、朋友圈、QQ空间等方法在微信js中是可以直接调用的,分享的内容可以自己改变的,但是分享出去的按钮只能是微信右上角的分享,开发者不能自定义分享按钮。。。这一点让人非常不爽。 
    H5页面js的代码示例:

    引入微信的js,然后初始化,然后微信会自动执行wx.ready中的方法

    1.  
      wx.config({
    2.  
      debug: false, //开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    3.  
      appId: appId, //必填,公众号的唯一标识
    4.  
      timestamp: timestamp, // 必填,生成签名的时间戳
    5.  
      nonceStr: nonceStr, //必填,生成签名的随机串
    6.  
      signature: signature, // 必填,签名
    7.  
      jsApiList: [//需要多少接口就写多少接口
    8.  
      'checkJsApi',//判断当前客户端是否支持指定JS接口
    9.  
      'onMenuShareAppMessage'//获取“分享给朋友”按钮点击状态及自定义分享内容接口
    10.  
      ] //必填,需要使用的JS接口列表,所有JS接口列表
    11.  
      });
    12.  
      wx.ready(function () {
    13.  
      var title = "xxxx";
    14.  
      var desc = "xxxx";
    15.  
      var imgUrl = "http://xxx.com/test/picture/xxxxx.png";
    16.  
      wx.onMenuShareAppMessage({
    17.  
      title: title, // 分享标题
    18.  
      desc: desc, // 分享描述
    19.  
      link: url, // 分享链接,h5网页的地址或者其它
    20.  
      imgUrl: imgUrl,
    21.  
      trigger: function(res) {
    22.  
      alert('用户点击发送给朋友');
    23.  
      },
    24.  
      success: function(res) {
    25.  
      alert('已分享');
    26.  
      },
    27.  
      cancel: function(res) {
    28.  
      alert('已取消');
    29.  
      },
    30.  
      fail: function(res) {
    31.  
      alert(JSON.stringify(res));
    32.  
      }
    33.  
      });
    34.  
      });
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    调用微信js中的方法流程: 
    初始化config–>执行wx.ready 
    开发者需要更多的功能就依照葫芦画瓢了,或者去微信js sdk文档去copy方法了。

    让人不愉快的事情又发生了,微信在4月29日开始限制自定义分享的链接啦,必须要是安全域名下的链接才可以分享。 
    详情请看: 
    JSSDK自定义分享接口的策略调整 
    这样导致不能直接分享自己想要的链接了,但是解决方法还是有的: 
    在你的域名下新建一个H5页面,在这个H5页面的js代码中做一个跳转就好啦(但是如果你分享出去的是支付页面,那多半是支付不了地)!

    四、处理微信直接可以分享页面问题 
    有时候业务需要不能把当前的页面分享出去,但是微信自带的分享、复制链接按钮是可以在任何页面拿到当前页面的地址,如果别人点击就会进入。为了避免这个情况发生,有几种处理方法: 
    1.后端足够强大,页面跳转完全由后端完成,在加入了权限验证的情况下就不怕这个的,后端会拦截请求验证,验证不过就跳指定的error页面就好。 
    2.前端做验证 
    jsp可以用session,判断session中的一个全局参数即可。 
    H5可以使用cookie,在项目的开始页写入cookie,在js中写一个验证方法,每个页面都调用这个验证方法进行验证,虽然有冗余代码,但是这个是可以实现地,简单粗暴,速度快。 
    设置cookie的方法:

    1.  
      jquery(function() {
    2.  
      var expiresDate= new Date();
    3.  
      expiresDate.setTime(expiresDate.getTime() + (30 * 60 * 1000));//半小时
    4.  
      jquery.cookie("openId",'${openId}', {
    5.  
      path : '/',//cookie的作用域为根目录,任何页面都是有效的
    6.  
      expires : expiresDate
    7.  
      });//cookie里面保存openId
    8.  
      });
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    然后在js中写一个方法每个页面都调用判断。

  • 相关阅读:
    [hdu2196]Computer树的直径
    [poj2342]Anniversary party树形dp入门
    链式前向星模板
    LintCode-50.数组剔除元素后的乘积
    Markdown的基本语法
    LintCode-8.旋转字符串
    LintCode-1.A + B 问题
    LintCode-61.搜索区间
    LintCode-88.最近公共祖先
    LintCode-54.转换字符串到整数
  • 原文地址:https://www.cnblogs.com/wangsongbai/p/13444699.html
Copyright © 2011-2022 走看看