微信小程序> 小程序微信支付java服务端

小程序微信支付java服务端

浏览量:473 时间: 来源:花未央D8023

小程序

1、首先可以通过服务端来获取openid,openid可以作为自己平台微信用户身份的唯一标识。

    /**     * @Description: 获取openId     * @param: code 小程序授权后获得的code     * @Author: zhangpeng32     * @Date: 2018/3/11 17:39     * @Version: 1.0.0     */    @RequestMapping(value = "/getOpenId", method = RequestMethod.POST)    public BaseRespMapString, String getOpenId(String code, HttpServletRequest request) throws Exception{        if (StringUtils.isEmpty(code)) {            return new BaseRespMapString, String(ResultStatus.error_weixin_user_code_empty);        }        //获取openId        String param = "?grant_type=" + PaymentConfig.GRANT_TYPE + "&appid=" + PaymentConfig.APPID + "&secret=" + PaymentConfig.API_KEY + "&js_code=" + code;        System.out.println(PaymentConfig.GET_OPEN_ID_URL + param);        //创建请求对象        String httpRet = PayUtils.httpRequest(PaymentConfig.GET_OPEN_ID_URL, "GET", param);        System.out.println(httpRet);        MapString, String result = new HashMapString, String();        JSONObject jsonObject = JSONObject.parseObject(httpRet);        if (jsonObject != null) {            Integer errcode = jsonObject.getInteger("errcode");            if (errcode != null) {                //返回异常信息                return new BaseRespMapString, String(errcode, jsonObject.getString("errmsg"), null);            }            result.put("openId", jsonObject.getString("openid"));            result.put("sessionKey", jsonObject.getString("session_key"));        }        return new BaseRespMapString, String(ResultStatus.SUCCESS, result);    }

2、调用支付统一下单API来获取prepay_id,并将小程序调起支付数据需要签名的字段appId,timeStamp,nonceStr,package再次签名。

特别要注意,调用官方的SDK默认的加密方式为HMACSHA256,SKD里面wxpay的初始化源码如下:

    public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport, final boolean useSandbox) throws Exception {        this.config = config;        this.notifyUrl = notifyUrl;        this.autoReport = autoReport;        this.useSandbox = useSandbox;        this.signType = SignType.MD5;        if (useSandbox) {            this.signType = SignType.MD5; // 沙箱环境        }        else {            this.signType = SignType.HMACSHA256;        }        this.wxPayRequest = new WXPayRequest(config);    }

我们在调用统一下单签名的时候,可以直接把这里的sign_type默认改为MD5

    public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport, final boolean useSandbox) throws Exception {        this.config = config;        this.notifyUrl = notifyUrl;        this.autoReport = autoReport;        this.useSandbox = useSandbox;        this.signType = SignType.MD5;/*        if (useSandbox) {            this.signType = SignType.MD5; // 沙箱环境        }        else {            this.signType = SignType.HMACSHA256;        }*/        this.wxPayRequest = new WXPayRequest(config);    }

使用微信支付的SDK调用微信支付比较简单,最新的SDK也不需要自己处理xml和map之间的转化,接口里面包含了签名的方法和签名验证的方法,在我调用统一下单接口的时候,开始报签名错误,自己要注意一下。可以通过微信签名验证工具来进行验证,工具的地址为:https://pay.weixin.qq.com/wiki/tools/signverify/。此处WXPayUtil为SDK自带的工具类,WXPayUtil.generateSignature生成签名,WXPayUtil.isSignatureValid直接可以在代码中组签名验证。

    @RequestMapping(value = "/doUnifiedOrder", method = RequestMethod.POST)    public BaseRespMapString, String doUnifiedOrder(@Valid WeixinInVo inVo, HttpServletRequest request, BindingResult bindingResult) {        if (bindingResult.hasErrors()) {            ListObjectError list = bindingResult.getAllErrors();            return new BaseRespMapString, String(ResultStatus.FAIL.getErrorCode(), list.get(0).getDefaultMessage(), null);        }        //根据id获取订单信息        SoOut soOut = soService.get(inVo.getSoId());        if (soOut == null) {            return new BaseRespMapString, String(ResultStatus.error_so_not_exist);        }        //订单已支付        if (soOut.getSoStatus() != So.SO_STATUS_WAIT_PAID) {            return new BaseRespMapString, String(ResultStatus.error_so_paid);        }        //生成的随机字符串        String nonce_str = WXPayUtil.generateNonceStr();        //获取客户端的ip地址        String spbill_create_ip = IpUtils.getIpAddr(request);        int price100 = soOut.getSoAmount().multiply(new BigDecimal(100)).intValue();        //统一下单接口        HashMapString, String data = new HashMapString, String();        data.put("appid", config.getAppID());        data.put("mch_id", config.getMchID());        data.put("nonce_str", nonce_str);        data.put("body", soOut.getSkuName());    //商品描述        data.put("out_trade_no", soOut.getId().toString());//商户订单号        data.put("total_fee", String.valueOf(price100));//支付金额,这边需要转成字符串类型,否则后面的签名会失败        data.put("spbill_create_ip", spbill_create_ip);        data.put("notify_url", PaymentConfig.WX_NOTIFY_URL);//支付成功后的回调地址        data.put("trade_type", PaymentConfig.TRADE_TYPE);//支付方式        data.put("openid", inVo.getOpenId());        //返回给小程序端需要的参数        MapString, String response = new HashMapString, String();        response.put("appId", config.getAppID());        try {            MapString, String rMap = wxpay.unifiedOrder(data);            System.out.println("统一下单接口返回: " + rMap);            String return_code = (String) rMap.get("return_code");//返回状态码            String result_code = (String) rMap.get("result_code");//            String nonceStr = WXPayUtil.generateNonceStr();            response.put("nonceStr", nonceStr);            Long timeStamp = System.currentTimeMillis() / 1000;            if ("SUCCESS".equals(return_code) && return_code.equals(result_code)) {                String prepayid = rMap.get("prepay_id");//                response.put("prepayid", rMap.get("prepay_id"));                response.put("package", "prepay_id="+prepayid);                response.put("signType", "MD5");                response.put("timeStamp", timeStamp + "");//这边要将返回的时间戳转化成字符串,不然小程序端调用wx.requestPayment方法会报签名错误                System.out.println("二次签名参数response : "+response);                //再次签名,这个签名用于小程序端调用wx.requesetPayment方法                String sign = WXPayUtil.generateSignature(response, PaymentConfig.API_KEY);                response.put("paySign", sign);                System.out.println("生成的签名paySign : "+ sign);                return new BaseRespMapString, String(ResultStatus.SUCCESS, response);            }else{                return new BaseRespMapString, String(ResultStatus.error_unified_order_fail.getErrorCode(), rMap.get("err_code_des"), null);            }        } catch (Exception e) {            e.printStackTrace();            return new BaseRespMapString, String(ResultStatus.FAIL, response);        }    }

注意:所有的签名加密方式一定要全部是MD5,这个问题卡了我两天,最后跟进代码到sdk源码中才找到问题。

3、微信支付结果通知,这里就是统一支付接口定义的回调url,只能在公网上进行测试验证。

比如我定义的是:

    //支付成功后的服务器回调url    public static final String WX_NOTIFY_URL = "https://xxxxxx.com/wxpay/wxNotify";

    @RequestMapping(value = "/wxNotify")    public void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {        //读取参数        BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));        String line = null;        StringBuilder sb = new StringBuilder();        while ((line = br.readLine()) != null) {            sb.append(line);        }        //sb为微信返回的xml        String notifyData = sb.toString();  //支付结果通知的xml格式数据        System.out.println("支付结果通知的xml格式数据:" + notifyData);        Map notifyMap = WXPayUtil.xmlToMap(notifyData);       // 转换成map        String resXml = "";        if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {            // 签名正确            if ("SUCCESS".equals(notifyMap.get("result_code"))) {                //这里是支付成功                //////////执行自己的业务逻辑////////////////                String mch_id = (String) notifyMap.get("mch_id"); //商户号                String openid = (String) notifyMap.get("openid");  //用户标识                String out_trade_no = (String) notifyMap.get("out_trade_no"); //商户订单号                String total_fee = (String) notifyMap.get("total_fee");                String transaction_id = (String) notifyMap.get("transaction_id"); //微信支付订单号                //查询订单 根据订单号查询订单  SoOut -订单实体类                Long soId = Long.valueOf(out_trade_no);                SoOut soOut = soService.get(soId);                if (!PaymentConfig.MCH_ID.equals(mch_id) || soOut == null || new BigDecimal(total_fee).compareTo(soOut.getSoAmount().multiply(new BigDecimal(100))) != 0) {                    logger.info("支付失败,错误信息:" + "参数错误");                    resXml = "xml" + "return_code![CDATA[FAIL]]/return_code" + "return_msg![CDATA[参数错误]]/return_msg" + "/xml ";                } else {                    // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功                    if (So.SO_STATUS_WAIT_PAID == soOut.getSoStatus()) {//支付的状态判断                        //订单状态的修改。根据实际业务逻辑执行                        int ret = soService.paid(inVo);                        resXml = "xml" + "return_code![CDATA[SUCCESS]]/return_code" + "return_msg![CDATA[OK]]/return_msg" + "/xml ";                    } else {                        resXml = "xml" + "return_code![CDATA[SUCCESS]]/return_code" + "return_msg![CDATA[OK]]/return_msg" + "/xml ";                        logger.info("订单已处理");                    }                }            } else {                logger.info("支付失败,错误信息:" + notifyMap.get("err_code"));                resXml = "xml" + "return_code![CDATA[FAIL]]/return_code" + "return_msg![CDATA[报文为空]]/return_msg" + "/xml ";            }        } else {            // 签名错误,如果数据里没有sign字段,也认为是签名错误            resXml = "xml" + "return_code![CDATA[FAIL]]/return_code" + "return_msg![CDATA[通知签名验证失败]]/return_msg" + "/xml ";            logger.info("通知签名验证失败");        }        //------------------------------        //处理业务完毕        //------------------------------        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());        out.write(resXml.getBytes());        out.flush();        out.close();    }

一定要注意参数的大小写,字符编码为UTF-8。

pom.xml增加微信sdk:

        dependency            groupIdcom.github.wxpay/groupId            artifactIdwxpay-sdk/artifactId            version0.0.3/version        /dependency

另外sdk的github地址为:https://github.com/wxpay/WXPay-SDK-Java。可以自己进行修改和编译打包。

如果有其他问题,请联系我。


版权声明

即速应用倡导尊重与保护知识产权。如发现本站文章存在版权问题,烦请提供版权疑问、身份证明、版权证明、联系方式等发邮件至197452366@qq.com ,我们将及时处理。本站文章仅作分享交流用途,作者观点不等同于即速应用观点。用户与作者的任何交易与本站无关,请知悉。

产品经理

手机 : 13312967497

擅长 : 小程序流量变现

扫码领取礼包

热门模板

  • 头条
  • 搜狐
  • 微博
  • 百家
  • 一点资讯
  • 知乎