微信支付功能的计划实现与关键实践(UniApp+Java)全代码
感觉本篇对你有资助可以关注一下我的微信公众号(深入浅出谈java),会不定期更新知识和面试资料、本领!!!
概述
在移动互联网时代,支付功能已成为应用开辟的焦点能力之一。本文将以 UniApp前端+Java后端技术栈为例,体系解析微信支付功能的计划实现与关键实践,为开辟者提供从技术架构到安全防护的全景视角。
微信支付功能是跨平台应用(UniApp前端 + Java后端)与微信支付体系对接的焦点模块,实现用户从下单到支付完成的闭环流程。支持多种支付场景(如APP支付、小步伐支付、H5支付),确保生意业务安全、实时性和数据一致性
对于支付体系,公司一般会对其举行独立,确保服务的安全、可靠、稳固。因此支付体系是现代互联网的关键焦点体系。本篇实现基本功能,提供思绪,部门代码不严谨,可以自行优化
微信支付流程图
大致如下:流程图中和流程步骤 描述的2、3 步举行了调换,不受影响,但是发起可以先创建订单
流程步骤
1、用户提交订单请求
- 行为主体:用户(通过UniApp前端操作)
- 动作描述:用户在UniApp中选择商品或服务,点击支付按钮,前端将订单信息(如商品ID、数目、金额等)发送至Java后端。
2、生成业务订单
- 行为主体:Java后端
- 动作描述:
- 后端接收订单请求后,验证数据合法性(如金额、商品库存等)。
- 在数据库中生成唯一业务订单号(out_trade_no),并记录订单状态为「待支付」
3、调用微信统一下单API
- 行为主体:Java后端 → 微信支付平台
- 动作描述:
- 后端构造统一下单请求参数(包罗商户号、订单号、金额、回调地址等)。
- 使用商户API密钥生成签名(保障请求安全性)。
- 向微信支付平台发送HTTP请求,调用统一下单接口(URL: https://api.mch.weixin.qq.com/pay/unifiedorder)。
4、接收预支付生意业务单响应
- 行为主体:微信支付平台 → Java后端
- 动作描述:
- 微信验证请求参数和签名,确认无误后生成预支付生意业务单。
- 返回XML格式响应数据,包含关键字段:
- prepay_id(预支付生意业务标识,用于后续支付)
- return_code(通讯状态码,如SUCCESS/FAIL)
- result_code(业务结果码,如SUCCESS/FAIL)
5、返回支付参数至前端
- 行为主体:Java后端 → UniApp前端
- 动作描述:
- 后端解析微信返回的prepay_id,重新构造前端支付参数(需二次签名)。
- 返回JSON数据给UniApp,包含:
- appId(微信应用ID)
- timeStamp(时间戳)
- nonceStr(随机字符串)
- package(固定值Sign=WXPay)
- signType(签名类型,通常为MD5或HMAC-SHA256)
- paySign(最终支付签名)
6、调起微信支付界面
- 行为主体:用户(UniApp前端) → 微信客户端
- 动作描述:
- UniApp通过uni.requestPayment API,传入后端返回的支付参数。
- 微信客户端(APP/小步伐)根据参数拉起支付界面,用户确认金额并输入密码。
7、用户完成支付
- 行为主体:微信支付平台 → 用户
- 动作描述:
- 微信验证支付密码和账户余额,扣款成功后,向用户展示支付结果页面(成功/失败)。
8、异步通知支付结果
- 行为主体:微信支付平台 → Java后端
- 动作描述:
- 微信通过POST请求调用后端预设的notify_url(需公网可访问)。
- 推送XML格式回调数据,包含:
- out_trade_no(商户订单号)
- transaction_id(微信支付单号)
- total_fee(实际支付金额)
- result_code(支付结果,如SUCCESS/FAIL)
9、处理回调并响应微信
- 行为主体:Java后端 → 微信支付平台
- 动作描述:
- 后端接收回调数据后:
- 验证签名防止伪造请求
- 检查订单金额与业务体系是否一致
- 更新订单状态为「已支付」(需做幂等处理,制止重复更新)
- 返回XML响应(必须包含),告知微信已正确处理。
10、通知前端最闭幕果
- 行为主体:Java后端 → UniApp前端
- 动作描述:
- 若前端未实时感知支付结果(如用户关闭页面),可通过两种方式同步:
- 轮询查询:前端定期请求后端订单状态接口
- WebSocket推送:后端主动推送支付结果
- 更新前端界面显示支付成功/失败状态。
账号预备工作
申请微信小步伐账号
1、开辟小步伐的第一步,你需要拥有一个小步伐账号,因此先申请小步伐账号
小步伐注册地址:小步伐
2、信息填好,举行注册,就会产生AppID、AppSecret
小步伐的 AppID 相称于小步伐平台的一个身份证,后续你会在很多地方要用到 AppID (注意这里要区别于服务号或订阅号的 AppID)
微信支付 官网开通商户支付能力
微信支付官网:微信支付 - 中国领先的第三方支付平台 | 微信支付提供安全快捷的支付方式
1、找到接入微信支付,举行绑定注册
注册需要营业执照、法人信息,按照要求填写即可
2、注册微信支付商户号
3、填写须要信息举行注册
4、申请证书和AIPv3秘钥,v2现在有镌汰趋势,不需要申请v2,直接v3走起。
5、下载和保存好 秘钥及证书(PS:一定要好好保存)
6、获取商户号
接入实现
服务端代码
1、导入maven依赖
-
- <dependency>
- <groupId>com.github.wxpay</groupId>
- <artifactId>wxpay-sdk</artifactId>
- <version>0.0.3</version>
- </dependency>
- <dependency>
- <groupId>com.thoughtworks.xstream</groupId>
- <artifactId>xstream</artifactId>
- <version>1.4.20</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>com.github.wechatpay-apiv3</groupId>
- <artifactId>wechatpay-apache-httpclient</artifactId>
- <version>0.4.7</version>
- </dependency>
复制代码 2、设置商户信息
- # 微信支付配置
- pay:
- appId: xxx #应用id
- mchId: xxx #商户id
- notifyUrl: https://服务器ip或对应域名/wxpay/weixin/callback #支付回调地址
复制代码 3、实体类代码
这个部门是需要用到的实体类代码
WeChatPay:微信支付预下单实体类PayParameterVO:微信支付,商品信息对象- @Data
- public class PayParameterVO {
- /** 商品价格(单位:分) */
- private String price;
- /** 微信openId */
- private String wxOpenId;
- /** 商品描述 */
- private String goodsTitle;
- }
复制代码 OrderReturnInfo:预下单成功之后返回结果对象- @Data
- public class OrderReturnInfo {
- /** 返回状态码 */
- private String return_code;
- /** 返回信息 */
- private String return_msg;
- /** 业务结果 */
- private String result_code;
- /** 小程序appID */
- private String appid;
- /** 商户号 */
- private String mch_id;
- /** 随机字符串 */
- private String nonce_str;
- /** 签名 */
- private String sign;
- /** 预支付交易会话标识。用于后续接口调用中使用,该值有效期为2小时 */
- private String prepay_id;
- /** 交易类型 */
- private String trade_type;
- }
复制代码 QueryReturnInfo:查询订单返回实体类- @Data
- public class QueryReturnInfo {
- /** 返回状态码 */
- private String return_code;
- /** 返回信息 */
- private String return_msg;
- /** 业务结果 */
- private String result_code;
- /** 错误代码 */
- private String err_code;
- /** 错误代码描述 */
- private String err_code_des;
- /** 小程序appID */
- private String appid;
- /** 商户号 */
- private String mch_id;
- /** 随机字符串 */
- private String nonce_str;
- /** 签名 */
- private String sign;
- /** 签名类型 */
- private String sign_type;
- private String prepay_id;
- /** 交易类型 */
- private String trade_type;
- /** 设备号 */
- private String device_info;
- /** 用户标识 */
- private String openid;
- /** 是否关注公众账号 */
- private String is_subscribe;
- private String trade_state;
- /** 付款银行 */
- private String bank_type;
- /** 订单金额 */
- private int total_fee;
- /** 应结订单金额 */
- private int settlement_total_fee;
- /** 货币种类 */
- private String fee_type;
- /** 现金支付金额 */
- private int cash_fee;
- /** 现金支付货币类型 */
- private String cash_fee_type;
- /** 总代金券金额 */
- private int coupon_fee;
- /** 代金券使用数量 */
- private int coupon_count;
- /** 代金券类型 */
- private String coupon_type_$n;
- /** 代金券ID */
- private String coupon_id_$n;
- /** 单个代金券支付金额 */
- private String coupon_fee_$n;
- /** 微信支付订单号 */
- private String transaction_id;
- /** 商户订单号 */
- private String out_trade_no;
- /** 支付完成时间 */
- private String time_end;
- private String trade_state_desc;
- /** 商家数据包 */
- private String attach;
- }
复制代码 SignInfo:签名实体类- @Data
- public class SignInfo {
- private String appId;//小程序ID
- private String timeStamp;//时间戳
- private String nonceStr;//随机串
- @XStreamAlias("package")
- private String repay_id;
- private String signType;//签名方式
- public void setSignType(String signType) {
- this.signType = signType;
- }
- }
复制代码 4、工具类代码
SignUtils:签名工具类- @Slf4j
- public class SignUtils {
- /**
- * 签名算法
- *
- * @param o 要参与签名的数据对象
- * @return 签名
- * @throws IllegalAccessException
- */
- public static String getSign(Object o) throws IllegalAccessException {
- ArrayList<String> list = new ArrayList<String>();
- Class cls = o.getClass();
- Field[] fields = cls.getDeclaredFields();
- for (Field f : fields) {
- f.setAccessible(true);
- if (f.get(o) != null && f.get(o) != "") {
- String name = f.getName();
- XStreamAlias anno = f.getAnnotation(XStreamAlias.class);
- if (anno != null) {
- name = anno.value();
- }
- list.add(name + "=" + f.get(o) + "&");
- }
- }
- int size = list.size();
- String[] arrayToSort = list.toArray(new String[size]);
- Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < size; i++) {
- sb.append(arrayToSort[i]);
- }
- String result = sb.toString();
- result += "key=" + Configure.getKey();
- log.info("签名数据:" + result);
- result = MD5.MD5Encode(result).toUpperCase();
- return result;
- }
- public static String getSign(Map<String, Object> map) {
- ArrayList<String> list = new ArrayList<String>();
- for (Map.Entry<String, Object> entry : map.entrySet()) {
- if (entry.getValue() != "") {
- list.add(entry.getKey() + "=" + entry.getValue() + "&");
- }
- }
- int size = list.size();
- String[] arrayToSort = list.toArray(new String[size]);
- Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < size; i++) {
- sb.append(arrayToSort[i]);
- }
- String result = sb.toString();
- result += "key=" + Configure.getKey();
- //Util.log("Sign Before MD5:" + result);
- result = MD5.MD5Encode(result).toUpperCase();
- //Util.log("Sign Result:" + result);
- return result;
- }
- }
复制代码 MD5:MD5 加密工具类- public class MD5 {
- private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
- "8", "9", "a", "b", "c", "d", "e", "f"};
- /**
- * 转换字节数组为16进制字串
- *
- * @param b 字节数组
- * @return 16进制字串
- */
- public static String byteArrayToHexString(byte[] b) {
- StringBuilder resultSb = new StringBuilder();
- for (byte aB : b) {
- resultSb.append(byteToHexString(aB));
- }
- return resultSb.toString();
- }
- /**
- * 转换byte到16进制
- *
- * @param b 要转换的byte
- * @return 16进制格式
- */
- private static String byteToHexString(byte b) {
- int n = b;
- if (n < 0) {
- n = 256 + n;
- }
- int d1 = n / 16;
- int d2 = n % 16;
- return hexDigits[d1] + hexDigits[d2];
- }
- /**
- * MD5编码
- *
- * @param origin 原始字符串
- * @return 经过MD5加密之后的结果
- */
- public static String MD5Encode(String origin) {
- String resultString = null;
- try {
- resultString = origin;
- MessageDigest md = MessageDigest.getInstance("MD5");
- resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
- } catch (Exception e) {
- e.printStackTrace();
- }
- return resultString;
- }
- }
复制代码 MapToObject:map 转化对象工具类- public class MapToObject {
- /**
- * Map数据转为java对象
- * @param map map数据
- * @param targetType 对象类型
- * @return
- * @param <T>
- * @throws IllegalAccessException
- * @throws InstantiationException
- */
- public static <T> T convertMapToObject(Map<String, String> map, Class<T> targetType) throws IllegalAccessException, InstantiationException {
- T targetObject = targetType.newInstance();
- for (Map.Entry<String, String> entry : map.entrySet()) {
- String key = entry.getKey();
- String value = entry.getValue();
- try {
- // 使用反射获取字段
- Field field = targetType.getDeclaredField(key);
- // 设置字段可访问(如果是私有字段)
- field.setAccessible(true);
- // 获取字段的类型
- Class<?> fieldType = field.getType();
- // 将字符串值转换为字段类型
- Object convertedValue = convertStringToType(value, fieldType);
- // 设置字段的值
- field.set(targetObject, convertedValue);
- } catch (NoSuchFieldException e) {
- // 处理字段不存在的异常
- e.printStackTrace();
- }
- }
- return targetObject;
- }
- private static Object convertStringToType(String value, Class<?> targetType) {
- if (targetType == int.class || targetType == Integer.class) {
- return Integer.parseInt(value);
- }
- // 添加其他可能的类型转换逻辑,例如 double、float、Date 等
- // 默认情况下,返回字符串值
- return value;
- }
- }
复制代码 HttpRequest:请求工具类- public class HttpRequest {
- //连接超时时间,默认10秒
- private static final int socketTimeout = 10000;
- //传输超时时间,默认30秒
- private static final int connectTimeout = 30000;
- /**
- * post请求
- *
- * @throws IOException
- * @throws ClientProtocolException
- * @throws NoSuchAlgorithmException
- * @throws KeyStoreException
- * @throws KeyManagementException
- * @throws UnrecoverableKeyException
- */
- public static String sendPost(String url, Object xmlObj) throws ClientProtocolException, IOException, UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException {
- HttpPost httpPost = new HttpPost(url);
- //解决XStream对出现双下划线的bug
- XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));
- xStreamForRequestPostData.alias("xml", xmlObj.getClass());
- //将要提交给API的数据对象转换成XML格式数据Post给API
- String postDataXML = xStreamForRequestPostData.toXML(xmlObj);
- //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
- StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");
- httpPost.addHeader("Content-Type", "text/xml");
- httpPost.setEntity(postEntity);
- //设置请求器的配置
- RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
- httpPost.setConfig(requestConfig);
- HttpClient httpClient = HttpClients.createDefault();
- HttpResponse response = httpClient.execute(httpPost);
- HttpEntity entity = response.getEntity();
- String result = EntityUtils.toString(entity, "UTF-8");
- return result;
- }
- /**
- * 自定义证书管理器,信任所有证书
- *
- * @author pc
- */
- public static class MyX509TrustManager implements X509TrustManager {
- @Override
- public void checkClientTrusted(
- java.security.cert.X509Certificate[] arg0, String arg1)
- throws CertificateException {
- }
- @Override
- public void checkServerTrusted(
- java.security.cert.X509Certificate[] arg0, String arg1)
- throws CertificateException {
- }
- @Override
- public java.security.cert.X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- }
- }
复制代码 5、设置类代码
WxPayConfig:微信支付设置- @Data
- @Component
- @Configuration
- @ConfigurationProperties(prefix = "pay")
- public class WxPayConfig {
- /**
- * 微信小程序appid
- */
- private String appId;
- /**
- * 小程序设置的API v2密钥
- */
- private String apiKey;
- /**
- * 微信商户平台 商户id
- */
- private String mchId;
- /**
- *小程序密钥
- */
- private String appSecret;
- /**
- * 小程序支付异步回调地址
- */
- private String notifyUrl;
- }
复制代码 Configure:商户支付秘钥- public class Configure {
- /**
- * 商户支付秘钥
- */
- @Getter
- private static String key = "此处填写秘钥";
- public static void setKey(String key) {
- Configure.key = key;
- }
- }
复制代码 6、常量类代码
WeChatPayUrlConstants:微信支付API地址常量- public class WeChatPayUrlConstants {
- /**
- * 统一下单预下单接口url
- */
- public static final String Uifiedorder = "https://api.mch.weixin.qq.com/pay/unifiedorder";
- /**
- * 订单状态查询接口URL
- */
- public static final String Orderquery = "https://api.mch.weixin.qq.com/pay/orderquery";
- /**
- * 订单申请退款
- */
- public static final String Refund = "https://api.mch.weixin.qq.com/secapi/pay/refund";
- /**
- * 付款码 支付
- */
- public static final String MicroPay = "https://api.mch.weixin.qq.com/pay/micropay";
- /**
- * 微信网页授权 获取“code”请求地址
- */
- public static final String GainCodeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize";
- /**
- * 微信网页授权 获取“code” 回调地址
- */
- public static final String GainCodeRedirect_uri = "http://i5jmxe.natappfree.cc/boss/WeChatPayMobile/SkipPage.html";
- }
复制代码 7、业务实现类代码
Controller 层- @Slf4j
- @RestController
- @RequestMapping("/system/wxpay")
- public class WxPayController {
- @Autowired
- private WxPayInfoService wxPayInfoService;
- /**
- * 小程序支付下单接口
- *
- * @return 返回结果
- */
- @ApiOperation("小程序支付功能")
- @PostMapping("/pay")
- public InvokeResult wxPay(@RequestBody PayParameterVO payParameterVO) {
- PayParameterVO parameterVO = new PayParameterVO();
- parameterVO.setWxOpenId(payParameterVO.getWxOpenId());
- parameterVO.setPrice("1");
- parameterVO.setGoodsTitle("测试支付商品");
- HashMap<String, String> payHistory = wxPayInfoService.insertPayRecord(parameterVO);
- return InvokeResultBuilder.success(payHistory);
- }
- /**
- * 查询订单
- */
- @ApiOperation("订单查询")
- @PostMapping("/wx/query")
- public InvokeResult orderQuery(@RequestParam("out_trade_no") String out_trade_no) {
- QueryReturnInfo queryReturnInfo = wxPayInfoService.orderQuery(out_trade_no);
- // return InvokeResultBuilder.success(queryReturnInfo.getTrade_state_desc(), queryReturnInfo);
- return InvokeResultBuilder.success(queryReturnInfo);
- }
- /**
- * 微信小程序支付成功回调
- *
- * @param request 请求
- * @param response 响应
- * @return 返回结果
- * @throws Exception 异常处理
- */
- @RequestMapping("/weixin/callback")
- public String callBack(HttpServletRequest request, HttpServletResponse response) throws Exception {
- log.info("接收到微信支付回调信息");
- String notifyXml = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
- // 解析返回结果
- Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyXml);
- // 判断支付是否成功
- if ("SUCCESS".equals(notifyMap.get("result_code"))) {
- //支付成功时候,处理业务逻辑
- wxPayInfoService.payCallbackSuccess(notifyMap);
- //返回处理成功的格式数据,避免微信重复回调
- return "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
- + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
- }
- // 创建响应对象:微信接收到校验失败的结果后,会反复的调用当前回调函数
- Map<String, String> returnMap = new HashMap<>();
- returnMap.put("return_code", "FAIL");
- returnMap.put("return_msg", "");
- String returnXml = WXPayUtil.mapToXml(returnMap);
- response.setContentType("text/xml");
- System.out.println("校验失败");
- return returnXml;
- }
- 、
- }
复制代码 接口层- public interface WxPayInfoService {
- /**
- * 创建统一支付订单
- */
- HashMap<String, String> insertPayRecord(PayParameterVO payParameterVO);
- /**
- * 查询订单
- * @param out_trade_no 订单号
- * @return 返回结果
- */
- QueryReturnInfo orderQuery(String out_trade_no);
- /**
- * 微信小程序支付成功回调
- * @param notifyMap
- */
- void payCallbackSuccess(Map<String, String> notifyMap);
- }
复制代码 实现层- @Slf4j
- @Service
- public class WxPayInfoServiceImpl implements WxPayInfoService {
- //这是注入的业务处理类
- // @Autowired
- // private IFPayOrderService ifPayOrderService;
- @Resource
- private WxPayConfig payProperties;
- private static final DecimalFormat df = new DecimalFormat("#");
- /**
- * 创建统一支付订单
- *
- * @param payParameterVO 商品信息
- * @return 返回结果
- */
- @Override
- @Transactional
- public HashMap<String, String> insertPayRecord(PayParameterVO payParameterVO) {
- String title = payParameterVO.getGoodsTitle();
- //金额 * 100 以分为单位
- BigDecimal fee = BigDecimal.valueOf(1);
- BigDecimal RMB = new BigDecimal(payParameterVO.getPrice());
- BigDecimal totalFee = fee.multiply(RMB);
- try {
- WeChatPay weChatPay = new WeChatPay();
- weChatPay.setAppid(payProperties.getAppId());
- weChatPay.setMch_id(payProperties.getMchId());
- weChatPay.setNonce_str(getRandomStringByLength(32));
- weChatPay.setBody(title);
- weChatPay.setOut_trade_no(getRandomStringByLength(32));
- weChatPay.setTotal_fee(df.format(Double.parseDouble(String.valueOf(totalFee))));
- // 获取当前服务器IP地址
- // weChatPay.setSpbill_create_ip(IpUtils());
- weChatPay.setNotify_url(payProperties.getNotifyUrl());
- weChatPay.setTrade_type("JSAPI");
- //这里直接使用当前用户的openid
- weChatPay.setOpenid(payParameterVO.getWxOpenId());
- weChatPay.setSign_type("MD5");
- //生成签名
- String sign = SignUtils.getSign(weChatPay);
- weChatPay.setSign(sign);
- log.info("订单号:" + weChatPay.getOut_trade_no());
- //向微信发送下单请求
- String result = HttpRequest.sendPost(WeChatPayUrlConstants.Uifiedorder, weChatPay);
- //将返回结果从xml格式转换为map格式
- Map<String, String> wxResultMap = WXPayUtil.xmlToMap(result);
- if (StringUtils.isNotEmpty(wxResultMap.get("return_code")) && wxResultMap.get("return_code").equals("SUCCESS")) {
- if (wxResultMap.get("result_code").equals("FAIL")) {
- log.error("微信统一下单失败!");
- return null;
- }
- }
- OrderReturnInfo returnInfo = MapToObject.convertMapToObject(wxResultMap, OrderReturnInfo.class);
- // 二次签名
- if ("SUCCESS".equals(returnInfo.getReturn_code()) && returnInfo.getReturn_code().equals(returnInfo.getResult_code())) {
- SignInfo signInfo = new SignInfo();
- signInfo.setAppId(payProperties.getAppId());
- long time = System.currentTimeMillis() / 1000;
- signInfo.setTimeStamp(String.valueOf(time));
- signInfo.setNonceStr(WXPayUtil.generateNonceStr());
- signInfo.setRepay_id("prepay_id=" + returnInfo.getPrepay_id());
- signInfo.setSignType("MD5");
- //生成签名
- String sign1 = SignUtils.getSign(signInfo);
- HashMap<String, String> payInfo = new HashMap<>();
- payInfo.put("timeStamp", signInfo.getTimeStamp());
- payInfo.put("nonceStr", signInfo.getNonceStr());
- payInfo.put("package", signInfo.getRepay_id());
- payInfo.put("signType", signInfo.getSignType());
- payInfo.put("paySign", sign1);
- payInfo.put("placeOrderJsonMsg", JSON.toJSONString(weChatPay));
- payInfo.put("orderNum", weChatPay.getOut_trade_no());
- // 业务逻辑结束 回传给小程序端唤起支付
- return payInfo;
- }
- return null;
- } catch (Exception e) {
- log.error(e.getMessage());
- }
- return null;
- }
- /**
- * 查询订单
- *
- * @param out_trade_no 订单号
- * @return 返回结果
- */
- @Override
- public QueryReturnInfo orderQuery(String out_trade_no) {
- try {
- WeChatPay weChatPay = new WeChatPay();
- weChatPay.setAppid(payProperties.getAppId());
- weChatPay.setMch_id(payProperties.getMchId());
- weChatPay.setNonce_str(WXPayUtil.generateNonceStr());
- weChatPay.setOut_trade_no(out_trade_no);
- //order.setSign_type("MD5");
- //生成签名
- String sign = SignUtils.getSign(weChatPay);
- weChatPay.setSign(sign);
- //向微信发送查询订单详情请求
- String result = HttpRequest.sendPost(WXPayConstants.ORDERQUERY_URL, weChatPay);
- Map<String, String> xmlToMap = WXPayUtil.xmlToMap(result);
- // 将 Map 转换为对象
- return MapToObject.convertMapToObject(xmlToMap, QueryReturnInfo.class);
- } catch (Exception e) {
- log.error("查询支付订单失败:[{}]", e.getMessage());
- }
- return null;
- }
- /**
- * 微信小程序支付成功回调
- *
- * @param notifyMap 回调Map数据
- */
- @Override
- public void payCallbackSuccess(Map<String, String> notifyMap) {
- //保存相关支付数据
- try {
- QueryReturnInfo queryReturnInfo = MapToObject.convertMapToObject(notifyMap, QueryReturnInfo.class);
- log.info("支付回调信息:" + queryReturnInfo);
- //处理回调信息,此处根据自己的项目业务进行处理
- // ifPayOrderService.receivePayCallback(queryReturnInfo);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- /**
- * 获取一定长度的随机字符串
- *
- * @param length 指定字符串长度
- * @return 一定长度的字符串
- */
- public static String getRandomStringByLength(int length) {
- String base = "abcdefghijklmnopqrstuvwxyz0123456789";
- Random random = new Random();
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; i++) {
- int number = random.nextInt(base.length());
- sb.append(base.charAt(number));
- }
- return sb.toString();
- }
- }
复制代码 前端焦点代码
支付方法- goPay () {
- console.log('goPay');
- const that = this
- //向服务器发送下单请求(服务端会返回预下单信息)
- uni.request({
- url: common.api_base_url + "/system/wxpay/pay",
- header: {
- "Content-Type": "application/json",
- "Authorization": "Bearer " + uni.getStorageSync('token'),
- },
- method: 'POST',
- data: {
- goodsId: that.nowGoodsId,
- },
- success(res) {
- console.log("下单信息结果",res)
- if (res.data.code == 200){
- //成功,调用微信支付接口进行支付()
- uni.requestPayment({
- provider: 'wxpay',
- timeStamp: res.data.data.timeStamp,
- nonceStr: res.data.data.nonceStr,
- package: res.data.data.package,
- signType: res.data.data.signType,
- paySign: res.data.data.paySign,
- // appId: app.globalData.appid,
- success: function (ress) {
- console.log("支付完成:",ress)
- //支付成功后,查询订单情况,或者2 秒自动跳转到其他页面
- uni.showToast({
- title: '支付成功',
- duration: 2000
- });
- },
- fail: function (err) {
- uni.showToast({
- title: '支付失败!',err,
- icon:"none",
- duration: 2000
- });
- }
- });
- }else {
- //弹出下单失败的提示
- uni.showToast({
- title:res.data.msg,
- icon:"none"
- });
- }
- }
- })
- },
复制代码 效果图
前端传递参数,后端生成预订单,返回前端,前端唤醒支付页面,随后支付即可,再调用订单状态查询接口,对差别状态的订单举行自己的业务逻辑判断。
最后文章有啥不对,欢迎大佬在评论区辅导!!!
如果感觉对你有资助就点赞推荐或者关注一下吧!!!
****
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |