JAVA服务器端接入微信APP支付记录

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

业务流程图如下:

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

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

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

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

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

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

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

 

统一下单:(接口连接https://api.mch.weixin.qq.com/pay/unifiedorder

准备的参数有 :

appid 公众账号ID 微信支付分配的公众账号ID(企业号corpid即为此appId)

mch_id 商户号 微信支付分配的商户号

nonce_str 随机字符串 

sign 签名 

body 商品描述

out_trade_no 商户订单号 商户系统内部订单号

total_fee 标价金额 订单总金额,单位为分

spbill_create_ip 终端IP

notify_url 通知地址(回调地址)

trade_type 交易类型 

一共10个必须参数

步骤1:将必填参数放入Map集合中,生成带sign(生成签名的key是在支付平台设置的)的xml格式的字符串,发送给统一下单链接。

步骤2:将微信返回的xml格式的字符串转换成map格式,并校验sign值是否正确。

步骤3:从map中取出returnCode和resultCode,当两个值都是SUCCESS时,再从map中获取prepay_id预支付交易会话标识,

nonce_str随机字符串,并生成一个时间戳time,将这三个参数用之前生成签名的key再生成一个sign,这个是返回客户端用于拉去订单界面的。

代码如下:

Map<String,String> orderMap = new Hash<String,String>();
orderMap.put("appid", WeiXConfig.WEIAPPID);
orderMap.put("mch_id", WeiXConfig.MCH_ID);
orderMap.put("nonce_str", WXPayUtil.generateNonceStr());
orderMap.put("body", WeiXConfig.BODY);
orderMap.put("out_trade_no", model.getId());
Integer payMoney = new BigDecimal(Integer.parseInt(model.getMoney())).multiply(newBigDecimal(100)).intValue(); orderMap.put("total_fee", String.valueOf(payMoney));
orderMap.put("total_fee", String.valueOf(payMoney));
orderMap.put("spbill_create_ip", spbill_create_ip);
orderMap.put("notify_url", WeiXConfig.WEI_NOTIFY_URL);
orderMap.put("trade_type", "APP");
String xmlInfo = WXPayUtil.generateSignedXml(orderMap, WeiXConfig.key);
String weixinPost = HttpsRequestUtil.httpsRequest(uri, "POST", xmlInfo).toString();
Map<String, String> returnMap = WXPayUtil.xmlToMap(weixinPost);
if (WXPayUtil.isSignatureValid(returnMap, WeiXConfig.key)) {
	 String returnCode = returnMap.get("return_code");// 通信标识
	 String resultCode = returnMap.get("result_code");// 交易标识
	 if (returnCode.equals(WXPayConstants.SUCCESS) &&         
           resultCode.equals(WXPayConstants.SUCCESS)) {
		  resultMap.put("code", ConstantUtil.SUCCESS);
		  resultMap.put("desc", ConstantUtil.SUCCESS_DESC);
		  String prepayid = returnMap.get("prepay_id");// 预支付交易会话标识
		  String noncestr = returnMap.get("nonce_str");// 微信返回的随机字符串
		  long time = WXPayUtil.getCurrentTimestamp();// 时间戳/单位秒
		  resultMap.put("prepay_id", prepayid);
		  resultMap.put("nonce_str", noncestr);
		  resultMap.put("mch_id", WeiXConfig.MCH_ID);
		  resultMap.put("timestamp", time);
		  String sign = secondSign(noncestr, time, prepayid, WeiXConfig.key);
		  resultMap.put("sign", sign);

		} else {
		  resultMap.put("code", ConstantUtil.SYS_ERROR);
		  resultMap.put("desc", returnMap.get("return_msg"));
		}
 } else {
	
 }

二次签名代码:

/**
	 * 二次签名
	 * 
	 * @param map 
	 * @param key
	 * @return
	 */
	public String secondSign(String nonce_str, long time, String prepayid, String key) {
		String sign = "";
		try {
			Map<String, String> map = new HashMap<>();
			map.put("appid", WeiXConfig.WEIAPPID);
			map.put("partnerid", WeiXConfig.MCH_ID);
			map.put("package", "Sign=WXPay");
			map.put("noncestr", nonce_str);
			map.put("timestamp", String.valueOf(time));
			map.put("prepayid", prepayid);
			String xmlStr = WXPayUtil.generateSignedXml(map, key);
			LogUtil.info("key-->{}", key);
			Map<String, String> xmlMap = WXPayUtil.xmlToMap(xmlStr);
			LogUtil.info("xmlMap-->{}", xmlMap);
			sign = xmlMap.get("sign");
		} catch (Exception e) {
			LogUtil.info("Exception-->{}", e);
		}
		return sign;
	}

 

到此统一下单结束

查询订单:(链接https://api.mch.weixin.qq.com/pay/orderquery

需要参数

appid 公众账号ID

mch_id 商户号

out_trade_no 商户订单号

nonce_str  随机字符串

sign  签名

一共5个参数

步骤1:将必填参数放入Map集合中,生成带sign(生成签名的key是在支付平台设置的)的xml格式的字符串,发送给查询订单链接。

步骤2:将微信返回的xml格式的字符串转换成map格式,并校验sign值是否正确。

步骤3:从map中取出appid和mch_id和result_code,当appid、商户mch_id和服务器值相同,并且result_code等于SUCCESS时,取map中trade_state(订单状态),根据订单状态决定是否下一步,订单状态有以下可能:

SUCCESS—支付成功

REFUND—转入退款

NOTPAY—未支付

CLOSED—已关闭

REVOKED—已撤销(刷卡支付)

USERPAYING--用户支付中

PAYERROR--支付失败(其他原因,如银行返回失败)

当订单状态是成功时,核对订单号以及金额是否正确,之后根据订单状态给用户发道具;到此查询订单结束,代码如下:

Map<String,String> orderMap = new Hash<String,String>();
orderMap.put("appid", WeiXConfig.WEIAPPID);
orderMap.put("mch_id", WeiXConfig.MCH_ID);
orderMap.put("out_trade_no", id);
String nonce_str = WXPayUtil.generateNonceStr();
orderMap.put("nonce_str", nonce_str);
String xmlInfo = WXPayUtil.generateSignedXml(orderMap, WeiXConfig.key);
String weixinPost = HttpsRequestUtil.httpsRequest(uri, "POST", xmlInfo).toString();
Map<String, String> returnMap = WXPayUtil.xmlToMap(weixinPost);
String return_code = returnMap.get("return_code");
if (WXPayConstants.SUCCESS.equals(return_code)) {
	String appid = returnMap.get("appid");
	String mch_id = returnMap.get("mch_id");
	String result_code = returnMap.get("result_code");
    /* 验签 */
	if (WXPayUtil.isSignatureValid(returnMap, WeiXConfig.key)) {

		if (WeiXConfig.WEIAPPID.equals(appid) && WeiXConfig.MCH_ID.equals(mch_id)
				&& "SUCCESS".equals(result_code)) {
			String trade_state = returnMap.get("trade_state");// 交易状态
			String total_fee = returnMap.get("total_fee");// 总金额
			String out_trade_no = returnMap.get("out_trade_no");// 商户订单号
			String trade_state_desc = returnMap.get("trade_state_desc");// 交易状态描述
            /* 状态成功 金额正确 */
			if ("SUCCESS".equals(trade_state) && total_fee.equals(String.valueOf(Integer.parseInt(model.getMoney()) * 100))) {
				/* 订单号相同 */
				if (out_trade_no.equals(id)) {
				
				
				}
            }
        }
    }
}

回调结果(连接是自己填的notify_url)

 

代码如下:

		BufferedReader reader = null;
		LogUtil.info(System.currentTimeMillis() + "<收到支付回调>");
		reader = request.getReader();
		String line = "";
		String xmlString = null;
		StringBuffer inputString = new StringBuffer();

		while ((line = reader.readLine()) != null) {
			inputString.append(line);
		}
		xmlString = inputString.toString();
		request.getReader().close();

		if ("".equals(xmlString)) {
			return "";
		}

		Map<String, String> map = WXPayUtil.xmlToMap(xmlString);
		LogUtil.info("----接收到的数据如下:---" + map.toString());
		String out_trade_no = map.get("out_trade_no");

		boolean flag = false;
		String test = Configuration.getProperty(Configuration.TESTINSTANCE);
		/* 不是测试 */
		if (null == test || "".equals(test)) {
			flag = checkWeiPayResult(map);
		} else {
			switch (test) {
			case "2":
				flag = checkWeiPayResult2(map);
				break;
			default:
				flag = checkWeiPayResult1(map);// 默认
				break;
			}
		}

		/* 检验签名 */
		if (flag) {
			Jedis jedis = JedisUtil.getJedis();
			try {
				Map<String, String> payMap = new HashMap<>();
				payMap.put("id", out_trade_no);
				PayOrderVerify entity = payService.queryOrderById(payMap);
				if (!entity.getCode().equals(PayConfig.CODE_FINISH) && entity.getStatus().equals(PayConfig.SEND_STATUS_NOT)) {
					entity.setCode(PayConfig.CODE_FINISH);
					payService.updateOrder(PayUtil.convert(entity));

					LogUtil.info("订单号验证成功,订单号:" + out_trade_no + ",玩家id:" + entity.getUserId());

					/* 通知大厅发货 */
					int command = ConstantUtil.G_CONST_CG_PS_PAY_CALLBACK_COMMAND_R;
					sendGoods(command, entity.getUserId(), entity.getpId(), entity.getId());
				}
				
				jedis.del("order" + out_trade_no);
			} catch (Exception e) {
				LogUtil.info("Exception-->{}", e);
			} finally {
				JedisUtil.returnResource(jedis);
			}
		}
		return returnXML(map.get("return_code"));
	}

参数校验代码:

/* 校验微信支付回调结果 正式的 */
	public boolean checkWeiPayResult(Map<String, String> map) {
		String return_code = map.get("return_code");
		try {
			if ("SUCCESS".equals(return_code)) {
				String mch_id = map.get("mch_id");
				if (WeiXConfig.MCH_ID.equals(mch_id)) {
					if (WXPayUtil.isSignatureValid(map, WeiXConfig.key)) {
						String fee_type = map.get("fee_type");
						if ("CNY".equals(fee_type)) {
							String out_trade_no = map.get("out_trade_no");
							Map<String, String> payMap = new HashMap<>();
							payMap.put("id", out_trade_no);
							PayOrderVerify entity = payService.queryOrderById(payMap);
							if (null != entity) {
								String result_code = map.get("result_code");
								if ("SUCCESS".equals(result_code)) {
									int total_fee = Integer.parseInt(map.get("total_fee"));
									if (Integer.parseInt(entity.getMoney()) * 100 == total_fee) {
										return true;
									} else {
										LogUtil.info("总金额不对,错的total_fee-->{},正确的total_fee-->{}", total_fee,
												Integer.parseInt(entity.getMoney()) * 100);
									}
								} else {
									LogUtil.info("result_code-->{}", result_code);
								}
							} else {
								LogUtil.info("订单号不对,out_trade_no-->{}", out_trade_no);
							}
						} else {
							LogUtil.info("货币种类不同,fee_type-->{}", fee_type);
						}
					} else {
						LogUtil.info("签名验证失败,sign-->{}", map.get("sign"));
					}
				} else {
					LogUtil.info("商户ID不一致,mch_id-->{}", mch_id);
				}
			} else {
				LogUtil.info("return_code-->{}", return_code);
			}

		} catch (Exception e) {
			LogUtil.info("Exception-->{}", e);
		}
		return false;
	}

 

到此全部结束!!!

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值