美文网首页
微信小程序 支付

微信小程序 支付

作者: _大叔_ | 来源:发表于2020-03-27 17:57 被阅读0次

注意事项

   在做微信小程序支付之前首先要认证小程序,其次申请微信支付功能。申请微信功能成功后,会有开发文档,在里面一定要熟读开发文档,否则会有坑。
   微信小程序支付顺序 -> 后端调统一下单(API) -> 小程序调用 wx.requestPayment()-> 后端回调处理

一、开发准备

  下载微信SDK点这里
   修改 WXPay.java 文件,我们所有的加密方式最好统一是MD5

二、配置appid,mch_id,mch_key

   appid 为小程序的appid
   mch_id 为微信商户平台的id
   mch_key 为微信商户 API密钥

   写一个类继承 WXPayConfig 然后实现他的方法,WXPayConfig 的所有抽象方法记得改成 public。

   完整代码如下:

package com.hyq.hyqcloud.service.user.impl;

import com.hyq.hyqcloud.pay.IWXPayDomain;
import com.hyq.hyqcloud.pay.WXPayConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.InputStream;


/**
 * @Author big uncle
 * @Date 2020/3/26 16:00
 * @module HYQ_APP
 **/
@Component
public class PayConfig extends WXPayConfig {
    /**
     * 你的appid"
    **/
    @Value("${hyq.tripartite.wechat.applets.appId}")
    private String appId;
    /**
     * 你的商户id
    **/
    @Value("${hyq.tripartite.wechat.applets.mch_id}")
    private String mchID;
    /**
     * 你的商户api安全key,在商户平台api安全目录下可设置
    **/
    @Value("${hyq.tripartite.wechat.applets.mch_key}")
    private String key;


    private byte[] certData;

    public PayConfig() throws Exception {
//        String certPath = "classpath:apiclient_cert.p12";
//        File file = new File(certPath);
//        InputStream certStream = new FileInputStream(file);
//        this.certData = new byte[(int) file.length()];
//        certStream.read(this.certData);
//        certStream.close();
    }
    /**
     * 获取 App ID
     * @return App ID
     */
    @Override
    public String getAppID(){
        return appId;
    }


    /**
     * 获取 Mch ID
     *
     * @return Mch ID
     */
    @Override
    public String getMchID(){
        return mchID;
    }


    /**
     * 获取 API 密钥
     * @return API密钥
     */
    @Override
    public String getKey(){
        return key;
    }


    /**
     * 获取商户证书内容
     * @return 商户证书内容
     */
    @Override
    public InputStream getCertStream(){
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    /**
     * 获取WXPayDomain, 用于多域名容灾自动切换
     * @return
     */
    @Override
    public IWXPayDomain getWXPayDomain() {
        return new IWXPayDomain() {
            @Override
            public void report(String domain, long elapsedTimeMillis, Exception ex) {
            }

            @Override
            public DomainInfo getDomain(WXPayConfig config) {
                return new DomainInfo("api.mch.weixin.qq.com", false);
            }
        };
    }
}

   支付代码如下:

    @Autowired
    private PayConfig payConfig;

    @Override
    public ResponseData pay(RequestData<String, AppletsUserVo> requestData) {
        // 请求数据
        AppletsUserVo appletsUserVo = requestData.getUser();
        // 请求数据库
        AppletsUser appletsUser = appletsUserMapper.selectById(appletsUserVo.getId());
        try {
            return ResponseData.successResponse(toPay("旅游度假村","1",appletsUser.getOpenId()));
        }catch(Exception e){
            e.printStackTrace();
            return ResponseData.failureResponse(1,"支付失败");
        }
    }

    /**
     * projectDesc 商品描述 也可是商品名称
     * price 价格
     * openId 这个我就不说了
    **/
    private Map<String,String> toPay(String projectDesc,String price,String openId) throws Exception {
        Map<String,String> resultMap = new HashMap<>(15);
        // 得到套餐信息
        WXPay wxpay = new WXPay(payConfig);
        //生成的随机字符串
        String nonce_str = WXPayUtil.generateNonceStr();
        //获取本机的ip地址
        InetAddress addr = null;
        try {
            addr = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        String spbill_create_ip = addr.getHostAddress();
        String out_trade_no= WXPayUtil.generateNonceStr();
        //统一下单接口参数
        HashMap<String, String> data = new HashMap<String, String>(20);
        // 商品描述
        data.put("body", projectDesc);
        data.put("device_info", "WEB");
        // 商户订单号
        data.put("out_trade_no",out_trade_no);
        // 价格
        data.put("total_fee", price);
        // 终端ip
        data.put("spbill_create_ip", spbill_create_ip);
        // 回调地址
        data.put("notify_url", "https://nuclean.cn/api/guardClient/appletsUser/payCallBack");
        // 交易类型 小程序 app h5 不同的平台值不一样
        data.put("trade_type","JSAPI");
        data.put("openid", openId);
        Map<String, String> rMap = wxpay.unifiedOrder(data);
        System.out.println("统一下单接口返回: " + rMap);
        String return_code = (String) rMap.get("return_code");
        String result_code = (String) rMap.get("result_code");
        String nonceStr = WXPayUtil.generateNonceStr();
        resultMap.put("nonceStr", nonceStr);
        Long timeStamp = System.currentTimeMillis() / 1000;
        if ("SUCCESS".equals(return_code) && return_code.equals(result_code)) {
            String prepayid = rMap.get("prepay_id");
            resultMap.put("package", "prepay_id="+prepayid);
            resultMap.put("signType", "MD5");
            //这边要将返回的时间戳转化成字符串,不然小程序端调用wx.requestPayment方法会报签名错误
            resultMap.put("timeStamp", timeStamp + "");
            //再次签名,这个签名用于小程序端调用wx.requesetPayment方法
            resultMap.put("appId",payConfig.getAppID());
            resultMap.put("paySign", WXPayUtil.generateSignature(resultMap, payConfig.getKey()));
        }
        return resultMap;
    }

   回调代码如下:

    @RequestMapping("/payCallBack")
    public ResponseData payCallBack(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String str = IoUtil.read(request.getInputStream(),"utf-8");
        log.debug(str);
        Map<String,String> map = WXPayUtil.xmlToMap(str);
        String state = map.get("return_code");
        String resultSign = map.get("sign");
        // 制空
        if(!"SUCCESS".equals(state)){
            String sign = WXPayUtil.generateSignature(map,"商户api密钥");
            if(sign.equals(resultSign)){
                // redis 上锁 并拒绝重复请求 加失效时间
                // 通过id去数据库查询
                // 比对 appid 商户id
                // 比对 openid 确定同一个人 比对 金额
            }
        }
        log.debug(JSONObject.toJSONString(map));
        return ResponseData.successResponse();
    }

log.debug 方法是 lombok的
IoUtil 是 hutool的 大家可以百度学习

  小程序代码就很简单了,后端支付传回来的数据和 wx.requestPayment()参数一一对应就行。

相关文章

网友评论

      本文标题:微信小程序 支付

      本文链接:https://www.haomeiwen.com/subject/ghkruhtx.html