其他分享
首页 > 其他分享> > 手把手教你如何采用服务商模式实现微信支付

手把手教你如何采用服务商模式实现微信支付

作者:互联网

背景

小程序盛行时代,一般的企业中都都会包含多个小程序,而大部分的小程序通常都需要实现支付功能,本文将针对服务商模式进行微信支付进行详细讲解。

微信支付的模式

图片.png

一般企业选用是服务商或者为渠道商模式,但是成为渠道商需要相关流量支撑才能申请,本文以服务商模式进行讲解。

前期准备

注册服务商

服务商申请需要通过已做过公司认证的公众号,登录公司的微信服务号,在【微信支付】>【服务商申请】,直接跟着官方引导一步步操作即可,具体申请流程如下:

图片.png

说明:所以企业需要申请公共号,才能申请注册服务商。

服务商入驻

通过服务商来开发的系统来帮助商户微信支付,首先需要完成商户号在服务商号中的入驻过程。服务商注册成功后,进入微信支付平台,登录服务商,进行商户入驻。一般商户入驻有两种,具体如下:

页面入驻

图片.png

入驻可以看作是商户生成商户号的同时与服务商形成绑定关系。具体可以参考微信公众号中按流程指引一步步操作就行。

图片.png

说明:商户入驻完成后,此商户才能用于微信支付。

申请证书

商户号入驻成功后,需要申请API证书。

图片.png

说明:按照官方文档申请证书,设置密钥,设置好密钥后一定要在安全的前提下记住,之后只能重置不能查看。

重要参数说明

子商户支付流程

以下是子商户APP中调用支付的交互时序图

图片.png

流程说明:

实现方案

服务商模式的微信支付的具体实现方案,本文采用的是Spring Boot集成weixin-java-pay来实现微信支付。

实现步骤

jar包引入

<dependency>
     <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-pay</artifactId>
    <version>4.1.0</version>
</dependency>
复制代码

支付配置

# 微信支付配置
wx:
  pay:
    #服务商id
    mchId: 12
    #证书
    keyPath: apiclient_cert.p12
    #服务商appid
    appId: wxe12233
    #支付回调通知地址
    notifyUrl: https://localhost:8080/pay/resWxPay
    #服务商key的密钥
    mchKey: 123444
复制代码

相关配置类

@Component
@ConfigurationProperties(prefix = "wx.pay")
public class WxPayProperties {
  /**
   *  小程序appid
   */
  private String appId;

  /**
   * 微信支付商户号
   */
  private String mchId;

  /**
   * 微信支付商户密钥
   */
  private String mchKey;

  /**
   * 服务商模式下的子商户公众账号ID
   */
  private String subAppId;

  /**
   * 服务商模式下的子商户号
   */
  private String subMchId;

  /**
   * apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定
   */
  private String keyPath;
  
  /**
   * 支付回调
   */
  private String notifyUrl;
  
  //省略get、set方法
  }
复制代码

说明:读取微信支付的配置信息

/**
 * 微信支付配置类
 */
@Configuration
public class CustWxPayConfig 
{
    @Autowired
	private WxPayProperties properties;

	@Bean
	@ConditionalOnMissingBean
	public WxPayService wxService() {
		WxPayConfig payConfig = new WxPayConfig();
		payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
		payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
		payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));
		payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));
		payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
		payConfig.setNotifyUrl(StringUtils.trimToNull(this.properties.getNotifyUrl()));

		//设置微信支付参数
		WxPayService wxPayService = new WxPayServiceImpl();
		wxPayService.setConfig(payConfig);
		return wxPayService;
	}
}

复制代码

说明:将微信支付的相关参数设置到wxjava中的cofig中。

业务实现类

@Service
@Transactional(rollbackFor =Exception.class)
public class CustWxPayServiceImpl implements CustWxPayService
{
    private Logger logger = LoggerFactory.getLogger(CustWxPayService.class);
    
    @Autowired
    private WxPayService wxService; 
        
    public void createWxPayOrder(WxPayObject payObject)
    {
       logger.info("Create wx pay order.");
    
        //并发控制
        
        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setTradeType(payObject.getTradeType()); 
        int payMoney = payObject.getPayMoney()
                .multiply(new BigDecimal(100)).intValue();
        // totalFee单位为(分)
        request.setTotalFee(payMoney);
        //第三方订单号
        request.setOutTradeNo(payObject.getOrderNo());
        //用户OpenID(支付小程序)
        request.setSubOpenid(payObject.getSubOpenid());
        //支付小程序APPID
        request.setSubAppId(payObject.getSubAppId()); 
        request.setNonceStr(getRandomString(32));
        request.setBody(payObject.getBody());         
        request.setFeeType(payObject.getFeeType());         
        HttpServletRequest httpRequest = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
                       
        //IP地址
        request.setSpbillCreateIp(IpUtil.getIpAddr(httpRequest));
        
        //配置回调地址
        request.setNotifyUrl(wxService.getConfig().getNotifyUrl());
        
        //收款子商户
        String subMchId = wxService.getConfig().getSubAppId();
        
        request.setSubMchId(subMchId);
        
        //DeviceID
        request.setDeviceInfo(payObject.getDeviceInfo());
        
        //支付类型:
        request.setTradeType(payObject.getTradeType());
        
        //创建建订单
        WxPayMpOrderResult wxPayMpOrderResult =null;
        try
        {
            wxPayMpOrderResult = wxService.createOrder(request);
            if (wxPayMpOrderResult == null)
            {
                logger.info("Create Wx Order Success. Result is null.");
            }
            else
            {
                logger.info("Create Wx Order Success. Result:{}",
                        JSON.toJSONString(wxPayMpOrderResult));
            }
        }
        catch (WxPayException e)
        {
           logger.error("createWxPayOrder error",e);
           throw new SysException("create wx order error",e);     
        }
    }

    @Override
    public void resWxPay(String xmlData)
    {
        logger.info("Wx Pay Response, param[{}]", xmlData);
        WxPayOrderNotifyResult result =null;
        
        try
        {
            result = wxService
                    .parseOrderNotifyResult(xmlData);
            
            //支付失败
            if ("FAIL".equalsIgnoreCase(result.getResultCode()) || "FAIL".equalsIgnoreCase(result.getReturnCode()))
            {
              //记录支付失败错误日志
                
              throw new SysException(result.getErrCodeDes());              
            }
            
            //获取订单号
            String outTradeNo = result.getOutTradeNo();
            if (StringUtils.contains(outTradeNo, "_"))
            {
                outTradeNo = outTradeNo.substring(0, outTradeNo.indexOf("_"));
            }
            
            //执行具体业务逻辑
            
            //记录流水
            
            //更新订单状态            
            
        }
        catch (WxPayException e)
        {
            throw new SysException("wx pay error",e);     
        }
    }
    @Override
    public WxPayOrderQueryResult queryOrder(String outTradeNo)
    {
        WxPayOrderQueryResult wxPayOrderQueryResult  =null;
        try
        {
            wxPayOrderQueryResult= wxService.queryOrder(null, outTradeNo);
        }
        catch (WxPayException e)
        {
            throw new SysException("query wx order error",e);     
        }
        return wxPayOrderQueryResult;
    }
    
    public static String getRandomString(int length) 
    {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
    
}
复制代码

说明:实现微信创建订单、支付回调、查询订单接口。

测试类

@RestController
@RequestMapping("/pay/wxpay/")
public class WxPayController
{
    private Logger logger =LoggerFactory.getLogger(WxPayController.class);
    
    @Autowired
    private CustWxPayService custWxPayService;
    
    /**
     * 
     * @param subAppId 小程序AppId
     * @param subOpenid 用户在小程序的openid
     * @param payMoney 支付金额
     * @param orderNo 第三方订单号
     * @return
     */
    @PostMapping("/reqWxPay")
    public Result reqWxPay(@RequestBody WxPayObject wxPayObject)
    {
        //支付参数验证
        logger.info("Req Wx Pay,param:{}",JSON.toJSONString(wxPayObject));

        Result result =new Result();
        
        try
        {
            //创建订单
            custWxPayService.createWxPayOrder(wxPayObject);
        }
        catch(Exception e)
        {
            logger.error("Req Wx Pay Error.", e);
            return Result.error("Req Wx Pay error"+e);
        }
        return Result.success(result);
    }
    
    /**
     * 异步回调
     * @param xmlData
     * @return
     */
    @PostMapping("/resWxPay")
    public String resWxPay(@RequestBody String xmlData)
    {
        logger.info("Wx Pay Response, Data:[{}]", xmlData);
        
        try
        {
            custWxPayService.resWxPay(xmlData);
        }
        catch(Exception e)
        {
           logger.error("Wx Pay Response Process Error.", e);
           return WxPayNotifyResponse.fail("订单支付失败.");
        }
        
        logger.info("Wx Pay Response Process Success.");
        return WxPayNotifyResponse.success("付款成功");
    }
    
    @GetMapping("/queryOrder")
    public Result queryOrder(String outTradeNo)
    {
        WxPayOrderQueryResult wxPayOrderQueryResult = custWxPayService.queryOrder(outTradeNo);
        logger.info(wxPayOrderQueryResult.toString());
        return Result.success(wxPayOrderQueryResult);
    }
}
复制代码

相关测试

创建支付订单

请求参数

图片.png

说明:

响应结果

图片.png

说明:returnCode为success,则说明创建微信支付订单成功。

查询订单

订单创建成功后,需要查询订单状态。

请求参数

图片.png

响应结果

图片.png

微信异步回调

关于微信支付回调,需要绑定外网域名,在内网需要测试的话,需要进行内网穿透,微信异步回调可能由于网络原因出现延迟,所以在业务上需要提供主动查询和异步回调结合的方式,关于具体实现将在后续的文章中进行讲解。

总结

本文服务商模式实现微信支付进行详细的讲解,实现过程还是比较复杂,订单支付中涉及到重复提交、幂等性验证、同步+异步的轮询处理等问题将在后续的文章中进行讲解。


作者:剑圣无痕
链接:https://juejin.cn/post/7134982531786473480
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标签:手把手,String,商户,微信,服务商,request,支付
来源: https://www.cnblogs.com/jiangshengwuhen/p/16618926.html