微信公众号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("微信通知返回结果:\t"+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("查询订单返回结果:\t"+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("已经支付的订单详情\t"+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中写一个方法每个页面都调用判断。

posted on 2020-08-06 10:32  Hi,王松柏  阅读(1195)  评论(0编辑  收藏  举报

导航