微信点餐之微信支付(7)

微信支付:(只有企业资质的才可以申请微信支付)
https://pay.weixin.qq.com/
微信支付流程文档:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_4

文档说明

https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

依赖说明

在pom文件中要加入第三方sdk依赖

<!--微信支付依赖-->
<dependency>
	<groupId>cn.springboot</groupId>
	<artifactId>best-pay-sdk</artifactId>
	<version>1.1.0</version>
</dependency>

功能实现

微信支付

1:在配置文件appliaction.yml中追加配置信息

wechat:
  #商户id
  mchId: 1xxxxxx469312
  #商户秘钥
  mchKey: C5245xxxxx64D494B0735025
  #商户证书
  keyPath: D:/python/h5.p12
  #微信支付异步通知调用的方法
  notifyUrl: http://applenst.natapp4.cc/sell/pay/notify

2:在WechatAccountConfig.java配置文件中追加属性配置
com\imooc\config\WechatAccountConfig.java

/*商户号*/
private String mchId;

/*商户秘钥*/
private String mchKey;

/*商户证书路径*/
private String keyPath;

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

3:创建微信支付配置类
com\imooc\config\WechatPayConfig.java

package com.imooc.config;

import com.lly835.bestpay.config.WxPayH5Config;
import com.lly835.bestpay.service.impl.BestPayServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 * @author: menghaibin
 * @create: 2020-02-23 13:56
 * @description: 微信支付配置
 **/
Component
public class WechatPayConfig {

    @Autowired
    private WechatAccountConfig accountConfig;

    @Bean
    public BestPayServiceImpl bestPayService(){

        WxPayH5Config wxPayH5Config = new WxPayH5Config();

        wxPayH5Config.setAppId(accountConfig.getMpAppId());
        wxPayH5Config.setAppSecret(accountConfig.getMpAppSecret());
        wxPayH5Config.setMchId(accountConfig.getMchId());
        wxPayH5Config.setMchKey(accountConfig.getMchKey());
        wxPayH5Config.setKeyPath(accountConfig.getKeyPath());
        wxPayH5Config.setNotifyUrl(accountConfig.getNotifyUrl());

        BestPayServiceImpl bestPayService = new BestPayServiceImpl();
        bestPayService.setWxPayH5Config(wxPayH5Config);

        return bestPayService;
    }
}

4:创建微信支付service接口(包括支付和退款)
com\imooc\service\PayService.java

package com.imooc.service;

import com.imooc.dto.OrderDTO;
import com.lly835.bestpay.model.PayResponse;
import com.lly835.bestpay.model.RefundResponse;

public interface PayService {

    /*微信支付*/
    public PayResponse create(OrderDTO orderDTO);

    /*支付成功后的回调方法*/
    public PayResponse notify(String notifyData);

    /*微信退款*/
    public RefundResponse refund(OrderDTO orderDTO);
}

5:创建微信支付service接口实现类
com\imooc\service\imp\PayServiceImp.java

package com.imooc.service.imp;

import com.imooc.dto.OrderDTO;
import com.imooc.exception.SellException;
import com.imooc.service.OrderService;
import com.imooc.service.PayService;
import com.imooc.utils.JsonUtil;
import com.imooc.utils.MathUtil;
import com.imooc.vo.enums.ResultEnum;
import com.lly835.bestpay.enums.BestPayTypeEnum;
import com.lly835.bestpay.model.PayRequest;
import com.lly835.bestpay.model.PayResponse;
import com.lly835.bestpay.model.RefundRequest;
import com.lly835.bestpay.model.RefundResponse;
import com.lly835.bestpay.service.impl.BestPayServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author: menghaibin
 * @create: 2020-02-23 13:15
 * @description: 微信支付
 **/
Service
@Slf4j
public class PayServiceImp implements PayService{

    @Autowired
    private BestPayServiceImpl bestPayService;
    @Autowired
    private OrderService orderService;

    private static final String ORDER_NAME = "微信点餐订单";

    /*微信支付*/
    @Override
    public PayResponse create(OrderDTO orderDTO) {
        PayRequest payRequest = new PayRequest();

        payRequest.setOpenid(orderDTO.getBuyerOpenid());
        payRequest.setOrderId(orderDTO.getOrderId());
        payRequest.setOrderAmount(orderDTO.getOrderAmount().doubleValue());
        payRequest.setOrderName(ORDER_NAME);
        payRequest.setPayTypeEnum(BestPayTypeEnum.WXPAY_H5);//公众号支付
        log.info("微信支付发起payRequest={}", JsonUtil.toJson(payRequest));

        PayResponse payResponse = bestPayService.pay(payRequest);
        log.info("微信支付发起payResponse={}",JsonUtil.toJson(payResponse));
        return payResponse;
    }

	/*微信支付异步通知*/
    @Override
    public PayResponse notify(String notifyData) {
        
        PayResponse payResponse = bestPayService.asyncNotify(notifyData);
        log.info("微信支付异步通知notify={}",JsonUtil.toJson(payResponse));
        //查询订单
        OrderDTO orderDTO = orderService.findOne(payResponse.getOrderId());
        if(orderDTO == null){
            log.error("微信支付异步通知,订单不存在");
            throw new SellException(ResultEnum.ORDER_NOT_EXIST);
        }
        //判断金额是否一致(由于字段类型不一致,判断精度即可)
        if(!MathUtil.equals(payResponse.getOrderAmount(),orderDTO.getOrderAmount().doubleValue())){
            log.error("微信支付异步通知,支付金额错误不一致,微信金额={},系统金额={}",payResponse.getOrderAmount(),orderDTO.getOrderAmount());
            throw new SellException(ResultEnum.WXPAY_ERROR);
        }
        //修改订单状态
        orderService.paid(orderDTO);
        return payResponse;
    }
}

6:创建微信支付的controller
com\imooc\controller\PayController.java

package com.imooc.controller;

import com.imooc.dto.OrderDTO;
import com.imooc.exception.SellException;
import com.imooc.service.OrderService;
import com.imooc.service.PayService;
import com.imooc.vo.enums.ResultEnum;
import com.lly835.bestpay.model.PayResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.Map;

/**
 * @author: menghaibin
 * @create: 2020-02-23 13:08
 * @description: 微信支付
 **/
@Controller
@Slf4j
@RequestMapping("/pay")
public class PayController {

    @Autowired
    private OrderService orderService;
    @Autowired
    private PayService payService;

	/*微信支付*/
    @GetMapping("/create")
    public ModelAndView create(@RequestParam("orderId") String orderId,
                               @RequestParam("returnUrl") String returnUrl,
                               Map<String,Object> map){

        //查询订单
        OrderDTO orderDTO = orderService.findOne(orderId);
        if(orderDTO == null){
            log.error("订单不存在");
            throw new SellException(ResultEnum.ORDER_NOT_EXIST);
        }

        //发起支付
        PayResponse payResponse = payService.create(orderDTO);
        map.put("payResponse",payResponse);
        map.put("returnUrl",returnUrl);
        //支付成功后会跳转到pay/create页面
        return new ModelAndView("pay/create",map);
    }

	/*支付成功后访问的方法*/
    @PostMapping("/notify")
    public ModelAndView wxnotify(@RequestBody String notifyData){
        //修改订单
        payService.notify(notifyData);

        //把处理结果返回给微信【规则定义的】
        return new ModelAndView("pay/success");
    }
}

7:创建微信支付时弹出的支付界面【需要把界面所在的路径加入微信支付白名单中http://域名/pay

此时要在pom文件中加入freemarker依赖

<!--freemarker依赖-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

创建支付页面和成功页面
resources\templates\pay\create.ftl【/pay/create执行成功后访问】

<script>
    function onBridgeReady(){
        WeixinJSBridge.invoke(
                'getBrandWCPayRequest', {
                    "appId":"${payResponse.appId}",     //公众号名称,由商户传入
                    "timeStamp":"${payResponse.timeStamp}", //时间戳
                    "nonceStr":"${payResponse.nonceStr}", //随机串
                    "package":"${payResponse.packAge}",
                    "signType":"MD5",//微信签名方式:
                    "paySign":"${payResponse.paySign}" //微信签名
                },
                function(res){
                location.href="${returnUrl}" //支付成功后的回调方法
                }
        );
    }
    if (typeof WeixinJSBridge == "undefined"){
        if( document.addEventListener ){
            document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
        }else if (document.attachEvent){
            document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
            document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
        }
    }else{
        onBridgeReady();
    }
</script>

resources\templates\pay\success.ftl【/pay/notify执行成功后访问】

<xml>
    <return_code><![CDATA[SUCCESS]]></return_code>
    <return_msg><![CDATA[OK]]></return_msg>
</xml>

7:项目构建及联调
1>配置虚拟机支付访问路径:

/opt/code/sell_fe_buyer/config/index.js

进入/opt/code/sell_fe_buyer目录执行重新构建命令

npm run build

拷贝文件使其生效

cp -r dist/* /opt/data/wwwrot/sell/

这时候就可以在手机上访问sell.com 下订单了!

微信退款

需要证书认证,详见链接说明:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4

在PayServiceImp类中实现refund方法:

/*微信退款*/
@Override
public RefundResponse refund(OrderDTO orderDTO) {
    RefundRequest refundRequest = new RefundRequest();
    refundRequest.setOrderId(orderDTO.getOrderId());
    refundRequest.setOrderAmount(orderDTO.getOrderAmount().doubleValue());
    refundRequest.setPayTypeEnum(BestPayTypeEnum.WXPAY_H5);
    log.info("微信退款 RefundRequest={}",JsonUtil.toJson(refundRequest));

    /*退款单号就是订单号 封装的*/
    RefundResponse refundResponse = bestPayService.refund(refundRequest);
    log.info("微信退款 RefundResponse={}",JsonUtil.toJson(refundResponse));
    return refundResponse;
}

被OrderServiceImp中的cancel取消订单方法所调用(取消订单时要做退款)

//如果已支付 需要退款
if(orderDTO.getPayStatus().equals(PayStatusEnum.SUCCESS.getCode())){
    //TODO
    /*调用微信退款的方法*/
    payService.refund(orderDTO);
}
posted @ 2020-04-01 15:02  努力的校长  阅读(525)  评论(0编辑  收藏  举报