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

    一、 首先授权配置

     公众号设置 --》功能设置
     设置业务域名!
    

    自定义菜单 
    这里的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地址

        <dependency>
          <groupId>com.github.binarywang</groupId>
          <artifactId>weixin-java-mp</artifactId>
          <version>2.5.0</version>
        </dependency>
     在做微信支付的时候有可能会用到xstream的包,有需要也拿去
     xstream-1.4.7.jar,xxp3_min-1.1.4.jar,xmlpull-1.1.3.1.jar
     maven地址 
    
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.7</version>
        </dependency>
        <dependency>
            <groupId>xpp3</groupId>
            <artifactId>xpp3</artifactId>
            <version>1.1.4c</version>
        </dependency>
        <dependency>
            <groupId>xmlpull</groupId>
            <artifactId>xmlpull</artifactId>
            <version>1.1.3.1</version>
        </dependency>

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

    @Configuration
    @PropertySource(
            value={"classpath:wxProperties.properties"},
            ignoreResourceNotFound = true)
    //@DependsOn("propertyPlaceholderConfigurer")
    public class WeixinConfig {
        //直接获取资源文件中的配置的值
        @Value("${wxProperties.appid}")
        private String appid;//appId
    
        @Value("${wxProperties.appsecret}")
        private String appsecret;//Appsecret
    
        @Value("${wxProperties.token}")
        private String token;//Token
    
        @Value("${wxProperties.aeskey}")
        private String aesKey;//aeskey,有就填,没有就不填
    
        @Value("${wxProperties.partener_id}")
        private String partenerId;//商户号
    
        @Value("${wxProperties.partener_key}")
        private String partenerKey;//商户秘钥
    
        @Value("${wxProperties.notify_url}")
        private String notifyUrl;//支付后台通知接口地址
    
        @Bean
        public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
           PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
           ppc.setIgnoreUnresolvablePlaceholders(true);
           return ppc;
        }
    
        @Bean
        public WxMpConfigStorage wxMpConfigStorage() {
            WxMpInMemoryConfigStorage configStorage = new WxMpInMemoryConfigStorage();
            configStorage.setAppId(this.appid);
            configStorage.setSecret(this.appsecret);
            configStorage.setToken(this.token);
            configStorage.setAesKey(this.aesKey);
            configStorage.setPartnerId(this.partenerId);
            configStorage.setPartnerKey(this.partenerKey);
            configStorage.setNotifyURL(this.notifyUrl);
            return configStorage;
        }
    
        @Bean
        public WxMpService wxMpService() {
            WxMpService wxMpService = new WxMpServiceImpl();
            wxMpService.setWxMpConfigStorage(wxMpConfigStorage());
            return wxMpService;
        }
    
    }

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

        @Autowired
        protected WxMpService wxMpService;

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

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

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

     public StatusResult<Map<String, Object>> createJsapiSignature(String url) {
            Map<String, Object> result = new HashMap<String, Object>();
            try {
                WxJsapiSignature  wxJsapiSignature = wxMpService.createJsapiSignature(url);
                String getJsapiTicket = wxMpService.getJsapiTicket();
                result.put("wxJsapiSignature", wxJsapiSignature);
                return StatusResult.success(result, "");
            } catch (WxErrorException e) {
                return StatusResult.failed("未知错误出现", result);
            }
        }

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

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

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

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

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

    function callPay(){
                if (typeof WeixinJSBridge == "undefined"){
                   if( document.addEventListener ){
                       document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
                   }else if (document.attachEvent){
                       document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
                       document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
                   }
                }else{
                   onBridgeReady();
                }       
            }
            function onBridgeReady(){
                   WeixinJSBridge.invoke(
                       'getBrandWCPayRequest', {
                           "appId":appId,     //公众号名称,由商户传入     
                           "timeStamp":timeStamp,         //时间戳,自1970年以来的秒数     
                           "nonceStr":nonceStr, //随机串     
                           "package":package,     
                           "signType":"MD5",         //微信签名方式:     
                           "paySign":paySign //微信签名 
                       },
                       function(res){     
                           if (res.err_msg == "get_brand_wcpay_request:ok") {    
                                alert("微信支付成功!");
                            } else if (res.err_msg == "get_brand_wcpay_request:cancel") {    
                                alert("用户取消支付!");
                            } else {  
                                 alert("支付失败!");
                            }     // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。 
                       }
                   ); 
            }

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

     public void getJSSDKCallbackData(HttpServletRequest request,
                HttpServletResponse response) {
            try {
                synchronized (this) {
                    Map<String, String> kvm = XMLUtil.parseRequestXmlToMap(request);
                    System.out.println("微信通知返回结果:	"+kvm.toString());
                    WxPayOrderQueryResult  wxPayOrderQueryResult = wxMpService.getPayService().queryOrder("", kvm.get("out_trade_no"));//用订单号去查询订单状态,冗余代码可看可删
    //                if (this.wxMpService.getPayService().checkSign(kvm,  kvm.get("sign"))) {
                    System.out.println("查询订单返回结果:	"+wxPayOrderQueryResult.getTradeState());
                    if ("SUCCESS".equals(wxPayOrderQueryResult.getTradeState())) {
                        if (kvm.get("result_code").equals("SUCCESS")) {
                            //TODO(user) 微信服务器通知此回调接口支付成功后,通知给业务系统做处理
                            log.info("out_trade_no: " + kvm.get("out_trade_no") + " pay SUCCESS!");
                            String out_trade_no = kvm.get("out_trade_no"); //支付订单号,接下来写业务代码                       
                                    }
                                }
                            } 
                            log.info("已经支付的订单详情	"+aleadyPayOrder);
                            response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[ok]]></return_msg></xml>");
                        } else {
                            log.error("out_trade_no: "
                                + kvm.get("out_trade_no") + " result_code is FAIL");
                            response.getWriter().write(
                                "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[result_code is FAIL]]></return_msg></xml>");
                        }
                    } else {
                        response.getWriter().write(
                            "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[check signature FAIL]]></return_msg></xml>");
                        log.error("out_trade_no: " + kvm.get("out_trade_no")
                            + " check signature FAIL");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

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

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

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

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

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

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

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

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

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

  • 相关阅读:
    CodeForces 7B
    CodeForces 4D
    离散化
    线段树入门
    洛谷 P3951 小凯的疑惑(赛瓦维斯特定理)
    Codeforces 1295D Same GCDs (欧拉函数)
    Codeforces 1295C Obtain The String (二分)
    Codeforces 1295B Infinite Prefixes
    Codeforces 1295A Display The Number(思维)
    Codeforces 1294F Three Paths on a Tree(树的直径,思维)
  • 原文地址:https://www.cnblogs.com/fgtt/p/6972480.html
Copyright © 2011-2022 走看看