IONIC3微信支付 (附后台JAVA)

2023-10-14 18:20
文章标签 java 微信 支付 后台 ionic3

本文主要是介绍IONIC3微信支付 (附后台JAVA),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Ionic3微信支付流程

总结通俗来说微信支付一共两步(最后附全部代码):

1.统一下单(给微信获得微信返回的支付订单号(prepay_id))

解释一下:通俗点讲用户支付钱的时候,需要跳到微信界面,根据一个微信支付订单(微信界面肯定是微信的东西,和自己的项目没有任何关系)来支付钱,这个微信支付订单是微信生成的以下简称vx订单,怎么生成?项目后台根据一系列参数生成一个map,利用map和商户微信支付密钥key根据规则生成签名sign,将sign也放入到此前的map中,再将map转换为xml(格式参考微信支付文档,微信只接受xml),并将此xml通过post请求发送给微信(发送url为微信统一定死的地址,详细接着看下面),不论成功与否都回返回一个xml,若成功xml转map后会取得此次统一下单的终极目的参数prepay_id(预支付id),这个id是统一下单步骤的终极目标,获得此id代表已经成功让微信为用户之后的跳转到微信支付界面付钱生成了一个订单界面,等候用户跳转微信支付。若失败则要查看返回的xml中,returnMsg会提示报的错误,根据错误排查(文章最后会有一系列坑及解决方案)。

注意:此步骤完成不会跳转微信支付接口,仅仅是给微信支付下了个可以理解为预付订单,取得预付订单号prepay_id

统一下单xml示例:

参数举例:商品订单号out_trade_no(unique,并不是vx订单)和钱数total_fee(any)已经用户支付时的客户端ip spbill_create_ip等等一系列参数,参考下图。

以下是必不可少的参数小白解释(具体可参考微信支付文档):

appid(String 32):微信开发平台创建app时取得

mch_id(String 32):商户号id:微信开发平台申请微信支付资格成功时取得。

body(String 32):自己定义对订单商品的描述,比如body = 充值Q币,用户跳到微信支付界面时显示出的充值界面内容即为充值Q币。

Out_trade_no(String 32):商品订单号,此订单号为我们自己生成的订单号,必须唯一。

Total_fee(Int):单位为分! 用户实际支付的金额

Spbill_create_ip(String 16):用户支付时客户端ip

Trader_type(String 16):APP(app支付时定死)

Nonce_str(String 32):随机生成字符串

Notify_url(String 256):用户支付完成后(完成统一下单不会走回调!),微信收到了钱或支付失败都有可能返回一个xml,返回时需要异步的访问我们服务器的一个url地址,此地址作为支付的回调函数,在此地址中处理相应业务逻辑,返回时仅仅会有商品订单号(项目生成),和实际支付金额,实际支付时间有用。

Sign(String 32):生成签名,需要用到商户支付密钥(不是appSecret!)此出生成签名必须与返回给TS的参数中生成签名的方式一致。具体生成方式网上一大堆。

1.调起支付接口

将统一下单取得的prepay_id和其他参数如下等再次(第二次)生成签名,与之前同意下单的签名不相同!将这些参数发送回前台准备进行微信窗口的跳转(调起支付接口),具体操作见下节。

 

注意:timestamp必须为String类型的时间戳!扩展字段为定死。商户订单号outtradeno可不传,为前台处理业务逻辑用。

2.App微信支付资格准备

https://open.weixin.qq.com/cgi-bin/frame?t=home/app_tmpl&lang=zh_CN

1.创建app,注册微信平台相关信息。取得appid,appSecret

2.通过后,开通微信支付资格(商户号申请),具体材料有打包并且已经签名成功的apk

3.取得资格后需要取得的参数为商户号,商户支付密钥。

最终上述步骤取得微信支付实际所需参数有:

APPID:申请的appid

MCH_ID:商户号

KEY:商户号的支付密钥(不是appSecret!)

下面是后台示例此步骤所获得的参数一览:

注意:apk包名和apk的签名一旦绑定不可更改,必须与正式发版后的包名签名一致,否则

会导致出现签名错误(普通错误)。

微信支付插件安装

Cmd: cordova plugin add cordova-plugin-wechat@2.0 --variable wechatappid=xxxxxxxxxxxxxxx

注意:@2.0为版本号可更换 wechatappid为申请的appid(不是商户号!),此处必须与申请微信支付的app的appid一致。

安装完成后,打开confing.xml若如图所示版本号的appid无误则为安装成功。

请求后台进行统一下单

安装成功后,经大量测试,无需引入module等其他操作,直接在要使用微信支付的page.ts开搞。

1.在ts中组件声明前声明一个window对象。

2.直接请求(get/post都可)后台(必须参数:支付金额(注意微信接口的单位为分,此处若为元需处理),用户id(进行支付钱的业务处理需要),订单号可后台生成),后台返回值重新组装一个类似于post请求的对象参数,必须的参数如下图(微信文档有7个必须,经测试有下图5个为必须即可)

  1. 统一下单后台代码示例

注意:

  1. 发送的post请求编码格式一定要统一(UTF-8),否则返回的xml会报body乱码错误
  2. KEY一定要是商户支付密钥不是appSercet!!两者不同。
  3. Total_fee在此处的单位一定是分,不论之前业务处理以元或其他单位,此处必须转换成分。
  4. 订单号一定是唯一的,此处建议取上一个订单号+1,再拼接一个一定位数的随机字符串,在回调函数中直接sub掉一定位数的字符串即可拿到唯一的订单号。
  5. 回调函数不能带参数!
  6. 统一下单的签名方式一定要和调起支付接口参数的签名方式一致!但并不是同一个签名!

因为签名时所需参数多了一个prepay_id!

  1. Timestamp时间戳一定要是string!
  2. 注意发送参数的大小写和非人的下划线变化。Eg:mch_id =>partnerid,nonce_str =>noncestr
  3. 统一下单中返回的xml报错商户订单号重复,解决方法检查发送给微信的商户订单号是否与上次未完成的订单重复,若未重复,等待一天即可(微信取消支付异常的预付订单)。

 

调起支付接口,跳转微信界面。

拿到通过第一步统一下单取得的参数后,将此对象参数通过下图请求发送即可跳转微信界面。

若失败 reason会打印错误(eg:1.普通错误2.用户取消支付返回等)。成功则为完成支付。

注意:

  1. 注意es5和es6的坑,回调函数中的this指向问题,es5 为function(data){}其中的this不是指ts的this而是回调函数中的this 。es6写法为(data)=> this指向为ts中的this。\
  2. 若返回普通错误,说明这个方法本身没问题,且插件安装正确。在统一下单成功的情况下,检查appid / 商户号 /商户支付密钥(不是appSecert)是否和申请通过时的一致!
  3. 若一致可能是申请通过时间未到24小时(一般要在项目开始时申请,不要先做现申请)!

 

 

以下为全部代码:

ts:

//声明window
declare var window;
@Component({selector: 'page-paywaymodal',templateUrl: 'paywaymodal.html',
})
    /*** 微信统一下单*/getWXPayParam(item) {console.log(item.type);let paymentObject = {paymentFee: this.payFee,payer: GlobalConfig.USERINFO.id,paymentType: item.paymentConfigType,paymentConfigName: item.paymentConfigName,paymentConfigId: item.paymentConfigId,paymentStatu: 0,orderIdList: this.orderId};this.httpService.post(this.payUrl, paymentObject).then(data => {if (!data.success) {this.toastAlertService.errorToast(data.message, 1000, "top");} else {console.log(data);let params = {// appid:data.preOrderResult.appid,   partnerid: data.preOrderResult.partnerid,  //商户号prepayid: data.preOrderResult.prepayid,    //预支付id//package: data.preOrderResult.package,noncestr: data.preOrderResult.noncestr,    //随机数timestamp: data.preOrderResult.timestamp,  //时间戳sign: data.preOrderResult.sign,             //签名//appID};this.WXPay(params, data.preOrderResult.outtradeno, data.preOrderResult.paymentFee);}});}
    /*** 调起微信支付接口* @param params */WXPay(params, paymentSn, paymentFee) {window.Wechat.sendPaymentRequest(params, (data) => {this.toastAlertService.successToast(data.message, 2000, "top");this.viewCtrl.dismiss(true);}, (reason) => {this.toastAlertService.successToast("支付失败" + reason, 2000, "middle");this.viewCtrl.dismiss(false);})}

java(serviceImpl):

package com.xxx.common.business;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import com.xxx.common.api.WeChatConfig;
import com.xxx.utils.CommonUtil;
import com.xxxx.utils.HttpRequest;
import com.xxxx.utils.WXPayUtil;
import com.xxxx.weixin.api.WxOrderService;
/*** 微信支付接口(仔细看注解)* @author lu**/
@Service
public class WxOrderServiceImpl implements WxOrderService {/*** ==========================================* 参数:* out_trade_no:订单号 total_fee:支付钱数  body:所购买的物品简介* 注意:*  1.微信预付单:指的是在自己的平台需要和微信进行支付交易生成的一个微信订单,称之为“预付单”*  2.订单:指的是自己的网站平台与用户之间交易生成的订单或消费记录*  3.时间戳一定要转成字符串类型,生成签名方式一定要相同* 微信支付过程:* 1. 生成网站订单或消费记录(一定要有否则保存不了参数处理业务逻辑)* 2. 用户支付 --> 网站在微信平台生成预付单(实际取得的是预支付订单号)* 3. 最终实际根据预付单的信息进行支付* ==========================================*/@Overridepublic Map<String,String> placeOrder(String body,String out_trade_no,String total_fee,HttpServletRequest request) throws Exception {System.out.println("进入产生预付订单api");try {//获取请求用户端实际ipString 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();}if(ip.indexOf(",")!=-1){String[] ips = ip.split(",");ip = ips[0].trim();}System.out.println("------请求用户端ip----------"+ip);Map<String, String> params = new HashMap<String, String>();	String total_yuan = "";// new BigDecimal(total_fee).movePointRight(2).toString();//分转元(测试先设支付为分)// 订单总金额,单位为元(测试中先为分)if (StringUtils.isNotEmpty(total_fee)) {total_yuan = new BigDecimal(total_fee).movePointRight(2).toString();//充值碳汇币以元为单位(分转元)3-》300分;// new BigDecimal(recharge_fee).movePointRight(2).toString();//充值碳汇币以元为单位(分转元)}// 用户支付次数过于密集,会在极短的时间内生成累加订单号和生成订单之间会有可能出现重复订单号的问题,故在发送给微信的订单号后面追加随机数,在回调函数中sub掉取出,会大大降低订单的重复率		out_trade_no += CommonUtil.getUUID().substring(0, 3);//3位随机数			params.put("appid",WeChatConfig.APPID);//APPIDparams.put("mch_id",WeChatConfig.MCH_ID);//商户号params.put("body",body);//详情描述params.put("out_trade_no", out_trade_no);//订单号params.put("total_fee", total_yuan);//支付费用(分)//params.put("total_fee", "1");测试用params.put("spbill_create_ip", ip);//用户端实际ipparams.put("trade_type",WeChatConfig.TRADE_TYPE);//交易类型params.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串params.put("notify_url",WeChatConfig.NOTIFY_URL);//回调urlString sign = WXPayUtil.generateSignature(params,WeChatConfig.KEY);//生成签名params.put("sign", sign);System.out.println("统一下单参数:"+params.toString());String xml = WXPayUtil.mapToXml(params).replace("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>", "").trim();//将所有参数(map)转xml格式,微信方接收方式为xmlString xmlStr = HttpRequest.sendPost(WeChatConfig.PLACEANORDER_URL, xml);//发送post请求"统一下单接口"返回预支付id:prepay_idSystem.out.println("xmlStr显示:" + xmlStr);String prepay_id = "";if (xmlStr.indexOf("SUCCESS") != -1) {  Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);  prepay_id = (String) map.get("prepay_id");//预支付ID  System.out.println("取得预支付id:"+prepay_id);}Map<String, String> payMap = new HashMap<String, String>();payMap.put("appid",WeChatConfig.APPID);  			payMap.put("partnerid",WeChatConfig.MCH_ID);payMap.put("prepayid",prepay_id);//预支付id(预支付提交后微信返回)payMap.put("package",WeChatConfig.PACKAGE);//扩展字段payMap.put("noncestr",WXPayUtil.generateNonceStr());//随机字符串payMap.put("timestamp",WXPayUtil.getCurrentTimestamp()+"");//时间戳String paySign = WXPayUtil.generateSignature(payMap,WeChatConfig.KEY);payMap.put("sign", paySign);//签名(注意:签名方式一定要与统一下单接口使用的一致)payMap.put("outtradeno", out_trade_no.substring(0,out_trade_no.length() - 3));//订单号payMap.put("paymentFee",total_fee);//total_yuan 实际支付金额System.out.println("吊起支付接口参数:"+payMap.toString());return payMap;} catch (Exception e) {e.printStackTrace();}return null;}}

/*** @Description: 微信支付的一些参数配置* @author lu*/ 
public class WeChatConfig {public static final String APPID = "xxxxxxxx";						// 公众账号IDpublic static final String MCH_ID = "xxxxxxxx";						// 商户号public static final String KEY = "xxxxxxxxxx";		// 商户密钥public static final String PACKAGE = "Sign=WXPay";
/*	// APP和网页支付提交用户端ip, Native支付填调用微信支付API的机器IP, 即:服务器ip地址public static final String SPBILL_CREATE_IP = "127.0.0.1";*/// 接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。(需要配置)public static final String NOTIFY_URL = "xxxxxxx/appPay/callBack";// 支付方式,取值如下:JSAPI,NATIVE,APPpublic static final String TRADE_TYPE = "APP";// 微信支付 - 统一下单地址public static final String PLACEANORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";}


 

在下辛苦填坑,转载请注明出处! 有问题欢迎指出请教加VX kuaibaojing

这篇关于IONIC3微信支付 (附后台JAVA)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/212284

相关文章

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件

Java中的数组与集合基本用法详解

《Java中的数组与集合基本用法详解》本文介绍了Java数组和集合框架的基础知识,数组部分涵盖了一维、二维及多维数组的声明、初始化、访问与遍历方法,以及Arrays类的常用操作,对Java数组与集合相... 目录一、Java数组基础1.1 数组结构概述1.2 一维数组1.2.1 声明与初始化1.2.2 访问

Javaee多线程之进程和线程之间的区别和联系(最新整理)

《Javaee多线程之进程和线程之间的区别和联系(最新整理)》进程是资源分配单位,线程是调度执行单位,共享资源更高效,创建线程五种方式:继承Thread、Runnable接口、匿名类、lambda,r... 目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnab

Java 方法重载Overload常见误区及注意事项

《Java方法重载Overload常见误区及注意事项》Java方法重载允许同一类中同名方法通过参数类型、数量、顺序差异实现功能扩展,提升代码灵活性,核心条件为参数列表不同,不涉及返回类型、访问修饰符... 目录Java 方法重载(Overload)详解一、方法重载的核心条件二、构成方法重载的具体情况三、不构

Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式

《Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式》本文详细介绍如何使用Java通过JDBC连接MySQL数据库,包括下载驱动、配置Eclipse环境、检测数据库连接等关键步骤,... 目录一、下载驱动包二、放jar包三、检测数据库连接JavaJava 如何使用 JDBC 连接 mys

SpringBoot线程池配置使用示例详解

《SpringBoot线程池配置使用示例详解》SpringBoot集成@Async注解,支持线程池参数配置(核心数、队列容量、拒绝策略等)及生命周期管理,结合监控与任务装饰器,提升异步处理效率与系统... 目录一、核心特性二、添加依赖三、参数详解四、配置线程池五、应用实践代码说明拒绝策略(Rejected

一文详解SpringBoot中控制器的动态注册与卸载

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp... 目录项目结构1. 创建 Spring Boot 启动类2. 创建一个测试控制器3. 创建动态控制器注

Java操作Word文档的全面指南

《Java操作Word文档的全面指南》在Java开发中,操作Word文档是常见的业务需求,广泛应用于合同生成、报表输出、通知发布、法律文书生成、病历模板填写等场景,本文将全面介绍Java操作Word文... 目录简介段落页头与页脚页码表格图片批注文本框目录图表简介Word编程最重要的类是org.apach

Spring Boot中WebSocket常用使用方法详解

《SpringBoot中WebSocket常用使用方法详解》本文从WebSocket的基础概念出发,详细介绍了SpringBoot集成WebSocket的步骤,并重点讲解了常用的使用方法,包括简单消... 目录一、WebSocket基础概念1.1 什么是WebSocket1.2 WebSocket与HTTP

SpringBoot+Docker+Graylog 如何让错误自动报警

《SpringBoot+Docker+Graylog如何让错误自动报警》SpringBoot默认使用SLF4J与Logback,支持多日志级别和配置方式,可输出到控制台、文件及远程服务器,集成ELK... 目录01 Spring Boot 默认日志框架解析02 Spring Boot 日志级别详解03 Sp