微信公众号授权,支付,退款总结【shoucang】
1.支付前准备
1.1首先两个平台接入账户。
- 商户平台:https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F
 - 公众平台:https://mp.weixin.qq.com/
 
1.2两个平台的作用
     3 商户平台:支付收款方,通俗点将就是网站用户支付的钱给谁。里面有商户的一些信息以及秘钥支付时要用。
     4.公众号平台:在这里需要它提供网页授权的一些信息。
2.微信公众号支付流程
    关于支付流程,官方给了一张很详细的流程图如下:
    当然这是所有支付的流程图,在这里博主结合自己的实现方式也画了一张只有授权和公众号支付流程的图。大家可以参考有画的不对的地方还请路过的大牛多多指教。
3. 微信公众号支付的那些坑
    1:获取授权的时候,访问授权接口不要用ajax提交。如果用ajax提交方式提交请求,微信服务端会报跨域请求不允许的错误。
    2:获取授权openid的时候appid,secret一定要正确,这里的secret获取方式为下图,如果忘记,可以重置:
    3:如果用的springmvc的框架,在统一支付接口记得用注解@ResponseBody,因为统一支付接口返回的数据一般是一个map,这个map中的数据前台页面要解析,所以需要这个注解。
    4:调用统一支付接口时,请求报文是xml格式的,所以要把需要的参数转变为xml形式。
    5:异步回调方法是支付成功后微信通知商户后台时调用,所以测试时需要在外网测试
    7:授权时,只授一次就行,所以在授权之前判断是否已经授权。
    8:微信支付以分为单位,支付金额需要注意转换单位。
    9:如果签名失败,一定要仔细检查参数是否都拼接完毕,拼接正确,一般签名失败最可能的原因就是secret错误,应该去微信公众平台重新查找并且核对。
    10:退款时,注意双向证书的路径。一般退款回调失败最可能的原因就是证书出错。
4. 微信公众号开发需要的一些官网网站
商户平台开发者文档网址
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
用户授权需要查看的网址,重点查看用户管理相关说明
http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
商户平台微信支付网址
https://pay.weixin.qq.com/wiki/doc/api/index.html
商户平台登录网址
https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2Findex.php%2Fcore%2Faccount
微信公众平台登录入口
https://mp.weixin.qq.com/
5.公众号支付代码
前端网页js代码
    var pay_orderno;    //订单编号
    //判断是否是授权回来的outh
    var outh = $.getUrlParam("outh");
    if (!empty(outh)){
        //说明outh不为空,即为授权回来的,则直接微信支付
        wxzhifu();
    }
    function getRequest() {
        var url = location.search; //获取url中"?"符后的字串
        var theRequest = new Object();
        if (url.indexOf("?") != -1) {
            var str = url.substr(1);
            strs = str.split("&");
            for (var i = 0; i < strs.length; i++) {
                theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]);
            }
        }
        return theRequest;
    }
    //保存订单信息
    function saveOrder(){
        var mode = "";
        if($("#AliPay")[0].checked) {
            mode = "支付宝";
        }else if($("#bankpay")[0].checked) {
            mode = "银联支付";
        }else if($("#wxpay")[0].checked) {
            mode = "微信支付";
        }
        var dishjson = data.dishJson;   //订单表dishJson内容
        var dishJson = (JSON.parse(dishjson))[0];
        var oldcanpin = dishJson.canpin;
        var newcanpin = oldcanpin + ",支付方式:"+ mode; //拼接支付方式以后的菜品信息
        //alert(newcanpin);
        dishJson["canpin"] = newcanpin;
        data["dishJson"] = JSON.stringify(dishJson);
        var url="/cyDishorder/saveCyDcOrders";
        var successfull= function (datas) {
            var bizData=datas.bizData;
            pay_orderno = bizData.orderNum;
            //alert(pay_orderno);
            //var paymoney = $("#ydmoney").text().substring(1);
            if(datas.rtnCode == "0000000"){
                pay();  //跳转支付方法
                //alert("==============")
            }
        }
        ajaxPostFun(url, data, successfull,null, "保存餐厅预定订单");
    }
    //跳转到支付页面
    function pay() {
        if($("#AliPay")[0].checked) {
            location.href = server+"/AliPayDingCan/" + pay_orderno;
        }else if($("#bankpay")[0].checked) {
            location.href = server+"/CYChinapay/" + pay_orderno;
        }else if($("#wxpay")[0].checked){
            //查询该用户是否微信授权
            var url = server+"/Member/FindById/"+userid;
            var successFun = function (data) {
                if(empty(data.bizData.openid)){
                    //alert("微信未授权");
                    //如果该用户没有授权,则进行授权操作
                    wxshouquan();
                }else{
                    //alert("微信已授权");
                    //用户已经授权,直接微信支付
                    wxzhifu();
                }
            }
            ajaxPostFun(url, {}, successFun, null, "查询用户是否授权");
        }else {
            layer.msg("请选择支付方式");
            return false;
        }
    }
    //微信授权
    function  wxshouquan() {
        location.href = server + "/CyWechatPay/outh?userid=" + userid;
    }
    //微信支付
    function wxzhifu(){
        var url = server+"/CyWechatPay/unifiedorder";
        ajaxPostFun(url, {userid:userid,orderno:pay_orderno}, function(res) {
            var _data = res.bizData;
            function onBridgeReady(){
                WeixinJSBridge.invoke(
                        'getBrandWCPayRequest', {
                            "appId":_data.appId,     //公众号名称,由商户传入
                            "timeStamp":_data.timeStamp,         //时间戳,自1970年以来的秒数
                            "nonceStr":_data.nonceStr, //随机串
                            "package" :_data.package,
                            "signType":_data.signType,         //微信签名方式:
                            "paySign": _data.paySign //微信签名
                        },
                        function(ress){
                            alert( JSON.stringify(ress));
                            if(ress.err_msg == "get_brand_wcpay_request:ok" ) {
                                layer.msg("支付成功!",{time:2000});
                                //window.location.href = "buyGoodsChenggong.html?orderid="+orderid;
                            }else if(ress.err_msg == "get_brand_wcpay_request:cancel"){
                                layer.msg("支付取消!",{time:2000});
                            }else {
                                layer.msg("未知错误!",{time:2000});
                            }    // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。
                        }
                );
            }
            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();
            }
        }, null, "微信支付获取package包");
    }
支付,退款,controller代码
@Controller
@RequestMapping(value = "/CyWechatPay")
public class CyWechatController {
    @Autowired
    private IMemberService memberService;
    @Autowired
    private IMobileCyDishorderService mobileCyDishorderService;
    @Autowired
    private IMobileMemberService mobileMemberService;
    @Autowired
    private IMobileServiceStyleService mobileServiceStyleService;
    private static Logger logger = Logger.getLogger(CyWechatController.class);
    private static String url_snsapi_base = "https://open.weixin.qq.com/connect/oauth2/authorize";
    private static String url_access_token = "https://api.weixin.qq.com/sns/oauth2/access_token";
    private static String url_unifiedorder = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    /**
     * 统一下单
     * @return prepare_id 预付款id
     * @throws IOException
     * @throws JDOMException
     */
    @ResponseBody
    @RequestMapping("/unifiedorder")
    public Map<String, Object> unifiedorder(@RequestParam(value = "orderno", required = true)String orderno, String userid,HttpServletRequest request) throws Exception {
        //根据订单号查询订单时间
        CyDishorderEntity orderEntity = (CyDishorderEntity) mobileCyDishorderService.findOne("orderNum", orderno);
        //获得随机数
        String nonce_str = WxTool.getRandomCode(32);
        //根据用户id查询用户信息
        Map<String,Object> memberEntity =memberService.findByid("id",userid);
        String openid = memberEntity.get("openid").toString();
        //生成xml,参数说明(说明,标识码,订单号,IP,价格,openid用户在微信端的唯一标示)
        String xml = this.getXmlData(orderEntity.getRemarks(), nonce_str,
                orderno, WxTool.getRemoteHost(request), new BigDecimal(orderEntity.getPayMoney()),openid);
        logger.info("生成的订单信息======>" + xml);
        //订单提交的微信地址(预支付地址)
        String result = HttpRequest.httpsRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", xml);
        //告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。
        @SuppressWarnings("unchecked")
        Map<String, Object> map2 = XMLUtil.doXMLParse(result);
        logger.info("统一下单接口返回的结果集======>" + map2);
        //return_code为微信返回的状态码,SUCCESS表示支付成功
        //return_msg 如非空,为错误原因 签名失败 参数格式校验错误
        if (map2.get("return_code").toString().equalsIgnoreCase("SUCCESS")
                && map2.get("result_code").toString().equalsIgnoreCase("SUCCESS")) {
            //预支付成功
            logger.info("微信预支付成功!");
            //map2.put("timestamp",Long.toString(System.currentTimeMillis() / 1000));
            //传递map2给前台页面处理
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("appId", map2.get("appid"));
            map.put("timeStamp", Long.toString(System.currentTimeMillis() / 1000));
            map.put("nonceStr", map2.get("nonce_str"));
            map.put("package", "prepay_id=" + map2.get("prepay_id"));
            map.put("signType", "MD5");
            map.put("paySign", WxTool.getSignUtil(map, ConfigUtil.APP_SECRECT));
            logger.info("统一下------->" + map);
            return map;
        } else {
            //支付失败,进行相应的失败业务处理
            logger.info("微信预支付失败!");
            //传递null给页面处理
            return null;
        }
    }
    /**
     * 申请退款
     */
    @RequestMapping("refund/{orderno}")
    @ResponseBody
    public String refund(@PathVariable String orderno) throws Exception {
        //根据订单号查询订单
        CyDishorderEntity orderEntity = (CyDishorderEntity) mobileCyDishorderService.findOne("orderNum", orderno);
        //获得随机数
        String nonce_str = WxTool.getRandomCode(32);
        StringBuilder sb2 = new StringBuilder();
        //微信签名需要的参数
        Map<String, Object> signMap = new HashMap<String, Object>();
        signMap.put("appid",ConfigUtil.APPID);//应用APPID
        signMap.put("mch_id",ConfigUtil.MCH_ID);//微信支付商户号
        signMap.put("nonce_str",nonce_str);//随机数
        signMap.put("op_user_id",ConfigUtil.MCH_ID);
        signMap.put("out_trade_no",orderEntity.getOrderNum());//订单号out_refund_no
        signMap.put("out_refund_no",orderEntity.getRefund_queryid());//退款流水号
        signMap.put("refund_fee",new BigDecimal(orderEntity.getPayMoney()).multiply(new BigDecimal(100)).intValue());//退款金额
        signMap.put("total_fee",new BigDecimal(orderEntity.getPayMoney()).multiply(new BigDecimal(100)).intValue());//总金额
        signMap.put("transaction_id","");//微信生成的订单号,在支付通知中有返回
        //生成xml,微信要求的xml形式
        StringBuffer xml =new StringBuffer();
        xml.append("<xml>");
        xml.append("<appid>"+ConfigUtil.APPID+"</appid>");//应用ID
        xml.append("<mch_id>"+ConfigUtil.MCH_ID+"</mch_id>");//微信支付分配的商户号
        xml.append("<nonce_str>"+nonce_str+"</nonce_str>");//随机字符串,不长于32位。
        xml.append("<op_user_id>"+ConfigUtil.MCH_ID+"</op_user_id>");//操作员,默认为商户号
        xml.append("<out_refund_no>"+orderEntity.getRefund_queryid()+"</out_refund_no>");//商户退款单号,商户系统内部的退款单号,商户系统内部唯一
        xml.append("<out_trade_no>"+orderEntity.getOrderNum()+"</out_trade_no>");//商户订单号
        xml.append("<refund_fee>"+new BigDecimal(orderEntity.getPayMoney()).multiply(new BigDecimal(100)).intValue()+"</refund_fee>");//退款金额
        xml.append("<total_fee>"+new BigDecimal(orderEntity.getPayMoney()).multiply(new BigDecimal(100)).intValue()+"</total_fee>");//订单金额
        xml.append("<transaction_id>"+"</transaction_id>");//微信订单号,微信生成的订单号,在支付通知中有返回
        xml.append("<sign>"+WxTool.getSignUtil(signMap, ConfigUtil.APP_SECRECT)+"</sign>");//签名
        xml.append("</xml>");
        logger.info("生成的申请退款信息=============================>" + xml.toString());
        /**
         * JAVA使用证书文件
         */
        logger.info("加载证书开始=========================================》》》》》");
        //指定读取证书格式为PKCS12
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        //读取本机存放的PKCS12证书文件
        FileInputStream instream = new FileInputStream(new File("/home/smit/down/apiclient_cert.p12"));
        try {
            //指定PKCS12的密码(商户ID)
            keyStore.load(instream, ConfigUtil.MCH_ID.toCharArray());
        } finally {
            instream.close();
        }
        //ssl双向验证发送http请求报文
        SSLContext sslcontext = null;
        sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, ConfigUtil.MCH_ID.toCharArray()).build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
        StringEntity se = new StringEntity(xml.toString(), "UTF-8");
        httppost.setEntity(se);
        //定义响应实例对象
        CloseableHttpResponse responseEntry = null;
        String xmlStr2 = null;//读入响应流中字符串的引用
        responseEntry = httpclient.execute(httppost);//发送请求
        HttpEntity entity = responseEntry.getEntity();//获得响应实例对象
        if (entity != null) {//读取响应流的内容
            BufferedReader bufferedReader = null;
            bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
            while ((xmlStr2 = bufferedReader.readLine()) != null) {
                sb2.append(xmlStr2);
            }
        }
        Map<String, Object> map = XMLUtil.doXMLParse(sb2.toString());
        logger.info("申请退款接口返回的结果集======>" + map);
        //return_code为微信返回的状态码,SUCCESS表示申请退款成功,return_msg 如非空,为错误原因 签名失败 参数格式校验错误
        if (map.get("return_code").toString().equalsIgnoreCase("SUCCESS")
                && map.get("result_code").toString().equalsIgnoreCase("SUCCESS")) {
            logger.info("****************退款申请成功!**********************");
            //修改订单状态为申请退款
            orderEntity.setOrderStatus(CyOrderStatusEnum.REFUND_SUCCESS.getCode());
            mobileCyDishorderService.update(orderEntity);
            return "SUCCESS";
        } else {
            logger.info("*****************退款申请失败!*********************");
            return "FAIL";
        }
    }
    //生成xml方法
    private static String getXmlData(String body, String nonce_str, String tradeNo,
                                     String ip, BigDecimal totla, String openid) throws Exception {
        Map<String, Object> signMap = new HashMap<String, Object>();
        signMap.put("appid", ConfigUtil.APPID);//应用APPID
        signMap.put("nonce_str", nonce_str);//随机数
        signMap.put("body", body);//商品描述
        signMap.put("mch_id", ConfigUtil.MCH_ID);//微信支付商户号
        signMap.put("notify_url", "http://域名/CyWechatPay/paysuccess.do");//异步通知回调地址
        signMap.put("out_trade_no", tradeNo);//订单号
        signMap.put("total_fee", totla.multiply(new BigDecimal(100)).intValue());//总金额
        signMap.put("trade_type", "JSAPI");//支付类型
        signMap.put("spbill_create_ip", ip);//客户端IP地址
        signMap.put("openid", openid);//支付用户的唯一标识
        StringBuffer xml = new StringBuffer();
        xml.append("<xml>");
        xml.append("<appid>" + signMap.get("appid") + "</appid>");//应用ID
        xml.append("<body>" + signMap.get("body") + "</body>");
        xml.append("<mch_id>" + signMap.get("mch_id") + "</mch_id>");//微信支付分配的商户号
        xml.append("<nonce_str>" + signMap.get("nonce_str") + "</nonce_str>");//随机字符串,不长于32位。
        xml.append("<notify_url>" + signMap.get("notify_url") + "</notify_url>");//接收微信支付异步通知回调地址
        xml.append("<openid>" + signMap.get("openid") + "</openid>");//用户的openid  唯一标示,用户授权时或的
        xml.append("<out_trade_no>" + signMap.get("out_trade_no") + "</out_trade_no>");//订单号
        xml.append("<spbill_create_ip>" + signMap.get("spbill_create_ip") + "</spbill_create_ip>");//用户端实际ip
        xml.append("<total_fee>" + signMap.get("total_fee") + "</total_fee>");//订单总金额,单位为分
        xml.append("<trade_type>" + signMap.get("trade_type") + "</trade_type>");//支付类型
        xml.append("<sign>" + WxTool.getSignUtil(signMap, ConfigUtil.APP_SECRECT) + "</sign>");//签名
        xml.append("</xml>");
        return xml.toString();
    }
    //微信支付异步回调
    @RequestMapping(value = "/paysuccess")
    public void PaySuccess(HttpServletRequest request, HttpServletResponse response){
        try {
            logger.info("微信支付回调开始========================================================");
            PrintWriter print = null;
            InputStream inStream = request.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            outSteam.close();
            inStream.close();
            String result = new String(outSteam.toByteArray(), "utf-8");
            //告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。
            @SuppressWarnings("unchecked")
            Map<Object, Object> map = XMLUtil.doXMLParse(result);
            //return_code为微信返回的状态码,SUCCESS表示支付成功
            //return_msg 如非空,为错误原因 签名失败 参数格式校验错误
            logger.info("微信返回的信息:"+map.toString());
            if (map.get("result_code").toString().equalsIgnoreCase("SUCCESS")
                    && map.get("return_code").toString().equalsIgnoreCase("SUCCESS")) {
                String tradeNo = map.get("out_trade_no").toString();
                //这里做出判断,防止微信服务的多次调用这里,造成一次支付,生成多个订单
                CyDishorderEntity  order =(CyDishorderEntity)mobileCyDishorderService.findOne("orderNum",tradeNo);
                if(order!=null && order.getOrderStatus().equals(CyOrderStatusEnum.PREPAID.getCode())){
                    //该订单已经支付成功,直接return
                    response.getWriter().write(
                            "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
                }
                updateOrder(map);//更新订单状态
            }
            response.getWriter().write(
                    "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 用户授权
     *
     * @param response
     * @throws IOException
     */
    @RequestMapping("/outh")
    public void outh(@RequestParam(value = "userid", required = true) int userid,
                     HttpServletResponse response, HttpServletRequest request) {
            StringBuffer url = request.getRequestURL();
            //String tempContextUrl = url.delete(url.length() - request.getRequestURI().length(), url.length()).append("/").toString();
            try {
                // 回调地址
                String redirecturl = URLEncoder.encode(new String(("http://域名/CyWechatPay/getopenid.do?userid=" + userid).getBytes("utf-8"), "utf-8"),"utf-8");
                logger.info("[微信获取OPENID回调地址]"+redirecturl);
                // 用户授权 snsapi_userinfo
                response.sendRedirect("https://open.weixin.qq.com/connect/oauth2/authorize?appid="
                        + ConfigUtil.APPID
                        + "&redirect_uri="
                        + redirecturl
                        + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect");
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    }
    /**
     * 商户获取用户资料
     *
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping("/getopenid")
    public void getopenid(@RequestParam(value = "userid", required = true) int userid,
                          HttpServletRequest request, HttpServletResponse response) {
        String code = request.getParameter("code");
        Map<String, Object> map = null; // 存放授权access_token和openid
        Map<String, Object> map2 = null;// 存放用户基本资料open
        // 获取授权的access_token和openid
        logger.info("[获取授权的access_token和openid]");
        map = WXUtils.requestUrl("https://api.weixin.qq.com/sns/oauth2/access_token?appid="
                + ConfigUtil.APPID
                + "&secret="
                +ConfigUtil.APP_SECRECT
                + "&code="
                + code
                + "&grant_type=authorization_code");
        String access_token = map.get("access_token").toString();
        String openid = map.get("openid").toString();
        // 获取用户资料
        map2 = WXUtils.requestUrl("https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openid + "&lang=zh_CN");
        //设置用户的openid
        memberService.updateuser(Integer.valueOf(userid),openid);
        try {
            response.sendRedirect("http://域名/Mobile/cyLijiZhifuX.html?=outh=outh");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //更新订单信息
    private void  updateOrder(Map<Object, Object> map) {
        //TODO:支付成功后更新订单的逻辑。
    }
}												
											微信公众号授权,支付,退款总结【shoucang】的更多相关文章
- 【tp5.1】微信公众号授权登录及获取信息录入数据库
		
微信公众号开发文档链接:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432 微信公众号授权登录分为两种: 1.以 ...
 - 微信公众号JSAPI支付
		
微信公众号JSAPI支付 一:配置参数 申请成功后,获取接口文件, 将所有文件放入项目根目录weixin下,在WxPay.ub.config.php中填入配置账户信息; 二:设置授权 开发者中心-&g ...
 - uniapp - 微信公众号授权登录
		
[缘由] 采用uniapp进行微信小程序和微信公众号双版本开发:考虑到用户唯一性,我们后端确定了以“unionid”.作为唯一标识. 有的小伙伴估计也是刚入这坑,我就简单说一下步骤流程 [摸索] ...
 - 网站如何接入微信公众号JSAPI支付PHP版
		
1.首先,我们要有一个微信公众号(分类类型有订阅号,服务号,企业号)我们的微信公众号一定是个服务号只有它才有微信支付接口.. 并且这个微信公众号一定要进行微信认证才能申请微信支付接口. 2.申请JSA ...
 - 微信公众号JSAPI支付-多公众号向同一商户号支付的问题解决
		
一.背景 项目提供公众号商城集成,在公众号里进行商品的购买,并与多家公众号合作增加渠道流量. . 二.实现 有关微信公众号.商户号的开通与支付绑定不细说 从背景里可知,我们需要实现多个公众号购买向同一 ...
 - java微信公众号JSAPI支付以及所遇到的坑
		
上周做了个支付宝微信扫码支付,今天总结一下.微信相比支付宝要麻烦许多 由于涉及到代理商,没办法,让我写个详细的申请流程,懵逼啊. 笔记地址 http://note.youdao.com/notesha ...
 - PHP应用如何对接微信公众号JSAPI支付
		
微信支付的产品有很多,1. JSAPI支付 2. APP支付 3. Native支付 4.付款码支付 5. H5支付. 其中基于微信公众号开发的应用选择“JSAPI支付“产品,其他APP支付需 ...
 - 微信公众号H5支付遇到的那些坑
		
简史 官方文档说的很清楚,商户已有H5商城网站,用户通过消息或扫描二维码在微信内打开网页时,可以调用微信支付完成下单购买的流程. 当然,最近微信支付平台也加入了纯H5支付,也就是说用户可以在微信以外的 ...
 - 解决微信公众号授权登录和开放平台微信第三方应用授权登录获取到的用户Openid关联问题
		
开发背景: 最近一段时间一直在做关于微信方面的网站应用开发,这段时间也收获的不少关于微信开发方面的开发技能,接触的比较多的主要有微信公众号和微信网站app第三方登录授权,以及微信会员卡,优惠券和扫描二 ...
 
随机推荐
- Charles配置抓取HTTPS请求的Android配置
			
关于android手机在mac版charles上抓不到包这个问题困扰了很久,查阅了很多资料,发现是android7.0系统安全策略问题. Charles抓包正常流程1.在手机上配置证书 点击后:直接在 ...
 - C语言+嵌入式SQL+DB2开发经验总结
			
1.使用DB2工具将SQC文件预编译成C文件和bnd文件. 命令: db2 prep ***.sqc version * package using * bindfile BLOCKING ALL I ...
 - [转]kaldi 神经网络
			
转自:http://blog.csdn.net/xmdxcsj/article/details/54695506 overview type author CPU/GPU feature nnet1 ...
 - Hive数仓之快速入门(二)
			
上次已经讲了<Hive数据仓库之快速入门一>不记得的小伙伴可以点击回顾一下,接下来我们再讲Hive数据仓库之快速入门二 DQL hive中的order by.distribute by.s ...
 - 小程序入口构造工具&二维码测试工具
			
小程序入口构造工具&二维码测试工具 本文将介绍我们小程序中隐藏的两个工具页面.原理虽不复杂,收益却实实在在,或许也能给诸君带来启发. 入口构造工具 痛点 PM&运营 投放链接 PM&a ...
 - Spring lazy-init 原理分析
			
普通的bean的初始化是在容器启动初始化阶段执行的,而被lazy-init修饰的bean 则是在从容器里第一次进行context.getBean(“”)时进行触发.Spring 启动的时候会把所有be ...
 - jquery.jtable的事件
			
前景提要最近在使用abp zero框架帮朋友搭建一个工厂管理系统.其中有一块功能的话是通过定时爬虫拉取当日的铝价.铝价展示用的是abp zero框架中土牛写的jquery.jtable,铝价需要根据当 ...
 - 剑指offer【05】- 用两个栈实现队列(java)
			
题目:用两个栈实现队列 考点:栈和队列 题目描述:用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 解题思路:每次psuh是时先将stack2清空放入stck1(保 ...
 - python之获取当前操作系统(平台)
			
Python在不同环境平台使用时,需要判断当前是什么系统,比如常用的windows,linux等 下面介绍一些能够获取当前系统的命令 1.使用sys.platform获取 #!/usr/bin/env ...
 - vue 关于图片路径的问题
			
在vue 中,当我们想加载assets中的图片,本人按照多年的开发经验会这样写,那是没问题的 <img src="../assets.1.jpg"/> 如果我要用v-b ...