当前位置:   article > 正文

SpringBoot + 微信支付集成+H5支付_wechatpayservice.payorder(callbackdata.getattach()

wechatpayservice.payorder(callbackdata.getattach()

最近在做订单支付,既然都做到这里,突然想起了博客,那么就来记录一波
 

1.应用场景:学生志愿填报推荐,线上付款。

2.数据流程
   学生登录 - 数据采集 - 生成订单 - 前端发起支付 - 后端处理数据(调用微信接口,返回数据给前端) - 生成支付单  -  等待回调 - 处理回调数据 - 更改订单状态 - 生成推荐数据 (整体业务流程就是这样,但是主要写支付逻辑这一块)
3.代码展示
 

1)引入微信支付集成jar

<!--引入微信支付-->
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-pay</artifactId>
    <version>3.4.0</version>
</dependency>
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-mp</artifactId>
    <version>3.4.0</version>
</dependency>
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-miniapp</artifactId>
    <version>3.5.0</version>
</dependency>

2)编写微信相关配置类

/**
 * 微信相关配置
 */
@Data
@Component
@ConfigurationProperties(prefix = "wechat")
public class WechatAccountConfig {

    // 小程序 appId
    private String mpAppId;

    // 小程序 appSecret
    private String mpAppSecret;

    // 微信支付ip
    private String ip;

    // 微信支付回调地址
    private String wechatPayCallback;

    // 微信退款回调地址
    private String weRefundCallback;
,
    // 授权类型,此处只需填写 authorization_code
    private String grantType;

    // 微信登录认证地址,登录凭证校验
    private String authCode2Session;

    // 微信token获取地址
    private String accessToken;

    // 商户密钥
    private String mchKey;

    //商户号
    private String mchId;

    // 支付证书路径
    private String keyPath;
}

3)application.yml 文件配置

wechat:
  mpAppId: 。。。。
  mpAppSecret: 。。。。
  validateUrl: 。。。。
  validateData: 。。。。
  ip: 。。。。(按理说是获取支付用户的ip地址,微信那边必传但是不重要)
  wechatPayCallback: /weChat/pay/notify
  weRefundCallback: http:/weChat/pay/wxRefundNotify
  grantType: 。。。。
  mchKey: 。。。。
  mchId: 。。。。
  keyPath: 。。。。

4)MallApplication 启动类增加微信相关
 

@Bean
public WxMpService wxMpService(){
    WxMpService wxMpService = new WxMpServiceImpl();
    wxMpService.setWxMpConfigStorage(wxMpConfigStorage());
    return wxMpService;
}

@Bean
public WxMpConfigStorage wxMpConfigStorage(){
    WxMpInMemoryConfigStorage wxMpConfigStorage = new WxMpInMemoryConfigStorage();
    wxMpConfigStorage.setAppId(wechatAccountConfig.getMpAppId());
    wxMpConfigStorage.setSecret(wechatAccountConfig.getMpAppSecret());
    return wxMpConfigStorage;
}

@Bean
public WxPayConfig wxPayConfig(){
    WxPayConfig payConfig = new WxPayConfig();
    payConfig.setSignType(WxPayConstants.SignType.MD5);
    payConfig.setNotifyUrl(wechatAccountConfig.getWechatPayCallback());

    payConfig.setAppId(wechatAccountConfig.getMpAppId());
    payConfig.setKeyPath(wechatAccountConfig.getKeyPath());
    payConfig.setMchId(wechatAccountConfig.getMchId());
    payConfig.setMchKey(wechatAccountConfig.getMchKey());

    return payConfig;
}

@Bean
public WxPayService wxPayService(){
    WxPayService wxPayService = new WxPayServiceImpl();
    wxPayService.setConfig(wxPayConfig());
    return wxPayService;
}

5)重点来了  WeChatServerDto 支付相关

@Slf4j
@Service
public class WeChatServerDto {

    @Autowired
    private WechatAccountConfig config;

    @Autowired
    private WxPayConfig wxPayConfig;

    @Autowired
    private WxPayService wxPayService;

    @Autowired
    private OrderServiceDto orderServiceDto;

    /**
     * 发起支付 方法前后处理订单逻辑 
     * @param reqDto
     * @return
     */
    public WxPayMpOrderResult payMpOrder(PayReqDto reqDto) throws SoaException {
        WxPayMpOrderResult unOrder = null;

        String tradeType = null;
        try {
            switch (reqDto.getPaymentType()){
                case APP_WECHAT:
                    tradeType = WxPayConstants.TradeType.APP;

                    break;
                case SMALL_PROGRAM:

                    tradeType = WxPayConstants.TradeType.JSAPI;

                    if (StringUtils.isEmpty(reqDto.getOpenId())){
                        throw new SoaException("openid不能为空");
                    }

                    WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();

                    wxPayConfig.setKeyPath(config.getKeyPath());
                    wxPayConfig.setMchKey(config.getMchKey());
                    wxPayConfig.setMchId(config.getMchId());
                    wxPayConfig.setAppId(config.getMpAppId());

                    // JSAPI支付openid必须传
                    orderRequest.setOpenid(reqDto.getOpenId());
                    orderRequest.setBody("商品购买");
                    orderRequest.setAppid(config.getMpAppId());
                    orderRequest.setMchId(config.getMchId());
                    //NATIVE -- 处理回调
                    orderRequest.setAttach(reqDto.getEPayScene().name());
                    // 商户订单号
                    orderRequest.setOutTradeNo(reqDto.getOrderNo());
                    // 支付币种 人名币
                    orderRequest.setFeeType("CNY");
                    // 支付金额 单位分
                    orderRequest.setTotalFee(reqDto.getPayMoney());
                    // 终端ip
                    orderRequest.setSpbillCreateIp(config.getIp());
                    // 微信支付回调地址
                    orderRequest.setNotifyUrl(config.getWechatPayCallback());
                    //支付类型
                    orderRequest.setTradeType(tradeType);
                    log.info("微信支付订单{}创建参数: {}", tradeType, JSONObject.toJSONString(orderRequest));
                    unOrder = wxPayService.createOrder(orderRequest);
                    log.info("微信支付订单{}创建返回结果: {}", tradeType, JSONObject.toJSONString(unOrder));
                    break;
                default:
                    break;
            }

        }catch (Exception e){
            throw new SoaException("发起支付失败!");
        }

        return unOrder;
    }

    /**
     * 微信退款 方法前后处理订单逻辑
     * @param refundReqDto
     * @return
     */
    private WxPayRefundResult refund(RefundReqDto refundReqDto) throws SoaException {

        WxPayRefundResult wxPayRefundResult = null;

        try {
            wxPayConfig.setKeyPath(config.getKeyPath());
            wxPayConfig.setMchKey(config.getMchKey());
            wxPayConfig.setMchId(config.getMchId());
            wxPayConfig.setAppId(config.getMpAppId());

            WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();

            wxPayRefundRequest.setAppid(config.getMpAppId());
            wxPayRefundRequest.setMchId(config.getMchId());
            //设置微信订单号
            wxPayRefundRequest.setTransactionId(refundReqDto.getTransactionId());
            //订单号(自己的)
            wxPayRefundRequest.setOutTradeNo(refundReqDto.getOrderNo());

            // 微信订单号,唯一,一个号码只能退一次,分批次退款需要
            wxPayRefundRequest.setOutRefundNo(refundReqDto.getRefundNo());
            //订单金额 单位分
            wxPayRefundRequest.setTotalFee(refundReqDto.getTotalAmount());
            //退款金额 单位分
            wxPayRefundRequest.setRefundFee(refundReqDto.getAmount());
            //退款货币种类
            wxPayRefundRequest.setRefundFeeType("CNY");
            // 退款原因
            wxPayRefundRequest.setRefundDesc(refundReqDto.getRemark());
            // 退款回调路径
            wxPayRefundRequest.setNotifyUrl(config.getWeRefundCallback());

            log.info("微信退款请求对象-->{}", wxPayRefundRequest.toString());
            log.info("微信配置对象-->{}", wxPayConfig.toString());
            log.info("微信退款订单号{}: 退款单号{}", refundReqDto.getOrderNo(),  refundReqDto.getRefundNo());
            wxPayRefundResult = wxPayService.refund(wxPayRefundRequest);
            log.info("微信退款订单{}:创建返回结果: {}", refundReqDto.getOrderNo(), JSONObject.toJSONString(wxPayRefundResult));

        } catch (Exception e) {
            e.printStackTrace();
            log.error("微信退款订单{}创建失败!退款单号:{},原因:{}",refundReqDto.getOrderNo(), refundReqDto.getRefundNo(), e.getMessage());
            throw new SoaException("微信支付订单创建失败!订单号:" + refundReqDto.getOrderNo());
        }

        return wxPayRefundResult;
    }

    /**
     * 微信支付回调
     * @param xmlResult
     */
    public void payNotify(String xmlResult) throws Exception{

        //转化xml数据
        WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlResult);
        log.info("微信回调报文-->{}", result.toString());

        wxPayConfig.setKeyPath(config.getKeyPath());
        wxPayConfig.setMchKey(config.getMchKey());
        wxPayConfig.setMchId(config.getMchId());
        wxPayConfig.setAppId(config.getMpAppId());
        wxPayService.parseOrderNotifyResult(xmlResult);
        // 返回状态值
        String returnCode = result.getReturnCode();
        String resultCode = result.getResultCode();

        if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {

            // 回执订单号,付款时候穿入的,
            String outTradeNo = result.getOutTradeNo();

            // 金额
            Integer totalFee = result.getTotalFee();

            // 最好是验证一下订单金额与微信回调金额是否一致
            /*if (new BigDecimal(totalFee).compareTo(order != 0) {
                throw new JeecgBootException("金额错误");
            }*/

            // 订单完成时间
            Date date = DateUtils.str2Date(result.getTimeEnd(), DateUtils.yyyymmddhhmmss);

            // 微信支付单号,可以理解为流水号,必须存好,退款时候需要
            String transactionId = result.getTransactionId();


            // 支付时候传入,用于区分具体逻辑
            String attach = result.getAttach();

            switch (EPayScene.valueOf(attach)){

                case PAYMENT_PRODUCT:
                    // 处理订单逻辑,支付单逻辑
                    orderServiceDto.payNotify(outTradeNo,totalFee,date,transactionId);
                    break;
                default:
                    break;
            }
        }else {
            throw new SoaException("微信支付回调失败");
        }

    }

    /**
     * 微信退款回调
     * @param xmlResult
     */
    public void payWxRefundNotify(String xmlResult) throws SoaException {
        WxPayRefundNotifyResult wxPayRefundNotifyResult = WxPayRefundNotifyResult.fromXML(xmlResult, WxPayRefundNotifyResult.class);
        String returnCode = wxPayRefundNotifyResult.getReturnCode();

        if ("SUCCESS".equals(returnCode)) {
            WxPayRefundNotifyResult.ReqInfo reqInfo = wxPayRefundNotifyResult.getReqInfo();

            String transactionId = reqInfo.getTransactionId();
            log.info("退款成功:微信订单号-->{}", transactionId);

            // 根据transactionId查询支付单

            // 订单号
            String outRefundNo = reqInfo.getOutRefundNo();

            // 微信退款单号
            String refundId = reqInfo.getRefundId();

            // 商户退款单号
            String outTradeNo = reqInfo.getOutTradeNo();

            // 订单金额
            Integer totalFee = reqInfo.getTotalFee();

            // 申请退款金额
            Integer refundFee = reqInfo.getRefundFee();

            // 退款金额
            reqInfo.getSettlementRefundFee();

            // 退款成功时间 2017-12-15 09:46:01
            String successTime = reqInfo.getSuccessTime();
            // TODO 处理订单以及支付单逻辑

        }else {
            throw new SoaException("微信支付退款回调失败");
        }

    }

}

6)回调Controller 

@Slf4j
@RestController
@RequestMapping("/weChat")
public class WeChatController {

    @Autowired
    private WeChatServerDto weChatServerDto;

    /**
     * 支付回调
     * @return
     */
    @RequestMapping(name = "/pay/notify",method = RequestMethod.GET)
    public String notify(HttpServletRequest request) {
        try {

            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());

            weChatServerDto.payNotify(xmlResult);

            //处理退款订单
            return WxPayNotifyResponse.success("处理成功!");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }

    /**
     * 退款回调
     */
    @RequestMapping(name = "/pay/wxRefundNotify")
    public String wxRefundNotify(HttpServletRequest request) {
        try {

            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());

            weChatServerDto.payWxRefundNotify(xmlResult);
            //处理退款订单
            return WxPayNotifyResponse.success("处理成功!");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }
}

总结,发起支付的Dto其实不重要,支付类型本来是打算要做其他支付的,但是项目上用不到。。。。。。
作品原创不喜勿喷,如有雷同纯属巧合

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/184015
推荐阅读
相关标签
  

闽ICP备14008679号