springboot集成微信app支付

2023-11-07

一、准备工作(以下信息需要自行开通和申请):

    public static final String APP_ID = "";//app的id 需要app应用
    public static final String KEY = "";//api密钥 商户账户信息里面去获取
    public static final String MCH_ID = "";//商户的id,需要开通商户

maven项目添加依赖:

		<!-- 微信支付 -->
		<dependency>
			<groupId>com.github.wxpay</groupId>
			<artifactId>wxpay-sdk</artifactId>
			<version>0.0.3</version>
		</dependency>

二、开发流程:

整个流程我们只需要两个接口即可:

1.微信支付的统一下单接口(本地项目请求微信):

接口api请点击这里

URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder

2.微信支付后的通知接口,是我们向外提供的(微信请求本地项目):接口地址自行定义

三、代码:我使用的springboot restful接口方式,详解请看注释

service层:


import java.util.Map;

/**
 * 
 * @类名称 WeixinService.java
 * @类描述 <pre>微信相关</pre>
 * @作者  yw  xingsfdz@163.com
 * @创建时间 2020年4月29日 下午4:25:10
 * @版本 5.0.0
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     5.0.0 	yw 	2020年4月29日             
 *     ----------------------------------------------
 * </pre>
 */
public interface WeixinService {

	/**
	 * 
	 * @方法名称 payBack
	 * @功能描述 <pre>回调接口</pre>
	 * @作者    yw
	 * @创建时间 2020年5月22日 下午12:50:15
	 * @param resXml
	 * @return
	 */
    String payBack(String resXml);

    /**
     * 
     * @param order 
     * @方法名称 doUnifiedOrder
     * @功能描述 <pre>统一下单</pre>
     * @作者    yw
     * @创建时间 2020年5月22日 下午12:50:26
     * @return
     * @throws Exception
     */
    Map<String, String> doUnifiedOrder(Order order) throws Exception;
    
}

service层实现(以下代码已删除了业务处理部分,需要自己添加自己项目的业务处理):


import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

/**
 * 
 * @类名称 WeixinServiceImpl.java
 * @类描述 <pre>微信 支付</pre>
 * @作者  yw  xingsfdz@163.com
 * @创建时间 2020年5月22日 下午12:51:13
 * @版本 5.0.0
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     5.0.0 	yw 	2020年5月22日             
 *     ----------------------------------------------
 * </pre>
 */
@Service
@Slf4j
public class WeixinServiceImpl implements WeixinService {
	
    public static final String HOST_IP = "";//回调的服务器ip
    public static final String NOTIFY_URL = "";//回调的地址,注意:外网可以访问
    public static final String TRADE_TYPE_APP = "APP";

    @Autowired
    OrderService orderService;//自己业务的处理服务
   
    @Override
    public String payBack(String resXml) {
        WXConfigUtil config = null;
        try {
            config = new WXConfigUtil();
        } catch (Exception e) {
            e.printStackTrace();
        }
        WXPay wxpay = new WXPay(config);
        String xmlBack = "";
        Map<String, String> notifyMap = null;
        try {
            notifyMap = WXPayUtil.xmlToMap(resXml);         // 调用官方SDK转换成map类型数据
            if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {//验证签名是否有效,有效则进一步处理

                String return_code = notifyMap.get("return_code");//状态
                String out_trade_no = notifyMap.get("out_trade_no");//商户订单号
                if (return_code.equals("SUCCESS")) {
                    if (out_trade_no != null) {
                        // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户的订单状态从退款改成支付成功
                        // 注意特殊情况:微信服务端同样的通知可能会多次发送给商户系统,所以数据持久化之前需要检查是否已经处理过了,处理了直接返回成功标志
                    	//业务处理 以下进行业务处理(比如修改订单状态信息等)
                        log.info("微信手机支付回调成功订单号:{}", out_trade_no);
                        xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                    } else {
                        log.info("微信手机支付回调失败订单号:{}", out_trade_no);
                        xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                    }
                }
                return xmlBack;
            } else {
                // 签名错误,如果数据里没有sign字段,也认为是签名错误
                //失败的数据要不要存储?
                log.error("手机支付回调通知签名错误");
                xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                return xmlBack;
            }
        } catch (Exception e) {
            log.error("手机支付回调通知失败", e);
            xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        return xmlBack;
    }

    /**
     * 
     * @方法名称 doUnifiedOrder
     * @功能描述 <pre>统一下单接口具体实现</pre>
     * @作者    yw
     * @创建时间 2020年5月22日 下午4:30:44
     * @param order 参数可以根据自己定义
     * @return
     * @throws Exception
     */
    @Override
    public Map<String, String> doUnifiedOrder(Order order) throws Exception {
        try {
            WXConfigUtil config = new WXConfigUtil();
            WXPay wxpay = new WXPay(config);
            Map<String, String> data = new HashMap<>();
            //生成商户订单号,不可重复
            data.put("appid", WXConfigUtil.APP_ID);
            data.put("mch_id", WXConfigUtil.MCH_ID);
            data.put("nonce_str", WXPayUtil.generateNonceStr());
            String body = "手机支付";
            data.put("body", body);
            data.put("out_trade_no", order.getOrderNo());//订单号
            data.put("total_fee", "1");//设置金额1分
            //自己的服务器IP地址
            data.put("spbill_create_ip", HOST_IP);
            //异步通知地址(请注意必须是外网)
            data.put("notify_url", NOTIFY_URL);
            //交易类型
            data.put("trade_type", TRADE_TYPE_APP);
            //附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
            data.put("attach", "");
            data.put("sign", WXPayUtil.generateSignature(data, WXConfigUtil.KEY,
                    WXPayConstants.SignType.MD5));
            //使用官方API请求预付订单
            Map<String, String> response = wxpay.unifiedOrder(data);
            if ("SUCCESS".equals(response.get("return_code"))) {//主要返回以下5个参数
                Map<String, String> param = new HashMap<>();
                param.put("appid", WXConfigUtil.APP_ID);
                param.put("partnerid",response.get("mch_id"));
                param.put("prepayid",response.get("prepay_id"));
                param.put("package","Sign=WXPay");
                param.put("noncestr",WXPayUtil.generateNonceStr());
                param.put("timestamp",System.currentTimeMillis()/1000+"");
                param.put("sign",WXPayUtil.generateSignature(param, WXConfigUtil.KEY,
                        WXPayConstants.SignType.MD5));
                return param;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("下单失败");
        }
        throw new Exception("下单失败");
    }
}

controller层:



import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;



import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

/**
 * 
 * @类名称 WeixinRestController.java
 * @类描述 <pre>微信app支付</pre>
 * @作者  yw  xingsfdz@163.com
 * @创建时间 2020年5月22日 下午4:04:19
 * @版本 5.0.0
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     5.0.0 	yw 	2020年5月22日             
 *     ----------------------------------------------
 * </pre>
 */
@Slf4j
@Api(value="微信",tags={"微信"})
@RequestMapping("/weixin/")
@RestController
public class WeixinRestController{
	
	@Autowired
	WeixinService weixinService;
	
	/**
	 * 
	 * @方法名称 wxAdd
	 * @功能描述 <pre>微信统一下单- 前端发起下单 比如web ios android</pre>
	 * @作者    yw
	 * @创建时间 2020年5月22日 下午12:56:59
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value={"app/wxpay"}, method={RequestMethod.POST})
    public ResponseMsg wxpay(HttpServletRequest request, Order order) throws Exception {
        return new ResponseMsg(weixinService.doUnifiedOrder(order));
    }
	
	/**
	 * 
	 * @方法名称 wxPayNotify
	 * @功能描述 <pre>给微信回调的接口</pre>
	 * @作者    yw
	 * @创建时间 2020年5月22日 下午4:04:55
	 * @param request
	 * @return
	 */
    @PostMapping("order/wxnotify")
    @ApiOperation("微信回调")
    public String wxPayNotify(HttpServletRequest request) {
        String resXml = "";
        try {
            InputStream inputStream = request.getInputStream();
            //将InputStream转换成xmlString
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder sb = new StringBuilder();
            String line = null;
            try {
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }
            } catch (IOException e) {
            	log.info(e.getMessage());
            } finally {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            resXml = sb.toString();
            String result = weixinService.payBack(resXml);
            return result;
        } catch (Exception e) {
            log.info("微信手机支付失败:" + e.getMessage());
            String result = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            return result;
        }
    }
}

四、测试:

安卓端发起请求,并请求支付成功:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

springboot集成微信app支付 的相关文章

随机推荐

  • mysql查询性能相关

    1 mysql innodb查询与什么因素有关 这张ppt说的相当详细 http tech uc cn wp content uploads 2013 10 MySQL Innodb E9 AB 98 E6 80 A7 E8 83 BD E
  • 【HTML】创建 <h2>-<h6> 标签

    任务描述 本关任务 依次创建 h2 h6 标签 文本内容为创建不同字体大小的标题 查看它们的区别 实现的效果如下 相关知识 第一关已经创建了h1标签 它是干什么的呢 它一般用来创建标题 另外 h2 也用来创建标题 它们有什么区别呢 h1的字
  • 快速掌握正则表达式

    文章目录 限定符 Qualifier 第一个常用限定符 第二个常用限定符 第三个常用限定符 或运算符 字符类 元字符 Meta characters d 数字字符 w 单词字符 空白符 s 任意字符 行首行尾 贪婪与懒惰匹配 Greedy
  • c++设计模式

    C 是一种面向对象的编程语言 支持许多设计模式 以下是几种常见的设计模式 1 单例模式 Singleton Pattern 确保一个类只有一个实例 并提供一个全局访问点 来访问该实例 2 工厂模式 Factory Pattern 定义一个接
  • kafka笔记3--快速部署KRaft版本的kafka3.1.1

    kafka笔记3 快速部署KRaft版本的kafka3 1 1 1 介绍 2 部署测试 2 1 部署 2 2 测试 3 注意事项 4 说明 1 介绍 Apache Kafka Raft 是一种共识协议 它的引入是为了消除 Kafka 对 Z
  • 【Java愚公】gitlab设置中文

    gitlab设置中文 设置步骤 设置完成后效果图 设置步骤 gitlab版本自带了中文语言包 可以通过上述方式直接切换 设置流程说明如下 访问gitlab服务 在用户偏好设置中设置用户语言类别 如下图所示 设置完成后效果图
  • 【STM32】电子时钟(1)

    一直想系统的学习STM32 但是公司的项目主要是电机算法 每天看到头都快炸了 打算仿照手机上的时钟应用写一个电子时钟 因为这个任务的定位是 好吧 就没有定位 主要是边玩边学 也不设时间期限和具体的功能指标 有空了就搞搞 想到了什么就加上去
  • 成功解决Myeclipse2017破解时遇到的crack.bat文件闪退问题

    解决问题 解决Myeclipse2017破解时遇到的crack bat文件闪退问题 解决方法 是环境变量设置有错 1 新建系统环境变量 JAVA HOME D Program Files MyEclipse2017CI7 binary co
  • Linux 音视频开发杂记之一-环境配置使用vscode

    开发环境 开发环境选择window10 Visual Studio Code ubuntu20 64 虚拟机 一Windows 安装 1 安装git for windows 安装过程直接下一步 主要原因是windows OpenSSH在vs
  • Flutter - Route传参

    Navigator 组件支持通过使用通用标识符从应用程序的任何地方导航到特定路由 在某些情况下 你可能还希望能够传递参数给特定路由 例如 你希望导航到 user 路由并携带上用户信息 在 Flutter 中 你能通过提供额外的 argume
  • 博客使用方法

    这里写自定义目录标题 凯哥英语视频 欢迎使用Markdown编辑器 新的改变 功能快捷键 合理的创建标题 有助于目录的生成 如何改变文本的样式 插入链接与图片 如何插入一段漂亮的代码片 生成一个适合你的列表 创建一个表格 设定内容居中 居左
  • 数据模型所描述的内容包括三个部分:数据结构、数据操作、数据约束。

    http www cnblogs com joechinochl articles 5252518 html 数据模型所描述的内容包括三个部分 数据结构 数据操作 数据约束 1 数据结构 数据模型中的数据结构主要描述数据的类型 内容 性质以
  • 大数据毕业设计题目选题推荐

    文章目录 0 前言 1 如何选题 1 1 选题技巧 如何避坑 重中之重 1 2 为什么这么说呢 1 3 难度把控 1 4 题目名称 1 5 最后 2 大数据 选题推荐 2 1 大数据挖掘类 2 2 大数据处理 云计算 区块链 毕设选题 2
  • if语句c语言编程题,c语言if语句的练习题答案

    1 编写程序输入a和b 求a和b的余数和商 includevoid main int a b scanf printf 商为 d 余数为 d 2 输入一个整型数据 分别求出各位数字 如 469 则个位数是9 十位数是6 百位数 是4 inc
  • 某型雷达的报文收发实录

    某型雷达的报文收发实录 前言 工作中需要与某型激光雷达进行通讯 读写报文解析出相应的角度 位置 在目前的工作中 切实遇到的问题是报文的收发 这里记录之 以下内容尚未进过实践检验2020 6 20 激光雷达的报文的接收 使用的API为wins
  • matlab怎么搭建神经网络,matlab实现神经网络算法

    怎样用matlab建立bp神经网络 net train net p t 把这句改成net train net p t 试试 matlab应该默认使用列向量 或者直接使用matlab提供的图形界面取训练 在命令行输入nnstart 谷歌人工智
  • 递归求解迷宫问题

    package com yg recursion author GeQiLin date 2020 2 24 16 01 public class MiGong private static int col 7 private static
  • Codeforces Round 881 (Div. 3) 题解

    目录 A Sasha and Array Coloring 题意 思路 代码 B Long Long 题意 思路 代码 C Sum in Binary Tree 题意 思路 代码 D Apple Tree 树形dp 题意 思路 代码 E T
  • 2022年C语言程序设计题库习集带答案(史上最全版)

    C语言程序设计 试题一 一 填空题 1 C语言中基本的数据类型有 2 C语言中普通整型变量的类型说明符为 在内存中占 字节 有符号普通整型的数据范围是 3 整数 35在机内的补码表示为 4 执行下列语句int a 8 a a a a 后 a
  • springboot集成微信app支付

    一 准备工作 以下信息需要自行开通和申请 public static final String APP ID app的id 需要app应用 public static final String KEY api密钥 商户账户信息里面去获取 p