一、微信小程序支付

开发文档: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  {@Resourceprivate 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@Overridepublic ServiceResult<Object> 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*/@Overridepublic ServiceResult<Object> 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<String, Object> 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<String, Object> 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<String, String> paraFilter(Map<String, String> sArray) {Map<String, String> result = new HashMap<String, String>();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<String, Object> params) {List<String> keys = new ArrayList<String>(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) {// 创建SSLContextStringBuffer 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<String, Object> map) {StringBuffer sb = new StringBuffer("");sb.append("<xml>");Set<String> set = map.keySet();for (Iterator<String> it = set.iterator(); it.hasNext(); ) {String key = it.next();Object value = map.get(key);sb.append("<").append(key).append(">");sb.append(value);sb.append("</").append(key).append(">");}sb.append("</xml>");return sb.toString();}/*** Xml string转换成Map** @param xmlStr* @return*/public static Map<String, Object> xmlString2Map(String xmlStr) {Map<String, Object> map = new HashMap<String, Object>();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<String, Object> recGetXmlElementValue(Element ele, Map<String, Object> map) {List<Element> eleList = ele.elements();if (eleList.size() == 0) {map.put(ele.getName(), ele.getTextTrim());return map;} else {for (Iterator<Element> 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集成微信支付后,会跳转到微信中完成支付,支付完后跳回到商户APP内,最后展示支付结果。

1.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 。

三、微信支付回调接口

PayResultXMLEntity :


import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;/*** 微信支付结果异步推送XML数据包实体*/@XmlRootElement(name = "xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class PayResultXMLEntity {// 返回状态码@XmlElement(name = "return_code")protected String returnCode;// 返回信息@XmlElement(name = "return_msg")protected String returnMsg;// 业务结果@XmlElement(name = "result_code")protected String resultCode;// 商户订单号@XmlElement(name = "out_trade_no")protected String outTradeNo;// 支付完成时间@XmlElement(name = "time_end")protected String timeEnd;// 微信支付订单号@XmlElement(name = "transaction_id")protected String transactionId;// 微信支付订单号@XmlElement(name = "total_fee")protected String totalFee;// 微信支付订单号@XmlElement(name = "mch_id")protected String mchId;public void setReturnCode(String returnCode) {this.returnCode = returnCode;}public String getReturnMsg() {return returnMsg;}public void setReturnMsg(String returnMsg) {this.returnMsg = returnMsg;}public String getReturnCode() {return returnCode;}public String getResultCode() {return resultCode;}public void setResultCode(String resultCode) {this.resultCode = resultCode;}public String getOutTradeNo() {return outTradeNo;}public void setOutTradeNo(String outTradeNo) {this.outTradeNo = outTradeNo;}public String getTimeEnd() {return timeEnd;}public void setTimeEnd(String timeEnd) {this.timeEnd = timeEnd;}public String getTransactionId() {return transactionId;}public void setTransactionId(String transactionId) {this.transactionId = transactionId;}public String getTotalFee() {return totalFee;}public void setTotalFee(String totalFee) {this.totalFee = totalFee;}public String getMchId() {return mchId;}public void setMchId(String mchId) {this.mchId = mchId;}@Overridepublic String toString() {return "PayResultXMLEntity{" +"returnCode='" + returnCode + '\'' +", returnMsg='" + returnMsg + '\'' +", resultCode='" + resultCode + '\'' +", outTradeNo='" + outTradeNo + '\'' +", timeEnd='" + timeEnd + '\'' +", transactionId='" + transactionId + '\'' +", totalFee='" + totalFee + '\'' +", mchId='" + mchId + '\'' +'}';}
}
/*** 微信支付回调** @param resultXMLEntity 微信支付结果异步推送XML数据包实体* @return*/@Transactional@Overridepublic String wxPayBillCallback(PayResultXMLEntity resultXMLEntity) {Map<String, Object> 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<PayDetailAO> 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<Integer> 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

请按示例值填写

举例如下:

<xml>

<return_code><![CDATA[SUCCESS]]></return_code>
  <return_msg><![CDATA[OK]]></return_msg>
</xml>

四.测试

微信小程序支付:

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

app支付:

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

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

微信小程序、app集成微信支付相关推荐

  1. 企业微信小程序_集成微信小程序插件_地图选点插件

    官网文档: https://lbs.qq.com/miniProgram/plugin/pluginGuide/locationPicker 具体操作参考官网文档即可,讲的很详细

  2. 微信小程序服务商下子商户支付下单接口

    微信小程序服务商下子商户支付下单流程 调用方法 <?php namespace app\index\controller; class WeixinPay extends Base { prot ...

  3. 微信小程序-JAVA实现微信支付功能(微信支付2.0)

    微信小程序-JAVA实现微信支付功能(微信支付2.0) 一.前言 本博客主要介绍JAVA后台与微信小程序(UNI-APP或者原生微信小程序)的微信支付的实现,如果是APP或者H5的开发暂时不支持,具体 ...

  4. 开发一个微信小程序/APP一般需要多少时间,多少钱?

    开发一个微信小程序/APP一般需要多少时间,多少钱? 微信小程序/APP开发的工期和费用估算需视功能需求的多少和难易程度而定,需求不明的情况下很难给出恰当评估. 在湃点网络定制平台,一对一的专业的顾问 ...

  5. android studio微信小程序,App拉起微信小程序工具方法

    在很多应用中都会关联一些微信小程序,如果通过App将微信小程序打开或者分享能.下面分别给介绍一下. 1.如何通过应用程序拉起小程序. 首先我们需要在AndroidStudio中集成微信的开发工具包截止 ...

  6. 微信小程序 app.json 详细介绍

    微信小程序 app.json 详细介绍 {// 写各个页面的路径 (新增页面或者减少页面都要对其进行修改)"pages": ["pages/index/index&quo ...

  7. 微信小程序APP(商超营销类)经验总结

    项目介绍 这是一款主打门店营销的小程序.包括首页.门店.营销.个人设置.登录.数据统计展示.营销设置等. 本来要独立完成整个项目,包括前后端一套的,有些意外因素,项目临时收尾(说明:只完成了前端的部分 ...

  8. 微信小程序app.json全局配置项

    微信小程序app.json全局配置 小程序根目录下的 app.json 文件用来对微信小程序进行全局配置.文件内容为一个 JSON 对象,有以下属性: app.json配置项(该配置项由微信小程序开发 ...

  9. 微信小程序App.js应用

    微信小程序App.js应用 文章目录 微信小程序App.js应用 1.App.js内容 2.判断用户以什么方式进入小程序 3.获取用户信息 4.设置全局变量 1.App.js内容 App.js写逻辑内 ...

  10. 微信小程序中使用JSAPI支付

    微信小程序中使用JSAPI支付 在微信小程序中使用微信支付api[wx.requestPayment]需要传递以下字段 如何获取支付所需要的值 在微信小程序中使用微信支付api[wx.requestP ...

最新文章

  1. AD恢复(2)使用授权还原
  2. 音频数据文件格式(PCM,WAV,MIDI)简记
  3. java中mq组建是什么_Java教程之RabbitMQ介绍
  4. linux交换分区的文件格式为,LINUX的交换分区或交换文件SWAP的查看与维护
  5. 13、mysql中视图的应用
  6. PHP iconv 解决utf-8和gb2312编码转换问题
  7. 一个类GraphQL的ORM数据访问框架发布
  8. python中kmeans怎么导入数据集_通过Python实践K-means算法
  9. mysql 查询优化 ~ 分区表查询的探索
  10. Matlab2016b中文乱码怎么办
  11. CAD学习笔记中级课【模板样式】
  12. 网络七层协议结构分析图
  13. Android Studio实现用户登陆界面demo(xml实现)
  14. 物体重心的特点是什么_确定物体重心位置的常用方法是什么呢?
  15. python头像转卡通_Python实现将照片变成卡通图片的方法【基于opencv】
  16. (MATLAB)散点椭圆拟合与绘制代码
  17. 5个炫酷登录页面,拿去就能用(附源码)
  18. 【转载】如何巧用IPD,建立完善的产品研发管理体系?
  19. OSChina 儿童节乱弹 —— 六一不能让童工加班!
  20. Mysql的优化和架构浅析

热门文章

  1. 在ArcGIS上使用python(arcpy包)的入门教程
  2. 基于element-ui 搭建管理后台
  3. VMware虚拟机怎么用U盘装win7系统
  4. PG数据库:分组后取每组第一条数据
  5. 门铃呼叫器_门铃呼叫器按哪个按键给对方开门?
  6. Bluetooth 蓝牙介绍(三):低功耗蓝牙BLE空口协议Ⅰ
  7. loadrunner压测小程序
  8. 能量谷算法Energy Valley Optimizer (EVO)附matlab代码
  9. eclipse默认指向WebContent目录修改为webRoot 设置说明
  10. 保存地理坐标信息的SLIC分割结果