java实现微信企业付款到个人账户
微信官方提供了微信企业账户付款到微信个人零钱接口,提供企业向用户付款的功能,支持企业通过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();
// 构造签名的mapprivate 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()));elseresultString = 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);// 创建一个新的SAXBuilderSAXBuilder sb = new SAXBuilder();// 通过输入源构造一个Documentorg.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”时,一定要使用原单号重试,否则可能造成重复支付等资金风险。
微信官方文档提供有相关的参数错误码https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2。
java实现微信企业付款到个人账户相关推荐
- java实现微信企业付款到个人零钱(微信红包)
今天公司打算做一个活动,就是可以让用户领取平台发送的红包,根据微信官方文档实现微信企业付款到零钱(因为商户号不满足一些条件无法使用红包,红包跟零钱实现方法基本一样),然后又加入了一些简单的红包算法.微 ...
- java实现微信企业付款到银行卡_微信企业付款到银行卡实现方式 - 黎明互联-官方博客 - 黎明互联 - 区块链培训,PHP培训,IT培训,职业技能培训,追求极致!改变您的职业生涯!...
首先说一下微信支付已上线企业付款至银行卡功能.商户可以将商户号余额付款至指定的收款银行账户.通过指定收款银行账户户名.卡号,以及收款银行信息即可实现付款.但是功能目前为灰度开放,已灰度新资金流直连普通 ...
- 【Java】微信企业付款报错:java.io.IOException: toDerInputStream rejects tag type 45
原因是证书格式问题,之前用PHP做一直用.pem格式的证书,看了官方文档才知道,其他语言大多用.p12格式的证书: 更换为.p12格式证书,不报错了.
- java 企业付款_java实现微信企业付款到个人功能
微信官方提供了微信企业账户付款到微信个人零钱接口,提供企业向用户付款的功能,支持企业通过API接口付款,或通过微信支付商户平台网页功能操作付款.该接口并不是直接所有的商户都拥有,企业要开启必须满足以下 ...
- Java 微信企业付款到个人钱包
Java 微信企业付款到个人钱包 希望可以帮助到你 文章目录 **Java 微信企业付款到个人钱包** 前言 一.需要准备的配置 二.开发 总结 前言 微信企业付款到个人钱包,此功能模块需要提前在微信 ...
- JAVA微信企业付款到零钱(十分钟搞定),附完整DEMO下载
最近帮朋友做了一个简单的微分销系统,实现从企业付款到零钱分润的功能,简单记录一下微信提现功能开发的流程, 主要就是按规则封装好请求参数调用微信接口,涉及一些签名校验: A.接口流程 获取用户OPENI ...
- java零钱换整程序_JAVA微信企业付款到零钱(十分钟搞定),
JAVA微信企业付款到零钱(十分钟搞定), 最近帮朋友做了一个简单的微分销系统,实现从企业付款到零钱分润的功能,简单记录一下微信企业付款到零钱的开发过程, 主要就是按规则封装好请求参数调用微信接口,涉 ...
- 微信支付、微信企业付款到零钱工具类
微信支付.微信企业付款到零钱工具类 主要依赖:apache httpclient 4.5 jdk1.8 工具类主要功能: xml参数拼接 签名算法实现 post加密请求 import lombok.e ...
- 微信零钱数据在服务器,关于微信企业付款到零钱X509Certificate2读取证书信息,发布到服务器访问不到的解决方案...
前言: 最近做了一个通过调用微信企业付款到用户零钱的功能,真的挺奇怪的,在我本地调试的时候都没有问题,但是当我发布到服务上的时候却一直无法读取到我的证书信息.读取的代码如下,使用的是微信官方文档提供的 ...
最新文章
- 全面屏适配方案,终极版,华为隐藏导航栏解决方案
- 客户信贷应收总额相关
- python中的print()、str()和repr()的区别
- 关于centos6升级python3.6无法使用pip的问题
- 【转】Linux 静态库与共享库的使用
- HTTP Live Streaming直播(iOS直播)技术分析与实现(转)
- 猜物品游戏java编程_小猿圈Java初学者练习小案例:猜数字游戏
- android 实现自定义卫星菜单
- 华北水利水电大学计算机实验报告怎么写,考试类:华北水利水电大学C语言实验报告.doc...
- WPS Office 2019 For Linux 8722 发布,引入pdf组件
- 备忘录怎么用红笔标注_备忘录丢失怎么找回来?教你轻松玩转备忘录
- mac终端编写c语言,【新手提问】有知道用mac终端编c语言的网络编程的人吗?
- Python爬虫之(二)工具的使用
- Ruby First
- windows程序设计之简单界面入门
- 贵州大学旧物交易系统
- 远距离485无线传输方案
- 通常环境光照度参照表
- 少室山论道——天下武功
- 节点表征学习与节点预测和边预测
热门文章
- Domain name server 域名服务
- Android手电筒开发
- 结果集没有当前行的解决方法
- LATEXT导入.sty
- 什么叫loopback地址?是怎样用的?
- android 开发论坛资源URL
- php 根据父级id查出,php,_三级分类 like查询 查询到很多id 需要找到对应的父级id 并根据父级id组合 应该怎么根据父级id将数据组合在一起呢?,php - phpStudy...
- 如何将scr文件设置为屏保
- pageHelper与PageInfo联合进行分页查询原理
- 用伪造的TCP协议头花式欺骗核心转发设备?