java实现微信企业付款到个人功能
程序员文章站
2024-02-25 23:27:15
微信官方提供了微信企业账户付款到微信个人零钱接口,提供企业向用户付款的功能,支持企业通过api接口付款,或通过微信支付商户平台网页功能操作付款。该接口并不是直接所有的商户都...
微信官方提供了微信企业账户付款到微信个人零钱接口,提供企业向用户付款的功能,支持企业通过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”时,一定要使用原单号重试,否则可能造成重复支付等资金风险。
微信官方文档提供有相关的
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。