一、介绍
本文介绍了微信发起支付的步骤和代码实例,如有不足的请提出,我会做出改正。
二、官方文档
统一下单:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
三、微信SDK安装方法
微信PC扫码支付(一)-maven本地仓库安装:微信支付sdk
四、发起支付
- 下文PayException为自定义异常类
- 下文WeixinConfig为微信需要固定参数类
第一步:调用微信支付
public Object pay(Map<String, Object> map) throws PayException{
Map<String,Object> resultMap=new HashMap<>();
//设备号
String deviceInfo="WEB";
//随机字符串
String nonceStr=Long.toString(System.currentTimeMillis() / 1000);
logger.info("微信扫码支付-nonceStr:"+nonceStr);
//商品描述
String body=(String)map.get("body");
logger.info("微信扫码支付-body:"+body);
//订单编号号(多个订单号用逗号分割)
String orderId=(String)map.get("orderIds");
logger.info("微信扫码支付-订单号:"+orderId);
//订单价格
String prices=(String)map.get("prices");
logger.info("微信扫码支付-订单价格:"+prices);
//总金额
String amountPaid=(String)map.get("amountPaid");订单总金额,单位为元
logger.info("微信扫码支付-订单总金额:"+amountPaid);
//商户订单号(多个订单标志)
String outTradeNo=(String)map.get("outTradeNo");
logger.info("微信扫码支付-商户订单号:"+outTradeNo);
//ip
String ip = "XXXXXXXXX";
logger.info("微信扫码支付-ip:"+ip);
//交易类型
String tradeType="NATIVE";
//验证参数
if(StringUtils.isBlank(body)){
throw new PayException("商品描述不能为空");
}
if(StringUtils.isBlank(orderId)){
throw new PayException("订单编号不能为空");
}
if(StringUtils.isBlank(prices)){
throw new PayException("订单价格不能为空");
}
if(StringUtils.isBlank(amountPaid)){
throw new PayException("订单总金额不能为空");
}
if(StringUtils.isBlank(outTradeNo)){
throw new PayException("商户订单号不能为空");
}
if (StringUtils.isBlank(ip)) {
ip = "127.0.0.1";
}
//组装参数
Map<String, String> packageParams = new HashMap<String, String>();
WeixinConfig weixinConfig=new WeixinConfig();
String appid=weixinConfig.getAppID();
logger.info("微信扫码支付-appid:"+appid);
String mchId=weixinConfig.getMchID();
logger.info("微信扫码支付-mchId:"+mchId);
String notifyUrl=weixinConfig.getNotifyUrl();
logger.info("微信扫码支付-notifyUrl:"+notifyUrl);
int price=(int)(Float.valueOf(amountPaid)*100);//订单总金额,单位为分
packageParams.put("appid", appid);
packageParams.put("mch_id", mchId);
packageParams.put("device_info", deviceInfo);
packageParams.put("nonce_str", nonceStr);
packageParams.put("body", body);
packageParams.put("attach",orderId+";"+prices);
packageParams.put("out_trade_no",outTradeNo);
packageParams.put("total_fee", Integer.toString(price));
packageParams.put("spbill_create_ip", ip);
packageParams.put("notify_url", notifyUrl);
packageParams.put("trade_type", tradeType);
//签名
String sign="";
Map<String, String> result=new HashMap<>();
try {
sign = WXPayUtil.generateSignature(packageParams, weixinConfig.getKey());
packageParams.put("sign",sign);
logger.info("微信扫码支付-sign:"+sign);
WXPay wxpay=new WXPay(weixinConfig,WXPayConstants.SignType.MD5,false);
//统一下单
result = wxpay.unifiedOrder(packageParams);
} catch (Exception e) {
logger.info("请求微信支付错误:",e);
throw new PayException("请求微信支付错误");
}
String returnCode = result.get("return_code");
logger.info("微信扫码支付-returnCode:"+returnCode);
String returnMsg = result.get("return_msg");
logger.info("微信扫码支付-returnMsg:"+returnMsg);
//code 标记成功失败,默认0:成功,1:失败、用于alert,2:失败、用于confirm
if (StringUtils.isBlank(returnCode) || !"SUCCESS".equals(returnCode)) {
throw new PayException(returnMsg);
}
String resultCode = result.get("result_code");
if (StringUtils.isBlank(resultCode) || !"SUCCESS".equals(resultCode)) {
throw new PayException(result.get("err_code_des"));
}
// 以下字段在return_code 和result_code都为SUCCESS的时候有返回
String codeUrl = result.get("code_url");
logger.info("微信扫码支付-codeUrl:"+codeUrl);
resultMap.put("returnCode", "SUCCESS");
resultMap.put("codeUrl", codeUrl);
return resultMap;
}
第二步:从调用返回的map中取出codeUrl,发到客户端(自己写的页面)
<div class="sui-container payOrder">
<p class="title">微信支付</p>
<div class="payOrderImg">
<div class="code">
<div class="codeImgDiv">
<img alt="" src="/front/trade/pay/weixin/codeImg.htm?codeUrl=${codeUrl}">
</div>
<div class="codeFoot">
<p>请使用微信扫一扫</p>
<p>扫描二维码支付</p>
</div>
</div>
</div>
</div>
第三步:客户端(页面)发起二次请求把图片加载出来
/**
* 微信二维码图片
* @param codeUrl 微信支付返回的code_url
* @return
*/
@ResponseBody
@RequestMapping(value = "/pay/weixin/codeImg")
public void codeImg(HttpServletResponse response, String codeUrl){
ServletOutputStream stream = null;
try {
stream = response.getOutputStream();
QRCodeWriter writer = new QRCodeWriter();
BitMatrix m = writer.encode(codeUrl, BarcodeFormat.QR_CODE, 300,300);
MatrixToImageWriter.writeToStream(m, "png", stream);
} catch (Exception e) {
logger.info("生成二维码图片错误:",e);
}finally {
if (stream != null) {
try {
stream.flush();
stream.close();
} catch (IOException e) {
logger.info("生成二维码图片错误:",e);
}
}
}
}
(重要) 第四步:由于二维码页面是自己写的,需要在页面写一个查询微信订单的定时器,发现订单成功了就去订单列表页面
订单查询:https://blog.csdn.net/cl11992/article/details/86712544
$(function(){
/**
* 查询订单,付款成功后跳转到订单列表页
* */
var repeat = 200; // 限制执行次数为200次
var timer = setInterval(function(){
if (repeat == 0){
clearInterval(timer);
} else{
/**
* 发起ajax请求(请求微信查询订单)
*/
}
repeat--;
}, 3000);//3秒执行一次 总共200次 10分钟
});