微信小程序、app集成微信支付

一、微信小程序支付

开发文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_11&index=2

申请小程序开发者账号,进行微信认证,获取appid,开通微信支付,即绑定申请的微信支付商户号。

1.小程序支付流程:

å°ç¨åºæ¯ä»æ¶åºå¾

2.商户系统和微信支付系统主要交互:

      1、小程序内调用登录接口,获取到用户的openid。

      2、商户调用支付接口统一下单。

      3、商户再次签名后返回发起支付需要的参数。

      4、商户调起微信支付控件后付款,并接收支付通知处理账单状态。

3.微信统一下单:

接口链接:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1

URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder

然后编写我们自己的支付服务调用该下单接口。

支付controller:

   /**
     * 付款
     *
     * @param  request
     * @param  openid   用户标识
     * @param  tradeType    交易类型 小程序取值如下:JSAPI  APP--app支付      
     * @return
     */
    @RequestMapping("/payment")
    public Object payment(String openid, String body, String tradeType, HttpServletRequest request) {
        //userId从session中获取即可
        return payService.payment(userId, openid, body, tradeType, request);
    }

支付服务:

@Service
public class PayService  {

    @Resource
    private IPayDetailService payDetailService;

    /**
     * 小程序appid
     */
    @Value("${wx.applet.appid}")
    String wx_applet_appid;

    /**
     * APP移动应用端appid
     */
    @Value("${app.appid}")
    String app_appid;
    /**
     * 微信小程序商户平台商户号
     */
    @Value("${wx.sh.mch_id}")
    String mchId;

    /**
     * 微信app商户平台商户号
     */
    @Value("${wx.app.mch_id}")
    String appMchId;

    /**
     * 付款
     *
     * @param userId
     * @param openid
     * @param body
     * @param tradeType    交易类型 小程序取值如下:JSAPI  APP--app支付
     * @param request
     * @return
     */
    @Transactional
    @Override
    public ServiceResult payment(String userId, String openid, String body, String tradeType, HttpServletRequest request) {
        //生成订单号
        String orderNumber = GenerateNum.getInstance().GenerateOrder();
                //微信支付调用统一下单接口
                //小程序端
                if (!StringUtils.isEmpty(tradeType) && PayConstant.TRADE_TYPE_WX_APPLET.equals(tradeType)) {
                    return payDetailService.wxPaybill(wx_applet_appid, mchId, orderNumber, PayConstant.WX_PAY_NOTIFY_URL, PayConstant.TRADE_TYPE_WX_APPLET,
                            openid, order.getActuallyPayMoney(), body, IPUtil.getIpAddr(request));
                    //app端
                } else if (!StringUtils.isEmpty(tradeType) && PayConstant.TRADE_TYPE_APP.equals(tradeType)) {
                    return payDetailService.wxPaybill(app_appid, appMchId, orderNumber, PayConstant.WX_PAY_NOTIFY_URL, PayConstant.TRADE_TYPE_APP,
                            null, order.getActuallyPayMoney(), body, IPUtil.getIpAddr(request));
                }
            } 
        return ServiceResultHelper.genResultWithFaild();
    } 
  

下单服务:

/**
     * 微信下单
     *
     * @param appId            APP端或者小程序appid
     * @param mchId            商户号
     * @param orderNumber      订单编号
     * @param notifyUrl        通知url
     * @param tradeType        交易类型
     * @param openid           用户标识
     * @param totalFee         订单总金额,单位为分
     * @param body             商品描述
     * @param spbill_create_ip APP和网页支付提交用户端ip
     * @return
     */
    @Override
    public ServiceResult wxPaybill(String appId, String mchId, String orderNumber, String notifyUrl, String tradeType,
                                           String openid, BigDecimal totalFee, String body, String spbill_create_ip) {
        try {
            if (StringUtils.isEmpty(orderNumber)) {
                return ServiceResultHelper.genResultWithFaild("订单号不能为空", -1);
            }
            //生成的随机字符串
            String nonce_str = CharacterUtil.getRandomString(32);
            //组装参数,用户生成统一下单接口的签名
            Map packageParams = new HashMap<>();
            if (!StringUtils.isEmpty(openid)) {
                packageParams.put("openid", openid);
            }
            packageParams.put("appid", appId);
            packageParams.put("mch_id", mchId);
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("body", body);
            packageParams.put("out_trade_no", orderNumber);//订单号
            packageParams.put("total_fee", totalFee.toString());//支付金额,这边需要转成字符串类型,否则后面的签名会失败
            packageParams.put("spbill_create_ip", spbill_create_ip);
            packageParams.put("notify_url", notifyUrl);//支付成功后的回调地址
            packageParams.put("trade_type", tradeType);//支付方式

            String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串

            //MD5运算生成签名,这里是第一次签名,用于调用统一下单接口
            String sign = PayUtil.sign(prestr, PayConstant.WX_PAY_PAY_KEY, "utf-8").toUpperCase();

            //拼接统一下单接口使用的xml数据,要将上一步生成的签名一起拼接进去
            packageParams.put("sign", sign);
            String xml = MapXmlUtil.map2Xmlstring(packageParams);
            LOG.info("调用统一下单接口请求XML数据:" + xml);

            //调用统一下单接口,并接受返回的结果
            String result = PayUtil.httpRequest(PayConstant.WX_PAY_BILL_URL, "POST", xml);

            LOG.info("调用统一下单接口返回XML数据:" + result);
            if (StringUtils.isEmpty(result)) {
                return ServiceResultHelper.genResultWithFaild("调用统一下单接口返回结果为空", -1);
            }

            // 将解析结果存储在HashMap中
            Map map = MapXmlUtil.xmlString2Map(result);
            String return_code = (String) map.get("return_code");//返回状态码
            Map data = new HashMap<>();//返回给小程序端需要的参数
            String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
            if (PayConstant.PAY_ORDER_SUCCESS.equals(return_code)) {
                //小程序的返回值
                if (!StringUtils.isEmpty(openid)) {
                    data.put("appId", appId);
                    data.put("nonceStr", nonce_str);
                    data.put("package", "prepay_id=" + prepay_id);
                    data.put("signType", "MD5");
                    Long timeStamp = System.currentTimeMillis() / 1000;
                    data.put("timeStamp", timeStamp + "");//这边要将返回的时间戳转化成字符串,不然小程序端调用wx.requestPayment方法会报签名错误
                    //拼接签名需要的参数
                    String stringSignTemp = PayUtil.createLinkString(data);
                    //再次签名,这个签名用于小程序端调用wx.requesetPayment方法
                    String paySign = PayUtil.sign(stringSignTemp, PayConstant.WX_PAY_PAY_KEY, "utf-8").toUpperCase();
                    data.put("paySign", paySign);
                } else {
                    //app的返回值
                    data.put("appid", appId);
                    data.put("partnerid", mchId);
                    data.put("prepayid", prepay_id);
                    data.put("noncestr", nonce_str);
                    Long timeStamp = System.currentTimeMillis() / 1000;
                    data.put("timestamp", timeStamp + "");
                    data.put("package", "Sign=WXPay");
                    String stringSignTemp = PayUtil.createLinkString(data);
                    String appSign = PayUtil.sign(stringSignTemp, PayConstant.WX_PAY_PAY_KEY, "utf-8").toUpperCase();
                    data.put("sign", appSign);
                }
                return ServiceResultHelper.genResultWithSuccess(data);
            }
            return ServiceResultHelper.genResultWithFaild(map.get("return_msg") != null ? map.get("return_msg").toString() : null, -1);
        } catch (Exception e) {
            LOG.info("下单异常:" + e.getMessage());
            return ServiceResultHelper.genResultWithFaild(e.getMessage(), -1);
        } 
  

调用微信下单接口返回结果:

字段名 变量名 必填 类型 示例值 描述
返回状态码 return_code String(16) SUCCESS

SUCCESS/FAIL

此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断

返回信息 return_msg String(128) 签名失败

返回信息,如非空,为错误原因

签名失败

参数格式校验错误

paySign为再次签名,这个签名用于小程序端调用wx.requesetPayment方法,调起微信支付控件。

requesetPayment 参数说明:

参数 类型 必填 说明
timeStamp String 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间
nonceStr String 随机字符串,长度为32个字符以下。
package String 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
signType String 签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致
paySign String 签名,具体签名方案参见微信公众号支付帮助文档;
success Function 接口调用成功的回调函数
fail Function 接口调用失败的回调函数
complete Function 接口调用结束的回调函数(调用成功、失败都会执行)

调用wx.requestPayment(OBJECT)发起微信支付。所以在调用下单接口成功后要返回需要的参数。详见下单服务代码小程序返回参数部分。

获取ip地址工具:

import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest;

public class IPUtil {
    public IPUtil() {
    }

    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            if (ip.equals("127.0.0.1") || ip.equals("0:0:0:0:0:0:0:1")) {
                InetAddress inet = null;

                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException var4) {
                    var4.printStackTrace();
                }

                ip = inet.getHostAddress();
            }
        }

        if (ip != null && ip.length() > 15 && ip.indexOf(",") > 0) {
            ip = ip.substring(0, ip.indexOf(","));
        }

        return ip;
    }
}

订单号生成工具:


import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 订单号生成工具
 */
public class GenerateNum {

    // 使用单例模式,不允许直接创建实例
    private GenerateNum() {
    }

    // 创建一个空实例对象,类需要用的时候才赋值
    private static GenerateNum g = null;

    // 单例模式--懒汉模式
    public static synchronized GenerateNum getInstance() {
        if (g == null) {
            g = new GenerateNum();
        }
        return g;
    }

    // 全局自增数
    private static int count = 0;
    // 每毫秒秒最多生成多少订单(最好是像9999这种准备进位的值)
    private static final int total = 9999;
    // 格式化的时间字符串
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");

    // 获取当前时间年月日时分秒毫秒字符串
    private static String getNowDateStr() {
        return sdf.format(new Date());
    }

    // 记录上一次的时间,用来判断是否需要递增全局数
    private static String now = null;

    /*
     * 生成一个订单号
     */
    public synchronized String GenerateOrder() {
        String datastr = getNowDateStr();
        if (datastr.equals(now)) {
            count++;// 自增
        } else {
            count = 1;
            now = datastr;
        }
        int countInteger = String.valueOf(total).length() - String.valueOf(count).length();// 算补位
        String bu = "";// 补字符串
        for (int i = 0; i < countInteger; i++) {
            bu += "0";
        }
        bu += String.valueOf(count);
        if (count >= total) {
            count = 0;
        }
        return datastr + bu;
    }
}

签名字符串工具:用于MD5运算生成签名,调用统一下单接口,并接受返回的结果


import org.apache.commons.codec.digest.DigestUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.SignatureException;
import java.util.*;

public class PayUtil {
    /**
     * 签名字符串
     *
     * @param text 需要签名的字符串
     * @param key  密钥
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static String sign(String text, String key, String input_charset) {
        text = text + "&key=" + key;
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));
    }

    /**
     * 签名字符串
     *
     * @param text 需要签名的字符串
     * @param sign          签名结果
     * @param key 密钥
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static boolean verify(String text, String sign, String key, String input_charset) {
        text = text + key;
        String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
        if (mysign.equals(sign)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * @param content
     * @param charset
     * @return
     * @throws SignatureException
     * @throws UnsupportedEncodingException
     */
    public static byte[] getContentBytes(String content, String charset) {
        if (charset == null || "".equals(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
        }
    }

    private static boolean isValidChar(char ch) {
        if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
            return true;
        if ((ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f))
            return true;// 简体中文汉字编码
        return false;
    }

    /**
     * 除去数组中的空值和签名参数
     *
     * @param sArray 签名参数组
     * @return 去掉空值与签名参数后的新签名参数组
     */
    public static Map paraFilter(Map sArray) {
        Map result = new HashMap();
        if (sArray == null || sArray.size() <= 0) {
            return result;
        }
        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
                    || key.equalsIgnoreCase("sign_type")) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }

    /**
     * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
     *
     * @param params 需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     */
    public static String createLinkString(Map params) {
        List keys = new ArrayList(params.keySet());
        Collections.sort(keys);
        String prestr = "";
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value =(String) params.get(key);
            if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }
        return prestr;
    }



    public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {
        // 创建SSLContext
        StringBuffer buffer = null;
        try {
            URL url = new URL(requestUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod(requestMethod);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.connect();
            //往服务器端写内容
            if (null != outputStr) {
                OutputStream os = conn.getOutputStream();
                os.write(outputStr.getBytes("utf-8"));
                os.close();
            }
            // 读取服务器端返回的内容
            InputStream is = conn.getInputStream();
            InputStreamReader isr = new InputStreamReader(is, "utf-8");
            BufferedReader br = new BufferedReader(isr);
            buffer = new StringBuffer();
            String line = null;
            while ((line = br.readLine()) != null) {
                buffer.append(line);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return buffer.toString();
    }
}

Map和xml互相转换工具:


import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.util.*;

public class MapXmlUtil {

    /**
     * Map转换成Xml
     *
     * @param map
     * @return
     */
    public static String map2Xmlstring(Map map) {
        StringBuffer sb = new StringBuffer("");
        sb.append("");

        Set set = map.keySet();
        for (Iterator it = set.iterator(); it.hasNext(); ) {
            String key = it.next();
            Object value = map.get(key);
            sb.append("<").append(key).append(">");
            sb.append(value);
            sb.append("");
        }
        sb.append("");
        return sb.toString();
    }


    /**
     * Xml string转换成Map
     *
     * @param xmlStr
     * @return
     */
    public static Map xmlString2Map(String xmlStr) {
        Map map = new HashMap();
        Document doc;
        try {
            doc = DocumentHelper.parseText(xmlStr);
            Element el = doc.getRootElement();
            map = recGetXmlElementValue(el, map);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 循环解析xml
     *
     * @param ele
     * @param map
     * @return
     */
    @SuppressWarnings({"unchecked"})
    private static Map recGetXmlElementValue(Element ele, Map map) {
        List eleList = ele.elements();
        if (eleList.size() == 0) {
            map.put(ele.getName(), ele.getTextTrim());
            return map;
        } else {
            for (Iterator iter = eleList.iterator(); iter.hasNext(); ) {
                Element innerEle = iter.next();
                recGetXmlElementValue(innerEle, map);
            }
            return map;
        }
    }
}

常量配置:



public class PayConstant {

    /**
     * 标价币种 默认人民币:CNY
     */
    public static final String FEE_TYPE_DEFAULT = "CNY";

    /**
     * 交易类型 小程序取值如下:JSAPI  APP--app支付
     */
    public static final String TRADE_TYPE_WX_APPLET = "JSAPI";

    public static final String TRADE_TYPE_APP = "APP";

    /**
     * 统一下单调用接口
     */
    public static final String PAY_ORDER_SUCCESS = "SUCCESS";

    public static final String PAY_ORDER_MSG = "OK";

    public static final String PAY_ORDER_FAIL="FAIL";

    /**
     * 支付方式  1:微信  2:支付宝
     */
    public static final Integer PAY_WAY_WX = 1;
    public static final Integer PAY_WAY_ZFB = 2;

    /**
     * 支付结果
     */
    public static final Integer PAY_RESULT_SUCCESS = 1;
    public static final Integer PAY_RESULT_FAIL = 0;//失败

    /**
     * 下单
     */
    public static final String WX_PAY_BILL_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    /**
     * 微信服务器支付结果回调通知url
     */
    public static String WX_PAY_NOTIFY_URL="https://applet.cnyang.com/wx-api/pay/wxPayBillCallback";

    /**
     * 商户平台API密钥
     */
    public static final String WX_PAY_PAY_KEY="GURkraWQOG5rrQFeQdXuACLwsCEGievVasa";


    /**
     * 订单状态 0:删除 1:已完成 2:未付款  3:待发货 4:待收货 5:待评价 6:已取消
     */
    public static final Integer ORDER_STATUS_DEL = 0;
    public static final Integer ORDER_STATUS_FINISH = 1;
    public static final Integer ORDER_STATUS_NO_PAY = 2;
    public static final Integer ORDER_STATUS_WAIT_DELIVERY = 3;
    public static final Integer ORDER_STATUS_ALREADY_DELIVERY = 4;
    public static final Integer ORDER_STATUS_WAIT_EVALUATION = 5;
    public static final Integer ORDER_STATUS_CANCLE = 6;

}

二、app支付

app开发文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_1

微信开放平台申请移动应用:

微信小程序、app集成微信支付_第1张图片

认证通过并申请开通微信支付接口调用权限:

微信小程序、app集成微信支付_第2张图片

商户在APP集成微信支付后,会跳转到微信中完成支付,支付完后跳回到商户APP内,最后展示支付结果。

1.app支付流程图:

APPæ¯ä»æ¶åºå¾

商户系统和微信支付系统主要交互说明:

步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。

步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。

步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appid,partnerid,prepayid,noncestr,timestamp,package。注意:package的值格式为Sign=WXPay

步骤4:商户APP调起微信支付。

步骤5:商户后台接收支付通知。

步骤6:商户后台查询支付结果

app支付调用下单服务时openid传值null,openid用于微信小程序下单。

2.支付服务、下单服务

这部分的代码和小程序的代码放在一起做了封装,详见上文。

app端调起支付控件所需的参数和小程序不一样。

下单成功后所需参数返回。

APP端调起支付的参数列表

字段名 变量名 类型 必填 示例值 描述
应用ID appid String(32) wx8888888888888888 微信开放平台审核通过的应用APPID
商户号 partnerid String(32) 1900000109 微信支付分配的商户号
预支付交易会话ID prepayid String(32) WX1217752501201407033233368018 微信返回的支付交易会话ID
扩展字段 package String(128) Sign=WXPay 暂填写固定值Sign=WXPay
随机字符串 noncestr String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,不长于32位。推荐随机数生成算法
时间戳 timestamp String(10) 1412000000 时间戳,请见接口规则-参数规定
签名 sign String(32) C380BEC2BFD727A4B6845133519F3AD6 签名,详见签名生成算法注意:签名方式一定要与统一下单接口使用的一致

详见app端开发步骤:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5 。

三、微信支付回调接口


    /**
     * 微信支付回调
     *
     * @param resultXMLEntity 微信支付结果异步推送XML数据包实体
     * @return
     */
    @Transactional
    @Override
    public String wxPayBillCallback(PayResultXMLEntity resultXMLEntity) {
        Map result = new HashMap<>();
        LOG.info("resultXMLEntity:" + resultXMLEntity.toString());
        if (resultXMLEntity == null) {
            LOG.error("微信支付结果异步推送XML数据包实体为空");
            result.put("return_code", PayConstant.PAY_ORDER_FAIL);
            result.put("return_msg", "微信支付结果异步推送XML数据包实体为空");
            return MapXmlUtil.map2Xmlstring(result);
        }
        if (!StringUtils.isEmpty(resultXMLEntity.getOutTradeNo())) {
            ServiceResult payDetailRet = getPayDetailByOrderNumber(resultXMLEntity.getOutTradeNo());
            if (payDetailRet != null && payDetailRet.isSucceed() && payDetailRet.getData() != null) {
                //已经支付成功,再次通知则不做处理
                if (payDetailRet.getData().getPayStatus() != null && payDetailRet.getData().getPayStatus().equals(PayConstant.PAY_RESULT_SUCCESS)) {
                    result.put("return_code", PayConstant.PAY_ORDER_SUCCESS);
                    result.put("return_msg", PayConstant.PAY_ORDER_MSG);
                    return MapXmlUtil.map2Xmlstring(result);
                }
            } else {
                result.put("return_code", PayConstant.PAY_ORDER_FAIL);
                result.put("return_msg", "订单号不存在");
                return MapXmlUtil.map2Xmlstring(result);
            }
        }
        if (!StringUtils.isEmpty(resultXMLEntity.getReturnCode())) {
            //生成订单号
            PayDetailAO payDetail = new PayDetailAO();
            if (resultXMLEntity.getReturnCode().equals(PayConstant.PAY_ORDER_SUCCESS)) {
                //更新订单状态
                orderService.updateOrder(resultXMLEntity.getOutTradeNo(), PayConstant.ORDER_STATUS_WAIT_DELIVERY, resultXMLEntity.getTimeEnd());
                //更新支付状态
                payDetail.setPayStatus(PayConstant.PAY_RESULT_SUCCESS);
            } else if (resultXMLEntity.getReturnCode().equals(PayConstant.PAY_ORDER_FAIL)) {
                payDetail.setPayStatus(PayConstant.PAY_RESULT_FAIL);
            }
            payDetail.setSerialNumber(resultXMLEntity.getTransactionId());//支付流水号
            payDetail.setUpdateTime(!StringUtils.isEmpty(resultXMLEntity.getTimeEnd()) ?
                    DateUtil.parseStrToDate(resultXMLEntity.getTimeEnd(), DateUtil.DATE_FORMAT_6) : null);
            //更新支付信息
            PayDetailCriteria criteria = new PayDetailCriteria();
            criteria.createCriteria().andOrderNumberEqualTo(resultXMLEntity.getOutTradeNo());
            ServiceResult payOrderRet = updateByCriteriaSelective(payDetail, criteria);
            if (payOrderRet != null && payOrderRet.isSucceed() && payOrderRet.getData() > 0) {
                LOG.info("微信支付成功");
                result.put("return_code", PayConstant.PAY_ORDER_SUCCESS);
                result.put("return_msg", PayConstant.PAY_ORDER_MSG);
                return MapXmlUtil.map2Xmlstring(result);
            }
        }
        result.put("return_code", PayConstant.PAY_ORDER_FAIL);
        result.put("return_msg", "微信支付结果通知处理失败");
        return MapXmlUtil.map2Xmlstring(result);
    }

收到微信支付结果通知后,按照示例返回参数给微信支付:

字段名 变量名 必填 类型 示例值 描述
返回状态码 return_code String(16) SUCCESS

请按示例值填写

返回信息 return_msg String(128) OK

请按示例值填写

举例如下:

  
  

四.测试

微信小程序支付:

微信小程序、app集成微信支付_第3张图片

   根据返回的参数即可在微信小程序端调起控件发起支付:

微信小程序、app集成微信支付_第4张图片

app支付:

微信小程序、app集成微信支付_第5张图片

  根据返回的参数即可在app端调起控件发起支付:

微信小程序、app集成微信支付_第6张图片

注意:微信小程序和app签名参数的大小写不同。

你可能感兴趣的:(微信支付)