微信小程序> 微信小程序支付(Java)

微信小程序支付(Java)

浏览量:475 时间: 来源:福尔摩帅

相信进行过微信公众号支付的同学对于微信小程序支付的开发上手很快,如下是微信官方对三种接入方式的对比

小程序

注意坑一:发起支付必须是HTTPS

流程

然后我们整理下发起订单的思路。如下是官方给的流程图,发起支付已经做了标注。

小程序

由此可见,服务器端发起订单需要以下五小步,我们来各个击破。

第一步:获取openid

第二步:生成商户订单

第三步:调用支付统一下单API

第四步:获取预支付会话标识 prepayId

第五步:将组合数据签名并返回

第一步:获取openId(跳过)

获取openId不做赘述,自行百度。

第二步:生成商户订单

这里由我们系统内部生成。官方API如下(官方建议用当前系统时间加随机序列来生成订单号):

小程序

生成商户订单号代码如下(仅供参考)

public static String getRandomOrderId() {        Random random = new Random(System.currentTimeMillis());        int value = random.nextInt();        while (value  0) {            value = random.nextInt();        }        return value + "";    }

第三步:调用统一下单支付API

下面进行第三步调用支付统一下单API(将必传参数整理成xml格式,发送给下单url):

注意坑二:参数名按照字典序排序、参数值为空不参与签名、区分大小写、sign参数不参与签名!

注意坑三:在结尾拼接要key、进行签名运算后的sign要转化成大写!详见官方“签名算法说明”

官方API说明:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1

签名算法说明:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3

整理的格式如下,然后发送到下单url。代码如下

xml
   appidwx2421b1c4370ec43b/appid
   attach支付测试/attach
   bodyJSAPI支付测试/body
   mch_id10000100/mch_id
   detail![CDATA[{ "goods_detail":[ { "goods_id":"iphone6s_16G", "wxpay_goods_id":"1001", "goods_name":"iPhone6s 16G", "quantity":1, "price":528800, "goods_category":"123456", "body":"苹果手机" }, { "goods_id":"iphone6s_32G", "wxpay_goods_id":"1002", "goods_name":"iPhone6s 32G", "quantity":1, "price":608800, "goods_category":"123789", "body":"苹果手机" } ] }]]/detail
   nonce_str1add1a30ac87aa2db72f57a2375d8fec/nonce_str
   notify_urlhttp://wxpay.wxutil.com/pub_v2/pay/notify.v2.php/notify_url
   openidoUpF8uMuAJO_M2pxb1Q9zNjWeS6o/openid
   out_trade_no1415659990/out_trade_no
   spbill_create_ip14.23.150.211/spbill_create_ip
   total_fee1/total_fee
   trade_typeJSAPI/trade_type
   sign0CB01533B8C1EF103065174F50BCA001/sign

/xml

代码如下,仅供参考

    /**     * 调用统一下单接口     * @param openId     */    private String unifiedOrder(String openId, String clientIP, String randomNonceStr) {        try {            String url = Constant.URL_UNIFIED_ORDER;            PayInfo payInfo = createPayInfo(openId, clientIP, randomNonceStr);            String md5 = getSign(payInfo);            payInfo.setSign(md5);            log.error("md5 value: " + md5);            String xml = CommonUtil.payInfoToXML(payInfo);            xml = xml.replace("__", "_").replace("![CDATA[1]]", "1");            //xml = xml.replace("__", "_").replace("![CDATA[", "").replace("]]", "");            log.error(xml);            StringBuffer buffer = HttpUtil.httpsRequest(url, "POST", xml);            log.error("unifiedOrder request return body: " + buffer.toString());            MapString, String result = CommonUtil.parseXml(buffer.toString());            String return_code = result.get("return_code");            if(StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")) {                String return_msg = result.get("return_msg");                if(StringUtils.isNotBlank(return_msg) && !return_msg.equals("OK")) {                    //log.error("统一下单错误!");                    return "";                }                String prepay_Id = result.get("prepay_id");                return prepay_Id;            } else {                return "";            }        } catch (Exception e) {            e.printStackTrace();        }        return "";    }

/**     * 生成订单信息     * @param openId * @param clientIP * @param randomNonceStr     */    private PayInfo createPayInfo(String openId, String clientIP, String randomNonceStr) {        Date date = new Date();        String timeStart = TimeUtils.getFormatTime(date, Constant.TIME_FORMAT);        String timeExpire = TimeUtils.getFormatTime(TimeUtils.addDay(date, Constant.TIME_EXPIRE), Constant.TIME_FORMAT);        String randomOrderId = CommonUtil.getRandomOrderId();        PayInfo payInfo = new PayInfo();        payInfo.setAppid(Constant.APP_ID);        payInfo.setMch_id(Constant.MCH_ID);        payInfo.setDevice_info("WEB");        payInfo.setNonce_str(randomNonceStr);        payInfo.setSign_type("MD5");  //默认即为MD5        payInfo.setBody("JSAPI支付测试");        payInfo.setAttach("支付测试4luluteam");        payInfo.setOut_trade_no(randomOrderId);        payInfo.setTotal_fee(1);        payInfo.setSpbill_create_ip(clientIP);        payInfo.setTime_start(timeStart);        payInfo.setTime_expire(timeExpire);        payInfo.setNotify_url(Constant.URL_NOTIFY);        payInfo.setTrade_type("JSAPI");        payInfo.setLimit_pay("no_credit");        payInfo.setOpenid(openId);        return payInfo;    }
/**     * 对订单信息签名     * @param payInfo     */    private String getSign(PayInfo payInfo) throws Exception {        StringBuffer sb = new StringBuffer();        sb.append("appid=" + payInfo.getAppid())                .append("&attach=" + payInfo.getAttach())                .append("&body=" + payInfo.getBody())                .append("&device_info=" + payInfo.getDevice_info())                .append("&limit_pay=" + payInfo.getLimit_pay())                .append("&mch_id=" + payInfo.getMch_id())                .append("&nonce_str=" + payInfo.getNonce_str())                .append("¬ify_url=" + payInfo.getNotify_url())                .append("&openid=" + payInfo.getOpenid())                .append("&out_trade_no=" + payInfo.getOut_trade_no())                .append("&sign_type=" + payInfo.getSign_type())                .append("&spbill_create_ip=" + payInfo.getSpbill_create_ip())                .append("&time_expire=" + payInfo.getTime_expire())                .append("&time_start=" + payInfo.getTime_start())                .append("&total_fee=" + payInfo.getTotal_fee())                .append("&trade_type=" + payInfo.getTrade_type())                .append("&key=" + Constant.APP_KEY);        log.error("排序后的拼接参数:" + sb.toString());        return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();    }


第四步:获取prepayId

第三步如果没问题,return_code 和result_code都为SUCCESS。则返回prepay_id(就是我们想要的预处理会话标识)如下所示:

xml
   return_code![CDATA[SUCCESS]]/return_code
   return_msg![CDATA[OK]]/return_msg
   appid![CDATA[wx2421b1c4370ec43b]]/appid
   mch_id![CDATA[10000100]]/mch_id
   nonce_str![CDATA[IITRi8Iabbblz1Jc]]/nonce_str
   openid![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]/openid
   sign![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]/sign
   result_code![CDATA[SUCCESS]]/result_code
   prepay_id![CDATA[wx201411101639507cbf6ffd8b0779950874]]/prepay_id
   trade_type![CDATA[JSAPI]]/trade_type

/xml

这里提供下思路,将xml格式转化成map。然后根据key=prepay_id 获取prepayId

工具类代码如下,仅供参考

public class CommonUtil {    public static String getRandomOrderId() {        // UUID.randomUUID().toString().replace("-","")        Random random = new Random(System.currentTimeMillis());        int value = random.nextInt();        while (value  0) {            value = random.nextInt();        }        return value + "";    }    private static XStream xstream = new XStream(new XppDriver() {        public HierarchicalStreamWriter createWriter(Writer out) {            return new PrettyPrintWriter(out) {                //增加CDATA标记                boolean cdata = true;                @SuppressWarnings("rawtypes")                public void startNode(String name, Class clazz) {                    super.startNode(name, clazz);                }                protected void writeText(QuickWriter writer, String text) {                    if (cdata) {                        writer.write("![CDATA[");                        writer.write(text);                        writer.write("]]");                    } else {                        writer.write(text);                    }                }            };        }    });    public static String payInfoToXML(PayInfo pi) {        xstream.alias("xml", pi.getClass());        return xstream.toXML(pi);    }    @SuppressWarnings("unchecked")    public static MapString, String parseXml(String xml) throws Exception {        MapString, String map = new HashMapString, String();        Document document = DocumentHelper.parseText(xml);        Element root = document.getRootElement();        ListElement elementList = root.elements();        for (Element e : elementList)            map.put(e.getName(), e.getText());        return map;    }
第五步:将组合数据签名并返回



版权声明

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

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