微信如何提现(java部分代码)

分享给好友,领取红包,红包满100可以提取到微信零钱,有一段时间天天被“PDD”好友助力轰炸,但是提现这个玩意到底怎么玩的呢,一直也没时间也没场景去搞一下。这几天刚好项目需要提现的需求,于是乎在这里整理一下。

微信提现在微信开发文档中成为企业付款,更多详细的介绍及参数配置,可参考微信开发文档
https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1

首先创建一个提现日志表,用来追踪提现记录

@Data
public class WithdrawalLog{

    private Long id;
    /**
     * 商户订单号
     */
    private String cashSn;

    /**
     * 用户id
     */
    private String userId;

    /**
     * openId
     */
    private String openId;

    /**
     * 提现金额
     */
    private BigDecimal amount;

    /**
     * 提现结果
     */
    private Boolean status;

    /**
     * 失败原因
     */
    private String message;
    
    private Date createTime;

}

准备好微信提现需要的必备参数,比如什么appid,商户号,用户openId等等。准备好之后废话不多说直接提吧。

    public BaseResponse<WithdrawalLog> withdrawalCash(String openId,String userId, BigDecimal amount) {
        try {
        	//项目保存的插件对象,不用在意,只要有mchId即可
            PluginVo pluginConfig = wxpayPaymentPlugin.getPluginConfig();
            String mch_id = pluginConfig.getAttribute("mchID");
			//用来生成32位随机字符
            SnowflakeIdWorker idWorker = SnowflakeIdWorker.getFlowIdWorkerInstance();
            String nonceStr = RandomStringUtils.randomAlphanumeric(32);
            String sn = String.valueOf(idWorker.nextId());
            Map<String, Object> parameterMap = new HashMap<>();
            parameterMap.put("mch_appid", pluginConfig.getAttribute("appID"));//商户账号appid
            parameterMap.put("mchid", mch_id);//商户号
            parameterMap.put("nonce_str", nonceStr);//随机字符串
            parameterMap.put("partner_trade_no", sn);//商户订单号
            parameterMap.put("openid", openId);//用户openid
            parameterMap.put("check_name", "NO_CHECK");//校验用户姓名选项
            parameterMap.put("amount", amount.multiply(new BigDecimal("100")).intValue());//金额
            parameterMap.put("desc", "佣金");//企业付款备注
            parameterMap.put("sign", generateSign(parameterMap));//签名

			//map转为xml工具类
            String postDataXML = XMLUtils.toXML(parameterMap);
            log.info("提现参数准备XML:{}", postDataXML);
            //调用微信提现请求
            String result = sendPost(postDataXML, mch_id);
            //微信返回xml类型的结果转为map
            Map responseMap = XMLUtils.fromXML(result);
            //保存提现日志
            WithdrawalLog withdrawalLog = new WithdrawalLog();
            withdrawalLog.setAmount(amount);
            withdrawalLog.setCashSn(sn);
            withdrawalLog.setOpenId(openId);
            withdrawalLog.setUserId(userId);
            if (FAIL.equals(responseMap.get(RETURN_CODE))) {
                withdrawalLog.setStatus(false);
                withdrawalLog.setMessage(responseMap.get(RETURN_MSG).toString());
                saveWithdrawalLog(withdrawalLog);
                return BaseResponse.successResponse("提现失败," + responseMap.get(RETURN_MSG));
            } else {
                if (SUCCESS.equals(responseMap.get(RESULT_CODE))) {

                    withdrawalLog.setStatus(true);
                    saveWithdrawalLog(withdrawalLog);
                    return BaseResponse.successResponse("微信退款完成");
                } else {
                    //出现业务错误
                    String errorCodeDes = String.valueOf(responseMap.get(ERR_CODE_DES));
                    withdrawalLog.setStatus(false);
                    withdrawalLog.setMessage(errorCodeDes);
                    saveWithdrawalLog(withdrawalLog);
                    log.error("err_code_des:" + errorCodeDes);
                    return BaseResponse.exceptionResponse("退款失败" + errorCodeDes);
                }
            }
        } catch (Exception e) {
            return BaseResponse.exceptionResponse("提现失败");
        }
    }
    //签名的处理,下边会提供笔者生成签名的工具类,可作为参考
    private String generateSign(Map<String, ?> parameterMap) {
        return SignatureUtils.getSign(parameterMap, "key", "sign");
    }
    //请求微信提现URL
    private String sendPost(String postDataXML, String mch_id) throws Exception {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse httpResponse = null;
        try {
            //获取微信退款证书
            KeyStore keyStore = getCertificate(mch_id);
            SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
            SSLConnectionSocketFactory sslf = new SSLConnectionSocketFactory(sslContext);
            httpClient = HttpClients.custom().setSSLSocketFactory(sslf).build();
            HttpPost httpPost = new HttpPost("\"https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers\"");//提现接口

            StringEntity reqEntity = new StringEntity(postDataXML);
            // 设置类型
            reqEntity.setContentType("application/x-www-form-urlencoded");
            httpPost.setEntity(reqEntity);
            String result = null;
            httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            if (Validator.isNotNullOrEmpty(httpEntity)) {
                result = EntityUtils.toString(httpEntity, "UTF-8");
                EntityUtils.consume(httpEntity);
            }
            return result;
        } finally {//关流
            httpClient.close();
            httpResponse.close();
        }
    }
    private KeyStore getCertificate(String mch_id) {
        //try-with-resources 关流
        try (FileInputStream inputStream = new FileInputStream(new File("D:\\wx\\1248201701_20190812_cert\\apiclient_cert.p12"))) {
            KeyStore keyStore = KeyStore.getInstance(PKCS12);
            keyStore.load(inputStream, mch_id.toCharArray());
            return keyStore;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

简单提醒:代码中pluginConfig为项目中对微信插件的配置,还有生成的32位随机字符串也是项目中的工具类,微信提现金额单位是分

关于签名的问题,按照微信文档提出的要求,拼接加密即可
微信签名,下边提供一下我用到的签名工具类

关于证书的问题:
在这里插入图片描述
去微信指定的地址下载证书,测试的时候放到本地即可,微信的提现和退款关于证书的操作是一样的,获取证书可能会碰到一写问题,可参考一下我之前写的ERROR: api.mch.weixin.qq.com:443 failed to respond [微信退款]

签名

public class SignatureUtils
{
  private static final Logger logger = LoggerFactory.getLogger(SignatureUtils.class);
  
  public static String getSign(Map<String, ?> map, String signKey, String... ignoreKeys)
  {
    StringBuilder signContent = new StringBuilder();
    if (null != map)
    {
      List<String> keys = new ArrayList(map.keySet());
      Collections.sort(keys, String.CASE_INSENSITIVE_ORDER);
      for (String key : keys) {
        if ((map.get(key) != null) && (!ArrayUtils.contains(ignoreKeys, key)))
        {
          String value;
          if ((map.get(key) instanceof String[]))
          {
            StringBuilder sb = new StringBuilder();
            for (String v : (String[])map.get(key))
            {
              if (sb.length() > 0) {
                sb.append(",");
              }
              sb.append(v);
            }
            value = sb.toString();
          }
          else
          {
            value = map.get(key).toString();
          }
          if (value.length() > 0)
          {
            signContent.append(key);
            signContent.append("=");
            signContent.append(value);
            signContent.append("&");
          }
        }
      }
    }
    signContent.append("key=");
    signContent.append(signKey);
    logger.debug("Sign Before MD5:" + signContent.toString());
    String result = DigestUtils.md5Hex(signContent.toString()).toUpperCase();
    return result;
  }
}

最后,微信提现需要登录微信支付商户平台-产品中心,开通企业付款,要不然代码写的再华丽,终是一场空。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值