【微信支付】springboot 微信app支付包括回调通知

由于微信技术文档比较坑。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
那就自己记录下吧
废话不多说了,从一个demo说起
怎么用idea创建一个项目不多说了

第一步,添加依赖

添加pom中的 依赖

<dependency>
    <groupId>com.github.wxpay</groupId>
    <artifactId>wxpay-sdk</artifactId>
    <version>0.0.3</version>
</dependency>

第二步,添加微信配置

这里解释下,这三个关键的东西,
appid需要的是认证过的微信公众平台的appid
mchID是商户平台的商户号
key是商户平台里的
在这里插入图片描述
这3个参数可以从微信的商户平台取

server.port=8080
#服务器域名地址
server.service-domain = http://127.0.0.1:8080

#微信app支付
pay.wxpay.app.appID = xxx
pay.wxpay.app.mchID = xxx
pay.wxpay.app.key = xxx
#从微信商户平台下载的安全证书存放的路径、我放在resources下面,切记一定要看看target目录下的class文件下有没有打包apiclient_cert.p12文件
pay.wxpay.app.certPath = static/cert/wxpay/apiclient_cert.p12
#微信支付成功的异步通知接口
pay.wxpay.app.payNotifyUrl=${server.service-domain}/api/wxPay/notify

第三步,添加配置文件类

package com.wxpay.demo.config;

import com.github.wxpay.sdk.WXPayConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.InputStream;

/**
 * 应用模块名称
 *
 * @author Rex
 * @since 2020/6/12 10:23
 */
@Component
@ConfigurationProperties(prefix = "pay.wxpay.app")
public class WxPayAppConfig implements WXPayConfig {
    /**
     * appID
     */
    private String appID;

    /**
     * 商户号
     */
    private String mchID;

    /**
     * API 密钥
     */
    private String key;

    /**
     * API证书绝对路径 (本项目放在了 resources/cert/wxpay/apiclient_cert.p12")
     */
    private String certPath;

    /**
     * HTTP(S) 连接超时时间,单位毫秒
     */
    private int httpConnectTimeoutMs = 8000;

    /**
     * HTTP(S) 读数据超时时间,单位毫秒
     */
    private int httpReadTimeoutMs = 10000;

    /**
     * 微信支付异步通知地址
     */
    private String payNotifyUrl;

    /**
     * 微信退款异步通知地址
     */
    private String refundNotifyUrl;

    /**
     * 获取商户证书内容(这里证书需要到微信商户平台进行下载)
     *
     * @return 商户证书内容
     */
    @Override
    public InputStream getCertStream() {
        InputStream certStream  =getClass().getClassLoader().getResourceAsStream(certPath);
        return certStream;
    }

    @Override
    public String getAppID() {
        return appID;
    }

    public void setAppID(String appID) {
        this.appID = appID;
    }

    @Override
    public String getMchID() {
        return mchID;
    }

    public void setMchID(String mchID) {
        this.mchID = mchID;
    }

    @Override
    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getCertPath() {
        return certPath;
    }

    public void setCertPath(String certPath) {
        this.certPath = certPath;
    }

    @Override
    public int getHttpConnectTimeoutMs() {
        return httpConnectTimeoutMs;
    }

    public void setHttpConnectTimeoutMs(int httpConnectTimeoutMs) {
        this.httpConnectTimeoutMs = httpConnectTimeoutMs;
    }

    @Override
    public int getHttpReadTimeoutMs() {
        return httpReadTimeoutMs;
    }

    public void setHttpReadTimeoutMs(int httpReadTimeoutMs) {
        this.httpReadTimeoutMs = httpReadTimeoutMs;
    }

    public String getPayNotifyUrl() {
        return payNotifyUrl;
    }

    public void setPayNotifyUrl(String payNotifyUrl) {
        this.payNotifyUrl = payNotifyUrl;
    }

    public String getRefundNotifyUrl() {
        return refundNotifyUrl;
    }

    public void setRefundNotifyUrl(String refundNotifyUrl) {
        this.refundNotifyUrl = refundNotifyUrl;
    }
}

第四步,添加Controller

package com.wxpay.demo.controller;

import com.wxpay.demo.common.ResultMap;
import com.wxpay.demo.service.WxPayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * 应用模块名称
 *
 * @author Rex
 * @since 2020/6/12 11:16
 */
@RestController
@RequestMapping("/wxPay")
public class WxPayController {

    @Autowired
    private WxPayService wxPayService;

    /**
     * 统一下单接口
     */
    @GetMapping("/unifiedOrder")
    public ResultMap unifiedOrder(
            @RequestParam String orderNo,
            @RequestParam double amount,
            @RequestParam String body,
            HttpServletRequest request) {
        try {
            // 1、验证订单是否存在

            // 2、开始微信支付统一下单
            ResultMap resultMap = wxPayService.unifiedOrder(orderNo, amount, body);
            return resultMap;//系统通用的返回结果集,见文章末尾
        } catch (Exception e) {
            return ResultMap.error("运行异常,请联系管理员");
        }
    }

    /**
     * 微信支付异步通知
     */
    @RequestMapping(value = "/notify")
    public String payNotify(HttpServletRequest request) {
        InputStream is = null;
        String xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml> ";
        try {
            is = request.getInputStream();
            // 将InputStream转换成String
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
            xmlBack = wxPayService.notify(sb.toString());
        } catch (Exception e) {
            System.out.println("微信手机支付回调通知失败:" + e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return xmlBack;
    }

}

第五步,创建service接口和实现

package com.wxpay.demo.service;

import com.wxpay.demo.common.ResultMap;

/**
 * 应用模块名称
 *
 * @author Rex
 * @since 2020/6/12 11:22
 */
public interface WxPayService {

    /**
     * @Description: 微信支付统一下单
     * @param orderNo: 订单编号
     * @param amount: 实际支付金额
     * @param body: 订单描述
     * @Author: Rex
     * @Date: 2019/8/1
     * @return
     */
    ResultMap unifiedOrder(String orderNo, double amount, String body) ;

    /**
     * @Description: 订单支付异步通知
     * @param notifyStr: 微信异步通知消息字符串
     * @Author: Rex
     * @Date: 2019/8/1
     * @return
     */
    String notify(String notifyStr) throws Exception;

    /**
     * @Description: 退款
     * @param orderNo: 订单编号
     * @param amount: 实际支付金额
     * @param refundReason: 退款原因
     * @Author: Rex
     * @Date: 2019/8/6
     * @return
     */
    ResultMap refund(String orderNo, double amount, String refundReason);

}
package com.wxpay.demo.service.impl;

import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.wxpay.demo.common.ResultMap;
import com.wxpay.demo.config.WxPayAppConfig;
import com.wxpay.demo.service.WxPayService;
import jdk.nashorn.internal.ir.annotations.Reference;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * 应用模块名称
 *
 * @author Rex
 * @since 2020/6/12 11:22
 */
@Service
public class WxPayServiceImpl implements WxPayService {
    private final Logger logger = LoggerFactory.getLogger(WxPayServiceImpl.class);

    @Autowired
    private WxPayAppConfig wxPayAppConfig;

    @Override
    public ResultMap unifiedOrder(String orderNo, double amount, String body) {
        Map<String, String> returnMap = new HashMap<>();
        Map<String, String> responseMap = new HashMap<>();
        Map<String, String> requestMap = new HashMap<>();
        try {
            WXPay wxpay = new WXPay(wxPayAppConfig);
            requestMap.put("body", body);                                     // 商品描述
            requestMap.put("out_trade_no", orderNo);                          // 商户订单号
            requestMap.put("total_fee", String.valueOf((int) (amount * 100)));   // 总金额
            requestMap.put("spbill_create_ip", ""); // 终端IP
            requestMap.put("trade_type", "APP");                              // App支付类型
            requestMap.put("notify_url", wxPayAppConfig.getPayNotifyUrl());   // 接收微信支付异步通知回调地址
            Map<String, String> resultMap = wxpay.unifiedOrder(requestMap);
            //获取返回码
            String returnCode = resultMap.get("return_code");
            String returnMsg = resultMap.get("return_msg");
            //若返回码为SUCCESS,则会返回一个result_code,再对该result_code进行判断
            if ("SUCCESS".equals(returnCode)) {
                String resultCode = resultMap.get("result_code");
                String errCodeDes = resultMap.get("err_code_des");
                if ("SUCCESS".equals(resultCode)) {
                    responseMap = resultMap;
                }
            }
            if (responseMap == null || responseMap.isEmpty()) {
                return ResultMap.error("获取预支付交易会话标识失败");
            }
            // 3、签名生成算法
            Long time = System.currentTimeMillis() / 1000;
            String timestamp = time.toString();
            returnMap.put("appid", wxPayAppConfig.getAppID());
            returnMap.put("partnerid", wxPayAppConfig.getMchID());
            returnMap.put("prepayid", responseMap.get("prepay_id"));
            returnMap.put("noncestr", responseMap.get("nonce_str"));
            returnMap.put("timestamp", timestamp);
            returnMap.put("package", "Sign=WXPay");
            returnMap.put("sign", WXPayUtil.generateSignature(returnMap, wxPayAppConfig.getKey()));//微信支付签名
            return ResultMap.ok().put("data", returnMap);
        } catch (Exception e) {
            logger.error("订单号:{},错误信息:{}", orderNo, e.getMessage());
            return ResultMap.error("微信支付统一下单失败");
        }
    }

    @Override
    public String notify(String notifyStr) {
        String xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml> ";
        try {
            // 转换成map
            Map<String, String> resultMap = WXPayUtil.xmlToMap(notifyStr);
            WXPay wxpayApp = new WXPay(wxPayAppConfig);
            if (wxpayApp.isPayResultNotifySignatureValid(resultMap)) {
                String returnCode = resultMap.get("return_code");  //状态
                String outTradeNo = resultMap.get("out_trade_no");//商户订单号
                String transactionId = resultMap.get("transaction_id");
                if (returnCode.equals("SUCCESS")) {
                    if (StringUtils.isNotBlank(outTradeNo)) {
                        /**
                         * 注意!!!
                         * 请根据业务流程,修改数据库订单支付状态,和其他数据的相应状态
                         *
                         */
                        logger.info("微信手机支付回调成功,订单号:{}", outTradeNo);
                        xmlBack = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return xmlBack;
    }

    @Override
    public ResultMap refund(String orderNo, double amount, String refundReason) {

        if (StringUtils.isBlank(orderNo)) {
            return ResultMap.error("订单编号不能为空");
        }
        if (amount <= 0) {
            return ResultMap.error("退款金额必须大于0");
        }

        Map<String, String> responseMap = new HashMap<>();
        Map<String, String> requestMap = new HashMap<>();
        WXPay wxpay = new WXPay(wxPayAppConfig);
        requestMap.put("out_trade_no", orderNo);
        requestMap.put("out_refund_no", "123456789");
        requestMap.put("total_fee", "订单支付时的总金额,需要从数据库查");
        requestMap.put("refund_fee", String.valueOf((int) (amount * 100)));//所需退款金额
        requestMap.put("refund_desc", refundReason);
        try {
            responseMap = wxpay.refund(requestMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String return_code = responseMap.get("return_code");   //返回状态码
        String return_msg = responseMap.get("return_msg");     //返回信息
        if ("SUCCESS".equals(return_code)) {
            String result_code = responseMap.get("result_code");       //业务结果
            String err_code_des = responseMap.get("err_code_des");     //错误代码描述
            if ("SUCCESS".equals(result_code)) {
                //表示退款申请接受成功,结果通过退款查询接口查询
                //修改用户订单状态为退款申请中或已退款。退款异步通知根据需求,可选
                //
                return ResultMap.ok("退款申请成功");
            } else {
                logger.info("订单号:{}错误信息:{}", orderNo, err_code_des);
                return ResultMap.error(err_code_des);
            }
        } else {
            logger.info("订单号:{}错误信息:{}", orderNo, return_msg);
            return ResultMap.error(return_msg);
        }
    }

}

第六步,添加通用返回结果

这个可以有自己的方法,无所谓的

package com.wxpay.demo.common;

import org.apache.http.HttpStatus;

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

/**
 * 应用模块名称
 *
 * @author Rex
 * @since 2020/6/12 11:18
 */
public class ResultMap extends HashMap<String, Object> {
    public ResultMap() {
        put("state", true);
        put("code", 0);
        put("msg", "success");
    }

    public static ResultMap error(int code, String msg) {
        ResultMap r = new ResultMap();
        r.put("state", false);
        r.put("code", code);
        r.put("msg", msg);
        return r;
    }

    public static ResultMap error(String msg) {
        return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
    }

    public static ResultMap error() {
        return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
    }

    public static ResultMap ok(String msg) {
        ResultMap r = new ResultMap();
        r.put("msg", msg);
        return r;
    }

    public static ResultMap ok(Map<String, Object> par) {
        ResultMap r = new ResultMap();
        r.putAll(par);
        return r;
    }

    public static ResultMap ok() {
        return new ResultMap();
    }

    public ResultMap put(String key, Object value) {
        super.put(key, value);
        return this;
    }

}

第七步,调用方式

http://localhost:8080/wxPay/unifiedOrder?orderNo=123456789&amount=1&body=支付

然后会收到返回值,主要是拿到prepayid

{"msg":"success","code":0,"data":{"package":"Sign=WXPay","appid":"wx6c6878cc93e5258c","sign":"C32453E8E71EAE8BB0EAE9A3A23C10BD","partnerid":"1544894961","prepayid":"wx1214084649121595f6e455481682463100","noncestr":"Yqxgko2qqshfpEcH","timestamp":"1591942126"},"state":true}

进而可以给app调用这个接口了。从而调起微信支付

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
好的,下面是一个简单的微信支付回调接口的示例代码,使用了Spring Boot框架和官方的微信支付SDK。 首先,需要在pom.xml文件中添加依赖: ```xml <dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>3.0.0</version> </dependency> ``` 然后,在Spring Boot应用的配置文件中添加微信支付的配置: ```yaml wxpay: app-id: your-app-id mch-id: your-mch-id mch-key: your-mch-key notify-url: your-notify-url ``` 接着,编写支付回调接口的代码: ```java @RestController @RequestMapping("/wxpay") public class WxPayController { @Autowired private WxPayService wxPayService; @PostMapping("/notify") public String notify(@RequestBody String xmlData) throws Exception { Map<String, String> data = WXPayUtil.xmlToMap(xmlData); if (wxPayService.verifyNotify(data)) { // 处理支付成功逻辑 return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>"; } else { // 处理支付失败逻辑 return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[Signature verification failed.]]></return_msg></xml>"; } } } ``` 其中,WxPayService是一个封装了微信支付相关操作的服务类,可以通过@Autowired注解进行自动注入。 在WxPayService中,需要进行签名验证和订单状态更新等操作。以下是一个简单的示例代码: ```java @Service public class WxPayService { @Autowired private WxPayConfig wxPayConfig; public boolean verifyNotify(Map<String, String> data) throws Exception { WXPay wxPay = new WXPay(wxPayConfig); if (wxPay.isPayResultNotifySignatureValid(data)) { String orderId = data.get("out_trade_no"); // TODO: 根据订单号更新订单状态 return true; } else { return false; } } } ``` 以上就是一个简单的微信支付回调接口的示例代码。需要注意的是,这只是一个示例,实际应用中还需要进行更多的错误处理和安全措施。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时光不等仁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值