微信JSAPI支付对接流程及支付接口设计

article/2025/9/13 18:31:03

文章目录

  • 前言
      • 一、JSAPI支付场景及逻辑
      • 二、开发步骤
        • 1.设置支付目录
        • 2.设置授权域名
        • 3.业务流程
      • 三、代码设计
        • 1. 支付页面
        • 2. Controller
        • 3. JS调起支付
        • 4. 工具类


前言

关于微信支付很早之前做过一次,近期项目再次使用就简单的记录一下。微信公众账号开通及微信支付认证的相关流程就不在这里做介绍了、本次单从代码实现上出一个完整案例。


一、JSAPI支付场景及逻辑

支付场景的交互细节,设计商户页面的逻辑:

  1. 用户打开商户网页选购商品,发起支付,在网页通过JavaScript调用getBrandWCPayRequest接口,发起微信支付请求,用户进入支付流程。
  2. 用户成功支付点击完成按钮后,商户的前端会收到JavaScript的返回值。商户可直接跳转到支付成功的静态页面进行展示。
  3. 商户后台收到来自微信开放平台的支付成功回调通知,标志该笔订单支付成功。
    注:2和3的触发不保证遵循严格的时序。JS API返回值作为触发商户网页跳转的标志,但商户后台应该只在收到微信后台的支付成功回调通知后,才做真正的支付成功的处理。

二、开发步骤

1.设置支付目录

支付授权目录说明:

  1. 商户最后请求拉起微信支付收银台的页面地址我们称之为“支付目录”,例如:https://www.weixin.com/pay.php。

  2. 商户实际的支付目录必须和在微信支付商户平台设置的一致,否则会报错 “ 当前页面的URL未注册:”

支付授权目录设置说明:

  • 登录微信支付商户平台(pay.weixin.qq.com)–>产品中心–>开发配置,设置后一般5分钟内生效。

支付授权目录校验规则说明:

  1. 如果支付授权目录设置为顶级域名(例如:https://www.weixin.com/ ),那么只校验顶级域名,不校验后缀;
  2. 如果支付授权目录设置为多级目录,就会进行全匹配,例如设置支付授权目录为https://www.weixin.com/abc/123/,则实际请求页面目录不能为https://www.weixin.com/abc/,也不能为https://www.weixin.com/abc/123/pay/,必须为https://www.weixin.com/abc/123/
    微信JSAPI支付-支付目录配置如图:
    在这里插入图片描述

2.设置授权域名

开发JSAPI支付时,在统一下单接口中要求必传用户openid,而获取openid则需要您在公众平台设置获取openid的域名,只有被设置过的域名才是一个有效的获取openid的域名,否则将获取失败。具体界面如图所示:
在这里插入图片描述
在这里插入图片描述

3.业务流程

在这里插入图片描述

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

  1. 商户server调用统一下单接口请求订单,api参见公共api【统一下单API】
  2. 商户server可通过【JSAPI调起支付API】调起微信支付,发起支付请求。
  3. 商户server接收支付通知,api参见公共api【支付结果通知API】
  4. 商户server查询支付结果,api参见公共api【查询订单API】

三、代码设计

1. 支付页面

    按照上述支付流程,从页面发起支付请求,支付页面代码如下:

  <div class="login-button"><div class="button" onClick="doPay()">确认支付</div></div><script type="text/javascript">var appid,timeStamp,nonceStr,packageValue,signType,paySign;function doPay(){$.ajax({url : '${ctx}/pay/unifiedorder',type : 'POST',data:{'orderId':${order.id}},//这里传入项目所需的订单信息例如订单金额等success : function(obj) {//ar obj = eval('(' + data + ')');if(parseInt(obj.agent)<5){alert("您的微信版本低于5.0无法使用微信支付");return;}appid = obj.appId, //公众号名称,由商户传入timeStamp = obj.timeStamp, //时间戳,自 1970 年以来的秒数nonceStr = obj.nonceStr, //随机串packageValue = obj.packageValue, //<span style="font-family:微软雅黑;>商品包信息</span>signType = obj.signType, //微信签名方式:paySign = obj.paySign//微信签名try {onBridgeReady();} catch (e) {}}});}</script>

&nbsp:&nbsp:&nbsp:&nbsp:代码包含详细注释,此次只关注doPay()方法的调用 ,前端发起调用,可以看见调用的接口为 /pay/unifiedorder。 接着我们来看后端代码的实现;

2. Controller

	@RequestMapping("/pay/unifiedorder")@ResponseBodypublic SortedMap<Object, Object> payparm(HttpServletRequest request, HttpServletResponse response){String orderId = request.getParameter("orderId");System.out.println(orderId);/** 用户订单信息 **/WrUserOrderEntity wrUserOrderEntity = wrUserOrderService.findById(WrUserOrderEntity.class, Long.valueOf(orderId));int total_fee = (int) (wrUserOrderEntity.getCountPrice() * 100);/** 用户信息 **/BnkUserEntity userEntity = bnkUserService.findById(BnkUserEntity.class, wrUserOrderEntity.getUserId());SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();parameters.put("appid", ConfigUtil.APPID);parameters.put("mch_id", ConfigUtil.MCH_ID);parameters.put("nonce_str", PayCommonUtil.CreateNoncestr());parameters.put("body", NAME_ORDER);parameters.put("out_trade_no", orderId);parameters.put("total_fee", total_fee + "");parameters.put("spbill_create_ip",getRemoteHost(request));parameters.put("notify_url", ConfigUtil.NOTIFY_URL);parameters.put("trade_type", "JSAPI");parameters.put("openid", userEntity.getOpenId());//获取签名String sign = PayCommonUtil.createSign("UTF-8", parameters);parameters.put("sign", sign);String requestXML = PayCommonUtil.getRequestXml(parameters); log.info("UNIFIEDORDER 请求参数:"+requestXML);/**注意:此处调用统一下单接口 **/String result =CommonUtil.httpsRequest(ConfigUtil.UNIFIED_ORDER_URL, "POST", requestXML);log.info("UNIFIEDORDER 请求返回:"+result);try {//解析微信返回的信息,以Map形式存储便于取值Map<String, String> map = XMLUtil.doXMLParse(result);SortedMap<Object,Object> params = new TreeMap<Object,Object>();params.put("appId", ConfigUtil.APPID);params.put("timeStamp",System.currentTimeMillis());params.put("nonceStr", PayCommonUtil.CreateNoncestr());params.put("package", "prepay_id="+map.get("prepay_id"));params.put("signType", ConfigUtil.SIGN_TYPE);String paySign =  PayCommonUtil.createSign("UTF-8", params);//这里用packageValue是预防package是关键字在js获取值出错params.put("packageValue", "prepay_id="+map.get("prepay_id"));//paySign的生成规则和Sign的生成规则一致params.put("paySign", paySign);//付款成功后跳转的页面params.put("sendUrl", ConfigUtil.SUCCESS_URL);String userAgent = request.getHeader("user-agent");char agent = userAgent.charAt(userAgent.indexOf("MicroMessenger")+15);//微信版本号,用于前面提到的判断用户手机微信的版本是否是5.0以上版本。params.put("agent", new String(new char[]{agent}));return params;} catch (Exception e) {e.printStackTrace();}return null;}@RequestMapping("/paySuccess")public void paySuccess(HttpServletRequest request, HttpServletResponse response) throws Exception{InputStream inStream = request.getInputStream();ByteArrayOutputStream outSteam = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while ((len = inStream.read(buffer)) != -1) {outSteam.write(buffer, 0, len);}System.out.println("~~~~~~~~~~~~~~~~付款成功~~~~~~~~~");outSteam.close();inStream.close();String result  = new String(outSteam.toByteArray(),"utf-8");//获取微信调用我们notify_url的返回信息Map<Object, Object> map = XMLUtil.doXMLParse(result);for(Object keyValue : map.keySet()){System.out.println(keyValue+"="+map.get(keyValue));}if (map.get("result_code").toString().equalsIgnoreCase("SUCCESS")) {//TODO 对数据库的操作response.getWriter().write(PayCommonUtil.setXML("SUCCESS", ""));   //告诉微信服务器,我收到信息了,不要在调用回调action了System.out.println("-------------"+PayCommonUtil.setXML("SUCCESS", ""));}}/*** 回调* @param request* @param response* @throws Exception*/@RequestMapping("/notify")public void notify(HttpServletRequest request, HttpServletResponse response) throws Exception {log.info("回调成功");InputStream inStream = request.getInputStream();ByteArrayOutputStream outSteam = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while ((len = inStream.read(buffer)) != -1) {outSteam.write(buffer, 0, len);}System.out.println("~~~~~~~~~~~~~~~~付款成功~~~~~~~~~");outSteam.close();inStream.close();String result  = new String(outSteam.toByteArray(),"utf-8");//获取微信调用我们notify_url的返回信息Map<Object, Object> map = XMLUtil.doXMLParse(result);for(Object keyValue : map.keySet()){System.out.println(keyValue+"="+map.get(keyValue));}if (map.get("result_code").toString().equalsIgnoreCase("SUCCESS")) {//更新订单信息写库等操作.String orderId = (String) map.get("out_trade_no");//告诉微信服务器,我收到信息了,不要在调用回调action了response.getWriter().write(PayCommonUtil.setXML("SUCCESS", ""));   System.out.println("-------------"+PayCommonUtil.setXML("SUCCESS", ""));}}public String getRemoteHost(HttpServletRequest request) {String 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.getRemoteAddr();}return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;}

    注意:此方法中涉及 openId ,这个需要根据各位的业务场景自行设计获取,我们项目中在设计之初使用了手机号绑定微信的操作,已经绑定在用户信息中。要注意的是微信openId的获取有两种授权方式,如果仅需要openId,则可以使用静默授权,需要用户头像及昵称等,需要使用 非静默授权:type: snsapi_base: 静默 ;snsapi_userinfo :非静默授权页面。

    上述方法中有notify() 为支付结果通知回调方法-异步, paySuccess() 为支付成功后跳转页面,由于本次使用微信前端拉起支付所以忽略 paySuccess() 的页面跳转方法;参数说明详见微信支付官方文档;

3. JS调起支付

    在微信浏览器里面打开H5网页中执行JS调起支付。接口输入输出数据格式为JSON。接着看支付页面代码根据统一下单接口调用返回相关参数 调用 onBridgeReady()方法 ;

    注意:WeixinJSBridge内置对象在其他浏览器中无效。getBrandWCPayRequest参数以及返回值定义

function onBridgeReady(){WeixinJSBridge.invoke('getBrandWCPayRequest', {"appId":"wx2421b1c4370ec43b",     //公众号名称,由商户传入     "timeStamp":"1395712654",         //时间戳,自1970年以来的秒数     "nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串     "package":"prepay_id=u802345jgfjsdfgsdg888",     "signType":"MD5",         //微信签名方式:     "paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 },function(res){if(res.err_msg == "get_brand_wcpay_request:ok" ){// 使用以上方式判断前端返回,微信团队郑重提示://res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。} }); 
}
if (typeof WeixinJSBridge == "undefined"){if( document.addEventListener ){document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);}else if (document.attachEvent){document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);}
}else{onBridgeReady();
}
	get_brand_wcpay_request:ok	支付成功get_brand_wcpay_request:cancel	支付过程中用户取消get_brand_wcpay_request:fail	支付失败调用支付JSAPI缺少参数:total_fee	1、请检查预支付会话标识prepay_id是否已失效2、请求的appid与下单接口的appid是否一致

    注:JS API的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回。由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。

    至此微信支付流程全部完成;js判断支付成功后可继续执行业务逻辑;

4. 工具类

  • 配置工具类

     这里面整理了微信支付相关的所有配置属性及接口可直接使用,本案例只使用了统一下单接口, 当微信拉起支付成功后微信会调用统一回调接口支付成功后跳转地址

public class ConfigUtil {/*** 服务号相关信息*/public final static String APPID = "";//服务号的应用号public final static String APP_SECRECT = "";//服务号的应用密码//public final static String TOKEN = "weixinCourse";//服务号的配置tokenpublic final static String MCH_ID = "";//商户号public final static String API_KEY = "";//API密钥public final static String SIGN_TYPE = "MD5";//签名加密方式
//	 public final static String CERT_PATH = "D:/apiclient_cert.p12";//微信支付证书存放路径地址,退款接口需要使用证书public final static String CERT_PATH = "/home/cert/apiclient_cert.p12";//微信支付证书存放路径地址、退款接口需要使用证书//微信支付统一接口的回调actionpublic final static String NOTIFY_URL = "http://****/pay/notify";//微信支付成功支付后跳转的地址public final static String SUCCESS_URL = "http://****/pay/paySuccess";//oauth2授权时回调actionpublic final static String REDIRECT_URI = "http://****/pay/authcode";/*** 微信基础接口地址*///获取token接口(GET)public final static String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";//oauth2授权接口(GET)public final static String OAUTH2_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";//刷新access_token接口(GET)public final static String REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";// 菜单创建接口(POST)public final static String MENU_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";// 菜单查询(GET)public final static String MENU_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN";// 菜单删除(GET)public final static String MENU_DELETE_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";/*** 微信支付接口地址*///微信支付统一接口(POST)public final static String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信退款接口(POST)public final static String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";//订单查询接口(POST)public final static String CHECK_ORDER_URL = "https://api.mch.weixin.qq.com/pay/orderquery";//关闭订单接口(POST)public final static String CLOSE_ORDER_URL = "https://api.mch.weixin.qq.com/pay/closeorder";//退款查询接口(POST)public final static String CHECK_REFUND_URL = "https://api.mch.weixin.qq.com/pay/refundquery";//对账单接口(POST)public final static String DOWNLOAD_BILL_URL = "https://api.mch.weixin.qq.com/pay/downloadbill";//短链接转换接口(POST)public final static String SHORT_URL = "https://api.mch.weixin.qq.com/tools/shorturl";//接口调用上报接口(POST)public final static String REPORT_URL = "https://api.mch.weixin.qq.com/payitil/report";
}

    上述配置文件中所需要的API_KEY、APP_SECRECT秘钥等,均在商户在微信公众平台或开放平台提交微信支付申请,微信支付工作人员审核资料无误后开通相应的微信支付权限。微信支付申请审核通过后,商户在申请资料填写的邮箱中收取到由微信支付小助手发送的邮件,此邮件包含开发时需要使用的支付账户信息;

  • 随机字符串生成工具类
public class PayCommonUtil {private static Logger log = LoggerFactory.getLogger(PayCommonUtil.class);public static String CreateNoncestr(int length) {String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";String res = "";for (int i = 0; i < length; i++) {Random rd = new Random();res += chars.indexOf(rd.nextInt(chars.length() - 1));}return res;}public static String CreateNoncestr() {String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";String res = "";for (int i = 0; i < 16; i++) {Random rd = new Random();res += chars.charAt(rd.nextInt(chars.length() - 1));}return res;}public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){StringBuffer sb = new StringBuffer();Set es = parameters.entrySet();Iterator it = es.iterator();while(it.hasNext()) {Map.Entry entry = (Map.Entry)it.next();String k = (String)entry.getKey();Object v = entry.getValue();if(null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + ConfigUtil.API_KEY);String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();return sign;}public static String getRequestXml(SortedMap<Object,Object> parameters){StringBuffer sb = new StringBuffer();sb.append("<xml>");Set es = parameters.entrySet();Iterator it = es.iterator();while(it.hasNext()) {Map.Entry entry = (Map.Entry)it.next();String k = (String)entry.getKey();String v = (String)entry.getValue();if ("attach".equalsIgnoreCase(k)||"body".equalsIgnoreCase(k)||"sign".equalsIgnoreCase(k)) {sb.append("<"+k+">"+"<![CDATA["+v+"]]></"+k+">");}else {sb.append("<"+k+">"+v+"</"+k+">");}}sb.append("</xml>");return sb.toString();}public static String setXML(String return_code, String return_msg) {return "<xml><return_code><![CDATA[" + return_code+ "]]></return_code><return_msg><![CDATA[" + return_msg+ "]]></return_msg></xml>";}
  • 通用工具类
    public class CommonUtil {private static Logger log = LoggerFactory.getLogger(CommonUtil.class);/*** 发送https请求* @param requestUrl 请求地址* @param requestMethod 请求方式(GET、POST)* @param outputStr 提交的数据* @return 返回微信服务器响应的信息*/public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {try {// 创建SSLContext对象,并使用我们指定的信任管理器初始化TrustManager[] tm = { new MyX509TrustManager() };SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");sslContext.init(null, tm, new java.security.SecureRandom());// 从上述SSLContext对象中得到SSLSocketFactory对象SSLSocketFactory ssf = sslContext.getSocketFactory();URL url = new URL(requestUrl);HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();conn.setSSLSocketFactory(ssf);conn.setDoOutput(true);conn.setDoInput(true);conn.setUseCaches(false);// 设置请求方式(GET/POST)conn.setRequestMethod(requestMethod);conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); // 当outputStr不为null时向输出流写数据if (null != outputStr) {OutputStream outputStream = conn.getOutputStream();// 注意编码格式outputStream.write(outputStr.getBytes("UTF-8"));outputStream.close();}// 从输入流读取返回内容InputStream inputStream = conn.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String str = null;StringBuffer buffer = new StringBuffer();while ((str = bufferedReader.readLine()) != null) {buffer.append(str);}// 释放资源bufferedReader.close();inputStreamReader.close();inputStream.close();inputStream = null;conn.disconnect();return buffer.toString();} catch (ConnectException ce) {log.error("连接超时:{}", ce);} catch (Exception e) {log.error("https请求异常:{}", e);}return null;}/*** 获取接口访问凭证* * @param appid 凭证* @param appsecret 密钥* @return*/public static Token getToken(String appid, String appsecret) {Token token = null;String requestUrl = ConfigUtil.TOKEN_URL.replace("APPID", appid).replace("APPSECRET", appsecret);// 发起GET请求获取凭证JSONObject jsonObject = JSONObject.fromObject(httpsRequest(requestUrl, "GET", null));if (null != jsonObject) {try {token = new Token();token.setAccessToken(jsonObject.getString("access_token"));token.setExpiresIn(jsonObject.getInt("expires_in"));} catch (JSONException e) {token = null;// 获取token失败log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));}}return token;}public static String urlEncodeUTF8(String source){String result = source;try {result = java.net.URLEncoder.encode(source,"utf-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}return result;}
    

    回顾一下支付流程: 前端发起支付调用 > 后端调用微信官方统一下单 > 根据返回参数返回前端 > 微信浏览器根据参数执行JS调起支付 > 支付成功 。 建议前端JS判断支付成功后在后续业务操作中增支付订单查询接口确认支付成功。

    提示:文章中很多参数详细引用了官方文档,增加了些许流程性代码,如需发现缺少相关工具类及代码错误私信我即可


http://chatgpt.dhexx.cn/article/X8jnQGWo.shtml

相关文章

【微信支付】jsApi支付 V3版本(附代码)

1、接入前的准备 官方文档地址 jsapi下单官方文档地址&#xff1a;https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml jsapi调起支付官方文档地址&#xff1a;https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml jsapi支付通知回调文档地址…

JAVA版微信支付V3—JSAPI支付

本人用的开发框架是:struts2&#xff08;用了struts2的0配置&#xff0c;对于struts的0配置不熟悉的可以看看这个博客了解下 http://www.cnblogs.com/fpjason/archive/2009/08/01/1536671.html&#xff09; 本人做的是微信V3版本的微信支付&#xff0c;也是目前最新的微信支付…

PHP微信支付JSAPI网页支付Native原生支付

微信JsApi网页支付链接&#xff08;微信中打开&#xff09;&#xff1a;微信安全支付 微信Native原生支付产生二维码链接&#xff1a;微信扫描支付样例 资源下载路径&#xff1a;PHP实现微信支付&#xff0c;支付宝支付对接_支付对接如何设置-PHP文档类资源-CSDN下载 使用PHP…

PHP实现微信支付(jsapi支付)流程

最近接触到一个项目&#xff0c;涉及到微信支付&#xff0c;搞微信开发这么久以来&#xff0c;还没搞过支付&#xff0c;之前也就搞过公众号发红包&#xff0c;感谢前辈们的探索&#xff0c;我看了他们的博文&#xff0c;让我少走了很多弯路。 前期准备&#xff1a; 1.微信认证…

【微信公众号】微信 jsapi 支付大概流程

文章目录 一、个人对微信 jsapi 支付的介绍二、微信支付需要的数据库表&#xff08;例子&#xff09;1. 订单表2. 支付信息表3. 退款信息表 三、微信支付必须的参数&#xff08;配置文件&#xff09;四、WxPayConfig.java1. MAVEN 依赖2. Java 代码&#xff08;商户私钥、签名验…

微信小程序支付V2版之JSAPI支付

文章目录 一、微信支付环境搭建1 企业微信小程序的开通2. 企业商户号的开通3 小程序号与商户号关联 二、微信小程序的支付流程1 JSAPI支付流程2 微信小程序获取openid3 微信小程序下单4 后台服务程序对订单的处理5 微信小程序发起支付6 支付结果的通知 三、微信支付API的使用1 …

Java实现微信支付(微信公众号JSAPI支付)

Java实现微信支付&#xff08;微信公众号JSAPI支付&#xff09; 第一步 开发环境准备 在接入微信支付之前&#xff0c;需要现在微信支付商户平台入驻&#xff0c;成为商家&#xff0c;才能继续后续的开发。 微信支付商户平台网址&#xff1a;https://pay.weixin.qq.com不过&…

微信 JSAPI 支付流程

微信支付分为5种&#xff1a; Jsapi支付&#xff0c;二维码支付&#xff0c;H5支付&#xff0c;小程序支付&#xff0c;App支付 Jsapi支付流程&#xff1a; (1) 通过oauth协议获取open_id a.第一步&#xff1a;用户同意授权&#xff0c;获取code 在确保微信公众账号拥有授权…

微信小程序微信支付《JSAPI支付》APIV3详细教程

文章目录 前提整体介绍我的maven依赖1、整体流程2、openid 的获取3、统一下单Controller&#xff08;预支付订单&#xff09;4、配置类和配置文件5、工具类6、前端接收到必要的参数&#xff0c;进行调起支付页面7、微信支付通知&#xff0c;notify_url的回调Controller8、前端小…

java对接微信支付:JSAPI支付(微信公众号支付)

本文是【微信JSAPI支付】文章&#xff0c;主要讲解商户对接微信支付&#xff0c;简洁版测试 文章目录 一、JSAPI支付接入前准备 二、代码片段 1.引入Maven依赖 2.后端业务请求接口 3.前端调起支付请求方法 总结 一、JSAPI支付接入前准备 1、JSAPI支付首先需要注册、认证一个公…

微信 JSAPI 支付流程

微信支付&#xff0c;开发文档地址&#xff1a; https://pay.weixin.qq.com/wiki/doc/api/index.html JSAPI支付文档地址&#xff1a; https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter9_2 微信支付分为5种&#xff1a; Jsapi支付&#xff0c;二维码支付&#xf…

微信公众号支付(JSAPI)

六年代码两茫茫&#xff0c;不思量&#xff0c;自难忘 6年资深前端主管一枚&#xff0c;只分享技术干货&#xff0c;项目实战分享 关注博主不迷路~ 文章目录 JSAPI支付简介应用场景支付的对接准备工作开发流程必填参数预支付统一下单公众号授权获取用户信息微信支付&#xff08…

微信支付之JSAPI支付

首先看一下&#xff0c;微信支付关于jsapi的官方文档&#xff0c;相关接口&#xff0c;一共有下单&#xff0c;查询订单&#xff0c;关闭订单&#xff0c;调起jsapi支付&#xff0c;支付结果通知&#xff0c;申请退款&#xff0c;查询单笔退款&#xff0c;退款结果通知&#xf…

微信支付JSAPI

一、什么是JSAPI支付 JSAPI支付是指商户通过调用微信支付提供的JSAPI接口&#xff0c;在支付场景中调起微信支付模块完成收款。 应用场景有&#xff1a; 线下场所&#xff1a;调用接口生成二维码&#xff0c;用户扫描二维码后在微信浏览器中打开页面后完成支付 公众号场景&…

微信支付之JSAPI支付开发流程

JSAPI支付 前言准备开发1.流程说明2.下单&#xff08;预支付&#xff09;3.前端调起支付4.支付结果异步通知5.退款申请6.退款结果异步通知 结语 前言 最近项目涉及到微信支付的功能&#xff0c;在这里简单分享下整体的开发流程,这里要介绍的是JSAPI支付。 JSAPI网页支付&#…

FME是一个好东东

FME产品分为三个层次&#xff1a; 一、入门级 1、特点&#xff1a;支持常见的GIS软件的数据交换&#xff0c;如 MapInfo TAB, DGN, DXF, DWG, SDTS, SHP, and TIGER&#xff1b;可以运行大部分函数&#xff08;Funtion和Factory&#xff09;&#xff1b;不支持由Plug-in开发的第…

黑马程序员Maven学习笔记

前言 这里是黑马程序员Maven学习笔记分享&#xff0c;这是视频链接。 我还有其它前端内容的笔记&#xff0c;有需要可以查看。 文章目录 前言基础Maven简介Maven是什么Maven的作用 Maven的下载Maven的基础概念仓库坐标本地仓库配置远程仓库的配置 第一个Maven项目Maven的项目…

MAEKDOWN

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

谷粒商城前端笔记

前端笔记 JavaScript ES6 ECMAScript6.0&#xff08;以下简称ES6&#xff0c;ECMAScript是一种由Ecma国际通过ECMA-262标准化的脚本&#xff09;&#xff0c;是JavaScript语言的下一代标准&#xff0c;2015年6月正式发布&#xff0c;从ES6开始的版本号采用年号&#xff0c;如…

谷粒商城-分布式基础【业务编写】

谷粒商城-分布式基础篇【环境准备】谷粒商城-分布式基础【业务编写】谷粒商城-分布式高级篇【业务编写】持续更新谷粒商城-分布式高级篇-ElasticSearch谷粒商城-分布式高级篇-分布式锁与缓存项目托管于gitee 一、三级分类 此处三级分类最起码得启动renren-fast、nacos、gate…