您现在的位置是:主页 > news > 北滘网站设计/肇庆网站快速排名优化
北滘网站设计/肇庆网站快速排名优化
admin2025/4/23 17:30:39【news】
简介北滘网站设计,肇庆网站快速排名优化,深圳专业商城网站制作,做教育类网站一般流程前言“微信小程序在开发中大部分都是电商类的业务,电商必不可少的是支付环节。实现微信小程序支付看微信官方文档太晦涩(多数人都觉得官方人员写的烂),我也是在看官方文档的路上迷失去了自己。这篇文章是我实战采坑后总结的经验构成,尽量带着…
前言
“微信小程序在开发中大部分都是电商类的业务,电商必不可少的是支付环节。实现微信小程序支付看微信官方文档太晦涩(多数人都觉得官方人员写的烂),我也是在看官方文档的路上迷失去了自己。这篇文章是我实战采坑后总结的经验构成,尽量带着大家读懂官方文档,授人以鱼不如授人以渔。
”
微信小程序支付必须有商户号,绑定商户平台才有微信支付功能,个人小类型程序没有支付功能。商户平台可使用商户营业执照申请
一、支付流程导读
1.支付系统交互流程
在开发前若时间充足,建议大家通篇阅读一下微信支付官方文档[1],对业务名称加以熟悉,看清楚接口参数名,是否必传,方便后面文章的阅读与开发。

- 调用微信登录API接口获取用户openid。
- 将支付金额,回调地址,小程序appid等传入调用统一下单接口API。
- 微信官方生成预支付订单数据,包括订单id,支付金额等。
- 将返回数据进行签名,防止篡改。
- 将5个参数数据返回给前端调用Payment(输密码的面板)。
- 用户确认金额,输入密码。
- 微信进行密码鉴权。
- 微信回调你的业务系统,将支付是否成功通知给你,进行订单支付状态更新。此时你的接口必须放开权限,且公网可访问。
二、开发前的准备
1.准备资料
- appid :小程序的id
- apikey : 可在小程序开发配置找到
- mchid : 商户号,商户平台可找到
2.引入SDK
微信支付官方给我们提供了很多工具类。微信支付SDK[2]中有方法可以在没有业务订单数据的情况下,给你生成订单参数,实现跑通微信支付,给大家提供的一个测试类。很友好,里面提供了支付时需要用的工具类方法。
3. 小程序配置合法域名
小程序必须配置合法请求域名地址,外部公网才能请求访问小程序接口。具体步骤为:小程序管理员打开微信公众平台,扫描登录微信小程序,进入小程序开发配置,配置小程序域名地址。

4 申请微信商户号
微信支付商户号类似于银行卡,充当收款账户功能。由于文章篇幅有限,此文不作讲解,可以查看申请微信商户号[3]官方文档教程进行申请。
5 小程序与商户号关联
申请微信小程序以后,将小程序APPID与微信商户号绑定,通过小程序收到的资金就进入指定的商户中心。小程序绑定商户号文档[4]讲解的很详细,这里就不再赘述,翻阅至文章结尾可看到教程地址。
三、获取用户OpenId
1. 配置文件
weixin:
# 小程序ID
appid: wx08huxxxxxxxxxxx
# 小程序秘钥
appSecret: 95e2932xxxxxxxxxxxx
# 商户秘钥
apiKey: ymruurG3xxxxxxxxxx
# 商户ID
mchId: 1244xxxxxxxx
#支付回调通知地址 必须为公网可访问的域名地址 且权限放开
routine:
notify: https:xxxxxx/wx/pay/notify
2. 获取用户OpenID
首先前端同学需要请求微信服务获取一个登录code[5]。然后带着登录code请求后端接口
@GetMapping(value = "/login/{code}")
@ApiOperation(value = "获取用户openid" , response = ApiResult.class)
@ResponseBodypublic ApiResult login(@PathVariable String code) throws Exception {
Map result= wxAuthApiService.wxLogin(code);if (result.isEmpty()){return ApiResult.fail("获取用户小程序openid失败");
}return ApiResult.ok(result);
}
Service
public interface WxAuthApiService {
// 获取获取用户小程序openid
Map wxLogin(String code) throws Exception;
}
实现类
/**
* @Author zhenxiang
* @Version 1.0
* @Description
*/
@Slf4j
@Service
public class WxAuthApiServiceImpl implements WxAuthApiService {
// 小程序ID
@Value("${weixin.appid}")
private String APPID;
// 小程序秘钥
@Value("${weixin.appSecret}")
private String SECRET;
@Transactional(rollbackFor = Exception.class)
@Overridepublic Map<String, String> wxLogin(String code) throws Exception {
Map param = new ConcurrentHashMap<>();if (StringUtils.isEmpty(code)) {throw new BusinessException("获取用户openid失败,code 不能为空");
}
String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
APPID, SECRET, code);
String result = HttpUtils.sendGet(url, null);
log.info(result);
JSONObject object = JSON.parseObject(result);if (object.getInteger("errcode") != null) {
log.info("获取用户openid失败code:{},msg:{}", object.getInteger("errcode"), object.getString("errmsg"));throw new BusinessException("获取用户openid失败,errcode:" + object.getInteger("errcode") + "errmsg:" + object.getString("errmsg"));
}
String openId = object.getString("openid");// 会话密钥
String sessionKey = object.getString("session_key");// 根据业务将openid与sessionKey 持久化存入数据库
param.put("openid", openId);
param.put("sessionKey", sessionKey);return param;
}
顺利拿到OpenID[6] 以后就可以请求支付,因为微信支付必须确定订单的支付人OpenID。
四、支付流程
1. 支付接口
/**
* 微信小程序 统一下单支付
* @param request
* @param response
* @return
*/
@PostMapping("/unifiedOrder")
@ResponseBody
@ApiOperation(value = "微信统一下单", response = ApiResult.class)public ApiResult unifiedOrder(HttpServletRequest request, HttpServletResponse response) throws Exception {
log.info("---------统一下单--------");
String openId = request.getParameter("openId");
if (StringUtils.isEmpty(openId)) {
throw new BusinessException("openid 不能为空");
}
log.info("---------openId--------" + openId);
Map map = wxPayService.unifiedOrder(openId, IpUtil.getIpAddress(request), request);return ApiResult.ok(map);
}
service
/**
* 统一下单接口
* @param openid 用户标识
* @param ip 请求ip
* @param request 订单数据
* @return
*/
Map unifiedOrder(String openid, String ip, HttpServletRequest request) throws Exception;
实现类
/**
* @Author zhenxiang
* @Version 1.0
* @Description
*/
@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {
@Value("${weixin.appid}")
private String APPID;
@Value("${weixin.appSecret}")
private String SECRET;
@Value("${weixin.apiKey}")
private String APIKEY;
@Value("${weixin.mchId}")
private String MCHID;
//交易类型
public static final String TRADE_TYPE_JS = "JSAPI";
public static final String FAIL = "FAIL";
public static final String SUCCESS = "SUCCESS";
// 微信统一下单url
public static final String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
// 支付回调地址
@Value("${routine.notify}")
public String NOTIFY_URL;
/** 统一下单
* @param openid 用户唯一标识
* @param ip 请求方IP地址
* @param request 请求数据
* @return 已生成订单信息
*/
@Override
public Map unifiedOrder(String openid, String ip, HttpServletRequest request) throws Exception {
// 1. 拼接统⼀下单地址参数
log.info("进入下单流程");
Map paramMap = new ConcurrentHashMap(10);
paramMap.put("appid", APPID);
paramMap.put("mch_id", MCHID);// 商品信息
paramMap.put("body", "test");
paramMap.put("openid", openid);// 订单号
paramMap.put("out_trade_no", request.getParameter("orderId"));// 随机字符串,长度要求在32位以内。
paramMap.put("nonce_str", StringHelpUtils.generateNonceStr());// 以分为单位,1代表0.01元
paramMap.put("total_fee", "1");
paramMap.put("spbill_create_ip", ip);
paramMap.put("notify_url", NOTIFY_URL);// 支付类型
paramMap.put("trade_type", TRADE_TYPE_JS);// 微信官方SDK中生成签名方法
String paramXml = WxPayUtil.generateSignedXml(paramMap, APIKEY, WxPayUtil.SignType.MD5);
log.info("签名参数:{}", paramXml);
Map resultMap = new ConcurrentHashMap<>(10);// 请求微信服务发起支付 生成预支付订单ID
String returnXml = HttpClientUtil.httpsRequest(UNIFIED_ORDER_URL, "POST", paramXml);
log.info("返回参数:{}", returnXml);
resultMap = WxPayUtil.xmlToMap(returnXml);
Map returnMap = new ConcurrentHashMap<>();// 微信SDK方法验证签名 再次签名if (WxPayUtil.isSignatureValid(resultMap, APIKEY, WxPayUtil.SignType.MD5)) {// 签名成功后返给前端
returnMap.put("appId", APPID);// 时间戳
returnMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");// 随机字符串
returnMap.put("nonceStr", WXPayUtil.generateNonceStr());// 签名类型
returnMap.put("signType", WXPayConstants.MD5);// 微信预订单ID ,package参数名在微信文档中已指定必填
returnMap.put("package", "prepay_id=" + resultMap.get("prepay_id"));// 5. 通过appId, timeStamp, nonceStr, signType, package及商户密钥进⾏key=value形式拼接并加密
String paySign = WXPayUtil.generateSignature(returnMap, APIKEY, WXPayConstants.SignType.MD5);
returnMap.put("paySign", paySign);
returnMap.put("mchId", MCHID);
returnMap.put("resultCode", SUCCESS);
log.info("returnMap:{}", returnMap);return returnMap;
} else {
returnMap.put("resultCode", FAIL);
log.info("签名验证错误");
}return returnMap;
}
}
前端同学拿到以上参数就能唤起Payment 支付密码输入面板啦。

2. 注意事项
- 微信支付金额以“分”为单位,需将"元"转换为"分"。
- 微信支付金额不能为"0"元。0元将导致签名失败,无法唤起Payment。
以上给我记牢了,我曾经一次又一次在这翻车,一步步看日志的那种,唉不说了,一把辛酸泪。
五 、支付回调
“何所谓支付回调:订单支付钱到了微信,究竟是否支付成功,业务系统无从知道。微信官方提供一个消息推送接口,下单后,将会请求你订单支付时设置的参数回调接口地址。微信会传送订单号、支付是否成功、支付金额、时间等信息。根据信息我们对相应的订单进行业务处理。
”
上代码。
接口:
/**
* 通知回调 notify
* @param request 订单信息
* @param response
* @return SUCCESS/FAIL
* @throws Exception
*/
@RequestMapping(value = "/notify")
@ApiOperation(value = "微信支付回调", response = ApiResult.class)public void notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
log.info("微信开始回调");
String resXml = wxPayService.notify(request,response);
log.info("微信回调成功,返回值:{}",resXml);
}
实现类:
/** 支付回调
* @param request
* @param response
* @return
*/
@Override
public String notify(HttpServletRequest request, HttpServletResponse response) throws IOException {
log.info("---------------微信支付回调----------------------");
// 调用返回 xml
String resXml = "";
try {
// 解析request中xml 转换成map
Map map = WxPayUtil.parseXml(request);
log.info("---------------微信支付回调订单号为:{}--------", map.get("out_trade_no"));// 检验签名是否成功if (WxPayUtil.isSignatureValid(map, APIKEY, WxPayUtil.SignType.MD5)) {
log.info("微信支付return_code:{}", map.get("return_code"));//log.info("判断结果:{}", "SUCCESS".equals(map.get("return_code")));if ("SUCCESS".equals(map.get("return_code"))) {
Boolean result = orderService.orderCallback(map).getData();
log.info("支付回调得到order更新数据库结果:{}", result);if (result) {// 返回success给微信服务器 剔除推送队列中的本次交易
resXml = " " +"";
} else {
log.info("----------------微信回调成功 更新数据库状态失败---------------");
}
} else {
log.info("微信回调失败:{}", map.get("return_code"));
}
} else {
resXml = "" + "" + "" + " ";
}
} catch (Exception e) {
log.error("微信回调失败,抛出异常:{}", e);
}
PrintWriter printWriter = new PrintWriter(response.getOutputStream());
log.info("回调返回给微信服务器:{}", resXml);
printWriter.write(resXml);
printWriter.flush();
printWriter.close();return resXml;
}
一定要放开支付回调的权限啊,不然微信想回调你,也进不了你家大门啊
以上就是微信小程序支付实现的大致过程,下期讲 微信退款。

参考资料
[1]微信支付官方文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=2_1
[2]微信支付SDK文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
[3]微信商户号文档地址文档:https://kf.qq.com/faq/180910jimEvQ180910Zj6jQV.html
[4]小程序绑定商户号文档:https://kf.qq.com/faq/1801116VJfua1801113QVNVz.html
[5]登录code文档:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
[6]什么是OpenID:OpenID是网站上或应用中唯一对应用户身份的标识,网站或应用可将此ID进行存储,便于用户下次登录时辨识其身份,或将其与用户在网站上或应用中的原有账号进行绑定
写在最后
由于微信公众号受不可抗拒原因,关闭了新注册公众号的文末留言功能,所以导致我无法与读者进行讨论交流,后期可能会开放。想跟作者深入沟通的进入微信公众号内留言,知无不言。
点赞、在看、你的支持是我写作的动力。不支持? 年轻人不讲武德。
如果能分享,帮助到你圈子里,更多想掌握对接微信支付的朋友的话,那就太感谢观众老爷啦。
