首页 > 编程 > Java > 正文

java实现微信企业付款到个人功能

2019-11-26 09:38:16
字体:
来源:转载
供稿:网友

微信官方提供了微信企业账户付款到微信个人零钱接口,提供企业向用户付款的功能,支持企业通过API接口付款,或通过微信支付商户平台网页功能操作付款。该接口并不是直接所有的商户都拥有,企业要开启必须满足以下两个条件:

 1、商户号已入驻90日
 2、商户号有30天连续正常交易

满足以上条件就可登录微信支付商户平台-产品中心,开通企业付款。
调用的链接地址:接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
微信官方接口文档提供的调用微信企业付款的参数:

参数中最重要是获取用户openid和调用接口ip,获取openid可以通过公众号获取,app端可以直接获取。具体的代码实现如下:

封装请求微信企业付款的实体类Transfers:

public class Transfers implements Serializable{  private static final long serialVersionUID = 1L;  /** 商户账号appid*/  public String mch_appid;  /** 微信支付商户号*/  public String mchid;  /** 随机串*/  public String nonce_str;  /** 签名*/  public String sign;  /** 商户订单号*/  public String partner_trade_no;  /** 用户id*/  public String openid;  /** 是否校验用户姓名 NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名*/  public String check_name;  /** 金额 单位:分*/  public Integer amount;  /** 企业付款描述信息*/  public String desc;  /** ip地址*/  public String spbill_create_ip;  public String getMch_appid() {    return mch_appid;  }  public void setMch_appid(String mch_appid) {    this.mch_appid = mch_appid;  }  public String getMchid() {    return mchid;  }  public void setMchid(String mchid) {    this.mchid = mchid;  }  public String getNonce_str() {    return nonce_str;  }  public void setNonce_str(String nonce_str) {    this.nonce_str = nonce_str;  }  public String getSign() {    return sign;  }  public void setSign(String sign) {    this.sign = sign;  }  public String getPartner_trade_no() {    return partner_trade_no;  }  public void setPartner_trade_no(String partner_trade_no) {    this.partner_trade_no = partner_trade_no;  }  public String getOpenid() {    return openid;  }  public void setOpenid(String openid) {    this.openid = openid;  }  public String getCheck_name() {    return check_name;  }  public void setCheck_name(String check_name) {    this.check_name = check_name;  }  public Integer getAmount() {    return amount;  }  public void setAmount(Integer amount) {    this.amount = amount;  }  public String getDesc() {    return desc;  }  public void setDesc(String desc) {    this.desc = desc;  }  public String getSpbill_create_ip() {    return spbill_create_ip;  }  public void setSpbill_create_ip(String spbill_create_ip) {    this.spbill_create_ip = spbill_create_ip;  }}

接口部分代码:

private Transfers transfers = new Transfers();// 构造签名的map  private SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();// 微信的参数  private WeixinConfigUtils config = new WeixinConfigUtils(); /**  * 微信提现(企业付款)  */  @Action("weixinWithdraw")  public String weixinWithdraw(){    String openId = request.getParameter("openid");    String ip = request.getParameter("ip");    String money = request.getParameter("money");    String doctorId = request.getParameter("doctorId");    if (StringUtils.isNotBlank(money) && StringUtils.isNotBlank(ip) && StringUtils.isNotBlank(openId) && StringUtils.isNotBlank(doctorId)) {    // 参数组    String appid = config.appid;    String mch_id = config.mch_id;    String nonce_str = RandCharsUtils.getRandomString(16);    //是否校验用户姓名 NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名    String checkName ="NO_CHECK";    //等待确认转账金额,ip,openid的来源    Integer amount = Integer.valueOf(money);    String spbill_create_ip = ip;    String partner_trade_no = UuIdUtils.getUUID();    //描述    String desc = "健康由我医师助手提现"+amount/100+"元";    // 参数:开始生成第一次签名    parameters.put("appid", appid);    parameters.put("mch_id", mch_id);    parameters.put("partner_trade_no", partner_trade_no);    parameters.put("nonce_str", nonce_str);    parameters.put("openId", openId);    parameters.put("checkName", checkName);    parameters.put("amount", amount);    parameters.put("spbill_create_ip", spbill_create_ip);    parameters.put("desc", desc);    String sign = WXSignUtils.createSign("UTF-8", parameters);    transfers.setAmount(amount);    transfers.setCheck_name(checkName);    transfers.setDesc(desc);    transfers.setMch_appid(appid);    transfers.setMchid(mch_id);    transfers.setNonce_str(nonce_str);    transfers.setOpenid(openId);    transfers.setPartner_trade_no(partner_trade_no);    transfers.setSign(sign);    transfers.setSpbill_create_ip(spbill_create_ip);    String xmlInfo = HttpXmlUtils.transferXml(transfers);    try {      CloseableHttpResponse response = HttpUtil.Post(weixinConstant.WITHDRAW_URL, xmlInfo, true);      String transfersXml = EntityUtils.toString(response.getEntity(), "utf-8");      Map<String, String> transferMap = HttpXmlUtils.parseRefundXml(transfersXml);      if (transferMap.size()>0) {        if (transferMap.get("result_code").equals("SUCCESS") && transferMap.get("return_code").equals("SUCCESS")) {          //成功需要进行的逻辑操作,          }        }      System.out.println("成功");    } catch (Exception e) {      log.error(e.getMessage());      throw new BasicRuntimeException(this, "企业付款异常" + e.getMessage());    }    }else {      System.out.println("失败");    }    return NONE;  }

产生随机串部分代码:

public class RandCharsUtils {  private static SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");  public static String getRandomString(int length) { //length表示生成字符串的长度    String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";      Random random = new Random();      StringBuffer sb = new StringBuffer();    int number = 0;    for (int i = 0; i < length; i++) {        number = random.nextInt(base.length());        sb.append(base.charAt(number));      }      return sb.toString();    }    }

生成签名:

public class WXSignUtils {  /**   * 微信支付签名算法sign   * @param characterEncoding   * @param parameters   * @return   */  @SuppressWarnings("rawtypes")  public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){    StringBuffer sb = new StringBuffer();    Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)    Iterator it = es.iterator();    while(it.hasNext()) {      Map.Entry entry = (Map.Entry)it.next();      String k = (String)entry.getKey();      Object v = entry.getValue();      if(null != v && !"".equals(v)           && !"sign".equals(k) && !"key".equals(k)) {        sb.append(k + "=" + v + "&");      }    }    sb.append("key=" + weixinConstant.KEY);    String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();    return sign;  }}

md5部分代码:

import java.security.MessageDigest;public class MD5Util {  private static String byteArrayToHexString(byte b[]) {    StringBuffer resultSb = new StringBuffer();    for (int i = 0; i < b.length; i++)      resultSb.append(byteToHexString(b[i]));    return resultSb.toString();  }  private static String byteToHexString(byte b) {    int n = b;    if (n < 0)      n += 256;    int d1 = n / 16;    int d2 = n % 16;    return hexDigits[d1] + hexDigits[d2];  }  public static String MD5Encode(String origin, String charsetname) {    String resultString = null;    try {      resultString = new String(origin);      MessageDigest md = MessageDigest.getInstance("MD5");      if (charsetname == null || "".equals(charsetname))        resultString = byteArrayToHexString(md.digest(resultString            .getBytes()));      else        resultString = byteArrayToHexString(md.digest(resultString            .getBytes(charsetname)));    } catch (Exception exception) {    }    return resultString;  }  private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",    "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };}

构造xml:

/**   * 构造企业付款xml参数   * @param xml   * @return   */  public static String transferXml(Transfers transfers){      xStream.autodetectAnnotations(true);      xStream.alias("xml", Transfers.class);      return xStream.toXML(transfers);  }

向微信发送xml请求(验证证书)部分代码:

public class HttpUtil {  /**   * 发送post请求   *    * @param url   *      请求地址   * @param outputEntity   *      发送内容   * @param isLoadCert   *      是否加载证书   */  public static CloseableHttpResponse Post(String url, String outputEntity, boolean isLoadCert) throws Exception {    HttpPost httpPost = new HttpPost(url);    // 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别    httpPost.addHeader("Content-Type", "text/xml");    httpPost.setEntity(new StringEntity(outputEntity, "UTF-8"));    if (isLoadCert) {      // 加载含有证书的http请求      return HttpClients.custom().setSSLSocketFactory(CertUtil.initCert()).build().execute(httpPost);    } else {      return HttpClients.custom().build().execute(httpPost);    }  }}

加载证书部分代码:(加载证书需要注意证书放置位置在项目下的webapp中建文件夹,linux单独防止只要地址配置正确即可。)

import java.io.File;import java.io.FileInputStream;import java.security.KeyStore;import javax.net.ssl.SSLContext;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.ssl.SSLContexts;/** * 加载证书的类 * @author  * @since 2017/08/16 */@SuppressWarnings("deprecation")public class CertUtil {  private static WeixinConfigUtils config = new WeixinConfigUtils();  /**   * 加载证书   */  public static SSLConnectionSocketFactory initCert() throws Exception {    FileInputStream instream = null;    KeyStore keyStore = KeyStore.getInstance("PKCS12");    instream = new FileInputStream(new File(weixinConstant.PATH));    keyStore.load(instream, config.mch_id.toCharArray());    if (null != instream) {      instream.close();    }    SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore,config.mch_id.toCharArray()).build();    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);    return sslsf;  }}

加载配置文件部分代码:

@SuppressWarnings("unused")public class WeixinConfigUtils {  private static final Log log = LogFactory.getLog(WeixinConfigUtils.class);  public static String appid;  public static String mch_id;  public static String notify_url;  public static String order_notify_url;  public static String doctor_notify_url;  static {    try{      InputStream is = WeixinConfigUtils.class.getResourceAsStream("/weixin.properties");      Properties properties = new Properties();      properties.load(is);      appid = properties.getProperty("weixin.appid");      mch_id = properties.getProperty("weixin.mch_id");      notify_url = properties.getProperty("weixin.notify_url");      order_notify_url = properties.getProperty("weixin.order_notify_url");      doctor_notify_url = properties.getProperty("weixin.doctor_notify_url");    }catch(Exception ex){      log.debug("加载配置文件:"+ex.getMessage());    }  }}

获取返回的xml参数并解析为map:

/**   * 解析申请退款之后微信返回的值并进行存库操作   * @throws IOException    * @throws JDOMException    */  public static Map<String, String> parseRefundXml(String refundXml) throws JDOMException, IOException{    ParseXMLUtils.jdomParseXml(refundXml);    StringReader read = new StringReader(refundXml);    // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入    InputSource source = new InputSource(read);    // 创建一个新的SAXBuilder    SAXBuilder sb = new SAXBuilder();    // 通过输入源构造一个Document    org.jdom.Document doc;    doc = (org.jdom.Document) sb.build(source);    org.jdom.Element root = doc.getRootElement();// 指向根节点    List<org.jdom.Element> list = root.getChildren();    Map<String, String> refundOrderMap = new HashMap<String, String>();    if(list!=null&&list.size()>0){      for (org.jdom.Element element : list) {        refundOrderMap.put(element.getName(), element.getText());      }      return refundOrderMap;      }    return null;  }

调用时候主要是获取openid和调起接口的ip(ip十分重要,微信在收到xml后会校验传过去的ip和微信获取的调起接口ip是否一致)
在调用时候当返回错误码为“SYSTEMERROR”时,一定要使用原单号重试,否则可能造成重复支付等资金风险。
微信官方文档提供有相关的参数错误码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表