java版微信和支付宝 支付的调起 和 回调

2023-11-17

写下项目中经常用到的微信和支付宝支付的拉起和回调的代码

1.支付参数和退款参数的封装

package co.yixiang.modules.storePaymentOrder.payment.dto;

import lombok.Data;

/**
 * 支付参数封装
 */
@Data
public class PayParam {
    //商品名称
    private String subject;
    //商品描述
    private String body;
    //订单号
    private String outTradeNo;
    //金额
    private String totalAmount;
    //支付类型 alipay/weChatPay/yue
    //private String paymentType;
    //回传参数 标识当前支付业务类型
    private String passbackParams;
}
package co.yixiang.modules.storePaymentOrder.payment.dto;

import lombok.Data;

/**
 * 退款参数封装
 */
@Data
public class RefundParam {
    //订单号
    private  String outTradeNo;

    //金额
    private  String totalAmount;

    //备注
    private  String body;
}

2.支付宝支付  获取客户端

        

<dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.11.8.ALL</version>
        </dependency>
/**
     * 获得支付宝证书公钥模式客户端(线上)
     * jcd
     * @param alipay
     * @return
     */
    @Override
    public DefaultAlipayClient getAliCertClient(AlipayConfig alipay) {
        DefaultAlipayClient aliCertClient = aliCertClientMap.get("aliCertClient");
        if(aliCertClient != null){
            return aliCertClient;
        }

        File appCert = new File("aliPayCert/appCertPublicKey_*********.crt");
        File alipayCert = new File("aliPayCert/alipayCertPublicKey_RSA2.crt");
        File alipayRootCert = new File("aliPayCert/alipayRootCert.crt");

        try {
            if (!appCert.exists()) {
                //第一种方式
                InputStream stream = AlipayConfigServiceImpl.class.getResourceAsStream("/aliPayCert/appCertPublicKey_2021002121653147.crt");
                FileUtils.copyInputStreamToFile(stream, appCert);
            }
            if (!alipayCert.exists()) {
                InputStream stream = AlipayConfigServiceImpl.class.getResourceAsStream("/aliPayCert/alipayCertPublicKey_RSA2.crt");
                FileUtils.copyInputStreamToFile(stream, alipayCert);
            }
            if (!alipayRootCert.exists()) {
                InputStream stream = AlipayConfigServiceImpl.class.getResourceAsStream("/aliPayCert/alipayRootCert.crt");
                FileUtils.copyInputStreamToFile(stream, alipayRootCert);
            }
        } catch (IOException e) {
            log.error(e.getMessage());
            throw new YshopException(e.getMessage());
        }

        String appCertPath = appCert.getAbsolutePath();
        String alipayCertPath = alipayCert.getAbsolutePath();
        String alipayRootCertPath = alipayRootCert.getAbsolutePath();


        String privateKey="很长的一串字符串";

        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
        certAlipayRequest.setAppId("appid");
        certAlipayRequest.setPrivateKey(privateKey);
        certAlipayRequest.setFormat("JSON");
        certAlipayRequest.setCharset("utf-8");
        certAlipayRequest.setSignType("RSA2");
        certAlipayRequest.setCertPath(appCertPath);
        certAlipayRequest.setAlipayPublicCertPath(alipayCertPath);
        certAlipayRequest.setRootCertPath(alipayRootCertPath);

        DefaultAlipayClient alipayClient = null;

        try {
            alipayClient = new DefaultAlipayClient(certAlipayRequest);
            aliCertClientMap.put("aliCertClient",alipayClient);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        return alipayClient;
    }
package co.yixiang.modules.storePaymentOrder.payment;

import cn.hutool.core.util.ObjectUtil;
import co.yixiang.api.YshopException;
import co.yixiang.exception.BadRequestException;
import co.yixiang.modules.storePaymentOrder.domain.YxStorePaymentOrder;
import co.yixiang.modules.storePaymentOrder.payment.dto.PayParam;
import co.yixiang.modules.storePaymentOrder.payment.dto.RefundParam;
import co.yixiang.modules.storePaymentOrder.service.dto.YxStorePaymentOrderDto;
import co.yixiang.modules.storePaymentOrder.service.dto.YxStorePaymentOrderQueryCriteria;
import co.yixiang.tools.domain.AlipayConfig;
import co.yixiang.tools.service.AlipayConfigService;
import co.yixiang.utils.RedisUtils;
import co.yixiang.utils.ShopKeyUtils;
import co.yixiang.utils.StringUtils;
import com.alipay.api.AlipayApiException;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.util.LinkedHashMap;
import java.util.Map;

@Service
@Slf4j
public class AliPayment {
    @Autowired
    private AlipayConfigService alipayConfigService;
    @Autowired
    private AlipayConfigService alipayService;

    @Autowired
    private RedisUtils redisUtils;

    public String pay(PayParam payParam) {
        AlipayConfig alipay = alipayService.find();
        if (ObjectUtil.isNull(alipay)) {
            throw new YshopException("请先配置支付宝");
        }
        //证书公钥模式
        DefaultAlipayClient alipayClient = alipayConfigService.getAliCertClient(alipay);
        // 创建API对应的request(手机APP版)
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        AlipayTradeAppPayModel bizModel = new AlipayTradeAppPayModel();
        bizModel.setSubject(payParam.getSubject()); //商品名称
        bizModel.setBody(payParam.getBody()); //商品描述
        bizModel.setOutTradeNo(payParam.getOutTradeNo()); //商户订单号
        bizModel.setTimeoutExpress("1740m"); //超时时间
        bizModel.setTotalAmount(payParam.getTotalAmount()); //金额
        bizModel.setProductCode("QUICK_MSECURITY_PAY"); //销售产品码
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId(alipay.getSysServiceProviderId());
        bizModel.setExtendParams(extendParams);
        try {
            bizModel.setPassbackParams(java.net.URLEncoder.encode(payParam.getPassbackParams(),"UTF-8"));//设置回传参数
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        String apiUrl = redisUtils.getY(ShopKeyUtils.getApiUrl());

        request.setBizModel(bizModel);
        request.setNotifyUrl(apiUrl + "/storePaymentOrder/alipay/notify"); //异步通知地址

        // 这里和普通的接口调用不同,使用的是sdkExecute
        AlipayTradeAppPayResponse response = null;
        try {
            response = alipayClient.sdkExecute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        if (response != null && response.isSuccess()) {
            log.info("Body: {}", response.getBody());
            log.info("TradeNo: {}", response.getTradeNo());
            log.info("TotalAmount: {}", response.getTotalAmount());
            log.info("MerchantOrderNo: {}", response.getMerchantOrderNo());
            log.info("OutTradeNo: {}", response.getOutTradeNo());
            log.info("SellerId: {}", response.getSellerId());
            return response.getBody();
        } else if (response != null) {
            log.error("Body: {}", response.getBody());
        }
        return null;
    }

    public Boolean refundOrder(RefundParam pefundParam) {
        AlipayConfig alipay = alipayService.find();
        if(alipay.getId() == null){
            throw new BadRequestException("请先添加相应配置,再操作");
        }
        //普通公钥模式 20220415 弃用
        //AlipayClient alipayClient = new DefaultAlipayClient(alipay.getGatewayUrl(), alipay.getAppId(), alipay.getPrivateKey(), alipay.getFormat(), alipay.getCharset(), alipay.getPublicKey(), alipay.getSignType());

        DefaultAlipayClient alipayClient = alipayConfigService.getAliCertClient(alipay);


        String apiUrl = redisUtils.getY(ShopKeyUtils.getApiUrl());

        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel bizModel = new AlipayTradeRefundModel();
        bizModel.setOutTradeNo(pefundParam.getOutTradeNo());
        bizModel.setRefundAmount(pefundParam.getTotalAmount());
        bizModel.setRefundReason(pefundParam.getBody());
        request.setBizModel(bizModel);
        request.setNotifyUrl(apiUrl + "/storePaymentOrder/alipay/notify");

        try {
            //弃用公钥模式,需要改变调用方式
            //AlipayTradeRefundResponse response = alipayClient.execute(request);

            //公钥证书模式的调用方式
            AlipayTradeRefundResponse response = alipayClient.certificateExecute(request);
            if (response != null && response.isSuccess()) {
                log.info("Msg: {}", response.getMsg());
                log.info("SubMsg: {}", response.getSubMsg());
                log.info("Body: {}", response.getBody());
                log.info("Code: {}", response.getCode());
                log.info("SubCode: {}", response.getSubCode());
                if (StringUtils.containsIgnoreCase(response.getMsg(),"Success")) {
                    return Boolean.valueOf(true);
                } else {
                    return Boolean.valueOf(false);
                }
            }
        } catch (Exception e) {
            //e.printStackTrace();
            log.error("支付宝退款错误: {}", e.getMessage());
        }
        return null;
    }
}

支付宝的回调

package co.yixiang.modules.storePaymentOrder.notify;

import cn.hutool.core.util.NumberUtil;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.enums.BillDetailEnum;
import co.yixiang.enums.OrderInfoEnum;
import co.yixiang.enums.PayTypeEnum;
import co.yixiang.modules.order.domain.YxStoreOrder;
import co.yixiang.modules.storePaymentOrder.event.StorePaymentOrderEvent;
import co.yixiang.modules.user.domain.YxUserRecharge;
import co.yixiang.tools.domain.AlipayConfig;
import co.yixiang.tools.service.AlipayConfigService;
import co.yixiang.tools.utils.AliPayStatusEnum;
import co.yixiang.tools.utils.AlipayUtils;
import co.yixiang.utils.StringUtils;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 商城其他支付项阿里支付的回调接口
 */
@Slf4j
@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@RequestMapping("/storePaymentOrder/alipay")
public class AlipayNotify {

    private final AlipayUtils alipayUtils;
    private final AlipayConfigService alipayService;
    private final ApplicationEventPublisher publisher;

    @AnonymousAccess
    @RequestMapping(value = "/notify", method = {RequestMethod.GET, RequestMethod.POST})
    @SuppressWarnings("all")
    @ApiOperation("支付异步通知(要公网访问),接收异步通知,检查通知内容app_id、out_trade_no、total_amount是否与请求中的一致,根据trade_status进行后续业务处理")
    public ResponseEntity<Object> notify(HttpServletRequest request) throws UnsupportedEncodingException {
        AlipayConfig alipay = alipayService.find();
        Map<String, String[]> parameterMap = request.getParameterMap();
        //内容验签,防止黑客篡改参数
        //if (alipayUtils.rsaCheck(request,alipay)) {
        if(alipayUtils.ZSRsaCheck(request,alipay)){
            //交易状态
            String tradeStatus = getRequestParameter(request, "trade_status");
            // 商户订单号
            String outTradeNo = getRequestParameter(request, "out_trade_no");
            //支付宝交易号
            String tradeNo = getRequestParameter(request, "trade_no");
            //付款金额
            String totalAmount = getRequestParameter(request, "total_amount");
            //退款金额
            String refundFee = getRequestParameter(request, "refund_fee");

            //获取回传参数paymentType
            String passbackParams = getRequestParameter(request, "passback_params");
            Map<String,String> map=new HashMap<>();
            if(StringUtils.isNotBlank(passbackParams)){
                passbackParams= java.net.URLDecoder.decode(passbackParams,"UTF-8");
                String[] split = StringUtils.split(passbackParams, ";");
                for (int i=0;i<split.length;i++){
                    String[] split1 = StringUtils.split(split[i], "=");
                    map.put(split1[0],split1[1]);
                }
            }


            //记录日志
            if (StringUtils.isNotEmpty(refundFee)) {
                log.info(">>>>> 交易状态: {}, 商户订单号: {}, 支付宝交易号: {}, 退款金额: {}", tradeStatus, outTradeNo, tradeNo, refundFee);
                //验证
                if (AliPayStatusEnum.CLOSED.getValue().equals(tradeStatus)) {
                    // outTradeNo 退款成功
                    publisher.publishEvent(new StorePaymentOrderEvent(this, outTradeNo,1,map));
                }
            } else if (StringUtils.isNotEmpty(totalAmount)) {
                log.info(">>>>> 交易状态: {}, 商户订单号: {}, 支付宝交易号: {}, 付款金额: {}", tradeStatus, outTradeNo, tradeNo, totalAmount);
                //验证
                if (AliPayStatusEnum.SUCCESS.getValue().equals(tradeStatus) || AliPayStatusEnum.FINISHED.getValue().equals(tradeStatus)) {
                    // outTradeNo 支付成功
                    publisher.publishEvent(new StorePaymentOrderEvent(this, outTradeNo,0,map));
                }
            } else {
                log.info(">>>>> 交易状态: {}, 商户订单号: {}, 支付宝交易号: {}", tradeStatus, outTradeNo, tradeNo);
            }

            //有回传参数
            /*if(map.containsKey("paymentType")){
                String paymentType = map.get("paymentType");
                if(StringUtils.equals(paymentType, "指定类型")){

                }
            }*/

            return new ResponseEntity<>("success",HttpStatus.OK);//返回success ,让支付宝不在重复调起回调
        }
        //记录日志
        log.info(">>>>> 请求失败");
        return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
    }

    private String getRequestParameter(HttpServletRequest request, String valname) {
        String value = request.getParameter(valname);
        if (value != null) {
            return new String(value.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
        }
        return value;
    }
}

支付宝回调验签

/**
     * 公钥证书模式效验签名
     * @param request
     * @param alipay
     * @return
     */
    public boolean ZSRsaCheck(HttpServletRequest request, AlipayConfig alipay){
        /**
         * 支付宝沙箱模式 验签需要的支付宝公钥证书
         */
        /*
        File alipayCert = new File("aliPayCertSandbox/alipayCertPublicKey_RSA2.crt");
        try {
            if (!alipayCert.exists()) {
                InputStream stream = AlipayConfigServiceImpl.class.getResourceAsStream("/aliPayCertSandbox/alipayCertPublicKey_RSA2.crt");
                FileUtils.copyInputStreamToFile(stream, alipayCert);
            }

        } catch (IOException e) {
            log.error("alipayCertPublicKey 证书文件未找到:{}",e.getMessage());
            throw new YshopException(e.getMessage());
        }*/


        /**
         * 支付宝线上的验签需要的支付宝公钥证书
         */
        File alipayCert = new File("aliPayCert/alipayCertPublicKey_RSA2.crt");
        try {
            if (!alipayCert.exists()) {
                InputStream stream = AlipayConfigServiceImpl.class.getResourceAsStream("/aliPayCert/alipayCertPublicKey_RSA2.crt");
                FileUtils.copyInputStreamToFile(stream, alipayCert);
            }

        } catch (IOException e) {
            log.error("alipayCertPublicKey 证书文件未找到:{}",e.getMessage());
            throw new YshopException(e.getMessage());
        }
        //支付宝公钥证书
        String alipayPublicCertPath=alipayCert.getAbsolutePath();

        /**
         * 这种方式是先获取请求中所有参数,在转成 & 和 = 的url参数格式,在分解 & = 格式得到一个map,这种方式有重复的步骤,效率不高
         */
        /*
        //签名方式
        String sign_type="RSA2";
        //对待签名字符串数据通过&进行拆分
        Map requestParams = request.getParameterMap();
        LinkedHashMap<String, String> map =  new LinkedHashMap<String, String>();
        //把拆分数据放在map集合内
        for (Object o : requestParams.keySet()) {
            String name = (String) o;
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            map.put(name, valueStr);
        }


        String join = Joiner.on("&")
            // 用指定符号代替空值,key 或者value 为null都会被替换
            .useForNull("")
            .withKeyValueSeparator("=")
            .join(map);

        //对待签名字符串数据通过&进行拆分
        String [] temp = join.split("&");
        LinkedHashMap<String, String> map0 =  new LinkedHashMap<String, String>();
        //把拆分数据放在map集合内
        for (int i = 0; i < temp.length; i++) {
            String[] arr = temp[i].split("=", 2); //通过"="号分割成2个数据
            String[] tempAagin = new String[arr.length]; //再开辟一个数组用来接收分割后的数据
            for (int j = 0; j < arr.length; j++) {
                tempAagin[j] = arr[j];
            }
            map0.put(tempAagin[0], tempAagin[1]);
        }*/


        /**
         * 这种方式效率高一点
         */
        //签名方式
        String sign_type="RSA2";
        //对待签名字符串数据通过&进行拆分
        Map requestParams = request.getParameterMap();
        LinkedHashMap<String, String> map =  new LinkedHashMap<String, String>();
        //把拆分数据放在map集合内
        for (Object o : requestParams.keySet()) {
            String name = (String) o;
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            map.put(name, valueStr);
        }

        try {
            return AlipaySignature.rsaCertCheckV1(map, alipayPublicCertPath, "utf-8",sign_type);
        } catch (AlipayApiException e) {
            log.error("支付宝异步验签失败:{}",e.getMessage());
            return false;
        }
    }

3.微信支付

<dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-pay</artifactId>
            <version>3.9.0</version>
        </dependency>
package co.yixiang.modules.storePaymentOrder.payment;

import cn.hutool.core.util.IdUtil;
import co.yixiang.api.BusinessException;
import co.yixiang.modules.storePaymentOrder.payment.dto.PayParam;
import co.yixiang.modules.storePaymentOrder.payment.dto.RefundParam;
import co.yixiang.tools.config.WeixinPayConfig;
import co.yixiang.utils.IpUtil;
import co.yixiang.utils.RedisUtil;
import co.yixiang.utils.RedisUtils;
import co.yixiang.utils.ShopKeyUtils;
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付服务类
 */
@Service
@Slf4j
public class WeChatPayment {
    @Autowired
    private RedisUtils redisUtils;


    public String pay(PayParam payParam) {

        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(RedisUtil.get(ShopKeyUtils.getWxNativeAppAppId()));
        payConfig.setMchId(redisUtils.getY(ShopKeyUtils.getWxPayMchId()));
        payConfig.setMchKey(redisUtils.getY(ShopKeyUtils.getWxPayMchKey()));
        payConfig.setKeyPath(redisUtils.getY(ShopKeyUtils.getWxPayKeyPath()));
        // 可以指定是否使用沙箱环境
        payConfig.setUseSandboxEnv(false);
        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);


        String apiUrl = redisUtils.getY(ShopKeyUtils.getApiUrl());
        BigDecimal bigDecimal = new BigDecimal(100);
        int payPrice = bigDecimal.multiply(new BigDecimal(payParam.getTotalAmount())).intValue();

        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setOutTradeNo(payParam.getOutTradeNo());
        orderRequest.setTotalFee(payPrice);
        orderRequest.setSpbillCreateIp(IpUtil.getLocalIP());
        orderRequest.setNotifyUrl(apiUrl + "/api/storePaymentOrder/weChatPay/payment/notify");
        //orderRequest.setNotifyUrl("http://18bd-222-142-153-201.ngrok.io" + "/api/wechat/notify");
        //orderRequest.setNotifyUrl("http://gjpvd6.natappfree.cc" + "/api/wechat/notify");
        orderRequest.setBody(payParam.getBody());
        orderRequest.setAttach(payParam.getPassbackParams());
        orderRequest.setTradeType("APP");
        try {
            WxPayAppOrderResult wxPayAppOrderResult = (WxPayAppOrderResult)wxPayService.createOrder(orderRequest);

            Map<String,String> jsConfig = new HashMap<>();
            jsConfig.put("appid",wxPayAppOrderResult.getAppId());
            jsConfig.put("partnerid",wxPayAppOrderResult.getPartnerId());
            jsConfig.put("prepayid",wxPayAppOrderResult.getPrepayId());
            jsConfig.put("package",wxPayAppOrderResult.getPackageValue());
            jsConfig.put("noncestr",wxPayAppOrderResult.getNonceStr());
            jsConfig.put("timestamp",wxPayAppOrderResult.getTimeStamp());
            jsConfig.put("sign",wxPayAppOrderResult.getSign());

            Gson gson = new GsonBuilder().disableHtmlEscaping().create();

            String s = gson.toJson(jsConfig);
            return s;
        }catch (WxPayException e) {
            log.info("支付错误信息:{}",e.getMessage());
            throw new BusinessException(e.getMessage());
        }
    }


    public void refundOrder(RefundParam refundParam) {
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(RedisUtil.get(ShopKeyUtils.getWxNativeAppAppId()));
        payConfig.setMchId(redisUtils.getY(ShopKeyUtils.getWxPayMchId()));
        payConfig.setMchKey(redisUtils.getY(ShopKeyUtils.getWxPayMchKey()));
        payConfig.setKeyPath(redisUtils.getY(ShopKeyUtils.getWxPayKeyPath()));
        // 可以指定是否使用沙箱环境
        payConfig.setUseSandboxEnv(false);
        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);

        String apiUrl = redisUtils.getY(ShopKeyUtils.getApiUrl());

        WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
        BigDecimal bigDecimal = new BigDecimal("100");
        int totalFee = bigDecimal.multiply(new BigDecimal(refundParam.getTotalAmount())).intValue();
        //订单总金额
        wxPayRefundRequest.setTotalFee(totalFee);
        wxPayRefundRequest.setOutTradeNo(refundParam.getOutTradeNo());
        //生成退款单号
        String orderSn = IdUtil.getSnowflake(0,0).nextIdStr();
        wxPayRefundRequest.setOutRefundNo(orderSn);
        //退款金额
        wxPayRefundRequest.setRefundFee(totalFee);
        wxPayRefundRequest.setNotifyUrl(apiUrl + "/api/storePaymentOrder/weChatPay/refund/notify");
        //wxPayRefundRequest.setNotifyUrl("http://e7de-219-154-179-218.ngrok.io" + "/api/notify/refund");
        //wxPayRefundRequest.setNotifyUrl("http://gjpvd6.natappfree.cc" + "/api/notify/refund");
        try {
            wxPayService.refundV2(wxPayRefundRequest);
        } catch (WxPayException e) {
            log.info("退款错误信息:{}",e.getMessage());
            throw new BusinessException(e.getMessage());
        }
    }
}

微信支付的回调

package co.yixiang.modules.storePaymentOrder.notify;

import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.enums.BillDetailEnum;
import co.yixiang.enums.OrderInfoEnum;
import co.yixiang.enums.PayMethodEnum;
import co.yixiang.modules.mp.config.WxPayConfiguration;
import co.yixiang.modules.order.event.WechatPaySuccessEvent;
import co.yixiang.modules.order.event.WechatRefundSuccessEvent;
import co.yixiang.modules.storePaymentOrder.event.StorePaymentOrderEvent;
import co.yixiang.modules.user.domain.YxUserRecharge;
import co.yixiang.utils.*;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * 商城其他支付项微信支付的回调接口
 */
@Slf4j
@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@RequestMapping("/storePaymentOrder/weChatPay")
public class WeChatPayNotify {
    private static RedisUtils redisUtils;
    private final ApplicationEventPublisher publisher;
    /**
     * 微信支付/充值回调
     */
    @AnonymousAccess
    @PostMapping("/payment/notify")
    @ApiOperation(value = "微信支付充值回调",notes = "微信支付充值回调")
    public String  renotify(@RequestBody String xmlData) {
        try {
            WxPayConfig payConfig = new WxPayConfig();
            payConfig.setAppId(RedisUtil.get(ShopKeyUtils.getWxNativeAppAppId()));
            payConfig.setMchId(redisUtils.getY(ShopKeyUtils.getWxPayMchId()));
            payConfig.setMchKey(redisUtils.getY(ShopKeyUtils.getWxPayMchKey()));
            payConfig.setKeyPath(redisUtils.getY(ShopKeyUtils.getWxPayKeyPath()));
            // 可以指定是否使用沙箱环境
            payConfig.setUseSandboxEnv(false);
            WxPayService wxPayService = new WxPayServiceImpl();
            wxPayService.setConfig(payConfig);

            WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);
            String orderId = notifyResult.getOutTradeNo();
            String attach = notifyResult.getAttach();

            //获取回传参数paymentType
            Map<String,String> map=new HashMap<>();
            if(StringUtils.isNotBlank(attach)){
                String[] split = StringUtils.split(attach, ";");
                for (int i=0;i<split.length;i++){
                    String[] split1 = StringUtils.split(split[i], "=");
                    map.put(split1[0],split1[1]);
                }
            }

            publisher.publishEvent(new StorePaymentOrderEvent(this, orderId,0,map));
            return WxPayNotifyResponse.success("OK");
        } catch (WxPayException e) {
            log.error(e.getMessage());
            return WxPayNotifyResponse.fail(e.getMessage());
        }

    }

    /**
     * 微信退款回调
     */
    @AnonymousAccess
    @ApiOperation(value = "退款回调通知处理",notes = "退款回调通知处理")
    @PostMapping("/refund/notify")
    @Transactional(rollbackFor=Exception.class)
    public String parseRefundNotifyResult(@RequestBody String xmlData, HttpServletResponse response) {
        try {
            WxPayConfig payConfig = new WxPayConfig();
            payConfig.setAppId(RedisUtil.get(ShopKeyUtils.getWxNativeAppAppId()));
            payConfig.setMchId(redisUtils.getY(ShopKeyUtils.getWxPayMchId()));
            payConfig.setMchKey(redisUtils.getY(ShopKeyUtils.getWxPayMchKey()));
            payConfig.setKeyPath(redisUtils.getY(ShopKeyUtils.getWxPayKeyPath()));
            // 可以指定是否使用沙箱环境
            payConfig.setUseSandboxEnv(false);
            WxPayService wxPayService = new WxPayServiceImpl();
            wxPayService.setConfig(payConfig);

            WxPayRefundNotifyResult result = wxPayService.parseRefundNotifyResult(xmlData);
            String orderId = result.getReqInfo().getOutTradeNo();
            BigDecimal refundFee = BigNum.div(result.getReqInfo().getRefundFee(), 100);

            publisher.publishEvent(new StorePaymentOrderEvent(this, orderId,0,null));
            return WxPayNotifyResponse.success("OK");
        } catch (WxPayException | IllegalAccessException  e) {
            log.error(e.getMessage());
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }
}

4.spring 事件 因为微信的回调超过几秒没有响应的话,会继续回调,所以需要发布一个事件,快速响应回调

package co.yixiang.modules.storePaymentOrder.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.core.annotation.Order;

import java.util.Map;

/**
 * 商城其他支付项的支付成功和退款成功事件
 */
@Order(500)
public class StorePaymentOrderEvent extends ApplicationEvent{
    private static final long serialVersionUID = 1L;

    private final String orderId;
    private final Integer type;//0:支付成功 1:退款成功
    private final Map passbackParams; //回传参数

    public StorePaymentOrderEvent(Object source, String orderId,Integer type,Map passbackParams) {
        super(source);
        this.orderId=orderId;
        this.type=type;
        this.passbackParams=passbackParams;
    }
    public String getOrderId() {
        return this.orderId;
    }
    public Integer getType() {
        return this.type;
    }
    public Map getPassbackParams() {
        return this.passbackParams;
    }
}
package co.yixiang.modules.storePaymentOrder.event;

import cn.hutool.core.util.StrUtil;
import co.yixiang.enums.BillDetailTreeEnum;
import co.yixiang.enums.BillEnum;
import co.yixiang.modules.cooperativeAgent.domain.YxUserCheckInCooperativeAgent;
import co.yixiang.modules.cooperativeAgent.service.YxUserCheckInCooperativeAgentService;
import co.yixiang.modules.cooperativeAgent.service.enums.OrderCooperativeAgentEnum;
import co.yixiang.modules.storePaymentOrder.domain.YxStorePaymentOrder;
import co.yixiang.modules.storePaymentOrder.enums.StorePaymentOrder;
import co.yixiang.modules.storePaymentOrder.service.YxStorePaymentOrderService;
import co.yixiang.modules.user.domain.YxUser;
import co.yixiang.modules.user.domain.YxUserBill;
import co.yixiang.modules.user.service.YxUserBillService;
import co.yixiang.modules.user.service.YxUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

@Component
@Slf4j
public class StorePaymentOrderListen {
    @Autowired
    private YxStorePaymentOrderService yxStorePaymentOrderService;

    @Autowired
    private YxUserCheckInCooperativeAgentService yxUserCheckInCooperativeAgentService;
    @Autowired
    private YxUserService userService;
    @Autowired
    private YxUserBillService billService;

    @Async
    @EventListener
    public void paySuccess(StorePaymentOrderEvent event) {
        String orderId = event.getOrderId();
        Map passbackParams = event.getPassbackParams();
        log.info(passbackParams.toString());
        Integer type = event.getType();
        if(type == 0){
            //支付成功
       
        }else if(type == 1){
            //退款成功
            //未实现
        }
    }
}

uniapp 的 调用

支付宝

uni.requestPayment({
					      provider: 'alipay',
					      orderInfo: res.data.pay, 
					      success: function (res) {
					          console.log('success:' + JSON.stringify(res));
	
					      },
					      fail: function (err) {
					          console.log('fail:' + JSON.stringify(err));
					      }
					  });

微信

let option=JSON.parse(res.data.pay);
					  let orderInfo = {
					    appid: option.appid,
					    noncestr: option.noncestr,
					    package: option.package,
					    partnerid: option.partnerid,
					    prepayid: option.prepayid,
					    sign: option.sign,
					    timestamp: option.timestamp + '',
					  }
					  // 调用只接口
					  uni.requestPayment({
					    provider: 'wxpay',
					    ...option,
					    timestamp: orderInfo.timestamp,
					    orderInfo,
					    success: (success) => {
					      that.getSignMes()
					    },
					    fail: (error) => {
					     
					    }
					  })

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

java版微信和支付宝 支付的调起 和 回调 的相关文章

随机推荐

  • C语言中的结构体(struct)

    C语言中 结构体类型属于一种构造类型 其他的构造类型还有 数组类型 联合类型 本文主要介绍关于结构体以下几部分 1 概念 为什么要有结构体 因为在实际问题中 一组数据往往有很多种不同的数据类型 例如 登记学生的信息 可能需要用到 char型
  • TCP滑动窗口和拥塞控制

    目录 滑动窗口 什么是滑动窗口 为什么要使用滑动窗口 滑动窗口的工作原理 滑动窗口会出现的几种问题 数据包丢失怎么解决 ACK丢失怎么解决 拥塞控制 拥塞控制是什么 拥塞控制的实现 理解拓展 拥塞控制是如何判断网络拥塞情况的 滑动窗口 什么
  • 虚拟机防火墙以及端口操作

    CentOS7 firewalld 默认安装 和 iptables 都不是防火墙 它们只是防火墙的管理程序 防火墙的开启 关闭 禁用命令 设置开机启用 禁用防火墙 systemctl enable disable firewalld ser
  • ⛳ 面试题-单例模式会存在线程安全问题吗?

    目录 面试题 单例模式会存在线程安全问题吗 一 单例模式 简介 二 饿汉式 三 懒汉式 3 1 懒汉式 在调用 getInstance 的时候才创建对象 线程不安全 3 2 改造1 对懒汉式进行加锁改造 线程安全 3 3 改造2 对懒汉式继
  • 网络抓包命令

    Linux环境下抓包 可以使用tcpdump命令 tcpdump i ens192 w dataAll pcap port 8008 这其中 ens192 指代网卡 可以通过ifconfig获取 也可以直接用 any 代替 意思是抓取全部网
  • CSS快速实现居中

    上效果 实现 父元素 diplay flex div用 margin auto
  • Windows7(sp1)上第一次搭建Flutter开发环境踩坑记录

    环境变量的配置 系统环境的要求 SDK的下载这些在Flutter中文网和各种博客中已经讲的很多了 过程中有问题也可以很快的解决 有一点需要说一下 我先是从Flutter中文网直接下载的SDK压缩包 解压后在Flutter目录下打开flutt
  • linux启动kvm虚拟机,CentOS 7系统KVM虚拟机支持UEFI启动

    1 安装OVMF Open Virtual Machine Firmware root DT Node 172 30 200 203 cat gt etc yum repos d kraxel repo lt create new qemu
  • nginx 卸载后重新安装/etc/nginx配置文件没了,cannot open /etc/nginx/nginx.conf (No such file or directory)

    sudo apt get purge remove nginx common sudo apt get purge remove nginx sudo apt get autoremove sudo apt install nginx
  • 解决nginx报错:502 Bad Gateway以及504 Gateway Time-out问题

    wordpress及宝塔面板的基本环节 出现nginx错误 502 Bad Gateway 502 Bad Gateway以及504 Gateway Time out 504 Gateway Time out问题后的解决办法 更多分类文章
  • Intellij IDEA 自动生成 serialVersionUID

    Setting gt Inspections gt Serialization issues gt Serializable class without serialVersionUID 选上以后 在你的class中 Alt Enter就会
  • 网络安全行业的那些岗位

    网络安全行业 正在蓬勃发展 想要找网络安全岗位的 可以参考这篇文章 一 网络安全岗位 1 需要网络安全人员的企业 有三种企业招聘网络安全人员 乙方企业 甲方企业 国有企业 乙方企业是专门从事网络安全行业的企业 为客户提供安全产品 如防火墙
  • VMware vRealize Suite 8.8.0

    https pan baidu com s 16 VtEGgAMia8vLjMweHjGA 输入提示信息 j323 目录 VMware vRealize Suite 2019 8 8 0 百度网盘群共享 629229614 VMware爱好
  • 抖音,B站,小红书三大平台品牌投放特征与建议

    目前 小红书 抖音 B站作为品牌投放的主要平台 应该如何选择 一 抖音 平台特征 用户类型 抖音用户男女均衡 以19 30岁年龄阶段用户为主 一二线城市用户偏多 南方用户偏多 内容形式 表演剧情 vlog 颜值出境等丰富多样的短视频展示形式
  • 【雅思备考】写作表达积累

    小作文 Line graph amount of source of provided generating 用来描述来源 means of xxx generation 生产方式 over a period of over the per
  • 【重磅推荐】vue之web3.js以太坊开发总结与完整案例!

    一个完整的Vue web3 js 基于Metamask开发测试和正式上线 FirstContract sol文件 pragma solidity gt 0 4 24 lt 0 7 0 contract FirstContract strin
  • www外部异步加载(不卡)-适合大量加载

    www外部异步加载 不卡 适合大量加载
  • 第一二天作业-BGP MPLS + OSPF分流互备做法

    三 MPLS OSPF分流互备做法 MPLS OSPF分流互备做法配置命令 在中间骨干区域所有路由器先配置OSPF 然后在中间骨干区域所有路由器上配置MPLS 先创建mpls lsr id 在全局开启mpls 在全局开启mpls ldp 在
  • Linux操作系统的层次与组成

    1 Linux操作系统的层次结构 简单来说 Linux操作系统整体分为三层 1 硬件系统 包括CPU 内存 硬盘 网卡等 2 内核 这是操作系统的核心 负责管理硬件系统 同时为上层的应用程序提供操作接口 3 用户进程 表示计算机中运行的所有
  • java版微信和支付宝 支付的调起 和 回调

    写下项目中经常用到的微信和支付宝支付的拉起和回调的代码 1 支付参数和退款参数的封装 package co yixiang modules storePaymentOrder payment dto import lombok Data 支