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

网友投稿 260 2023-01-21


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

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

1、商户号已入驻90日

 2、商户号有30天连续正常交易

满足以上条件就可登录微信支付商户平台-产品中心,开通企业付款。

调用的链接地址:接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers

微信官方接口文档提供的调用微信企业付款的参数:

封装请求微信企业付款的实体类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 parameters = new TreeMap();

// 微信的参数

private WeixinConfigUtils cohttp://nfig = 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 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 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 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 list = root.getChildren();

Map refundOrderMap = new HashMap();

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”时,一定要使用原单号重试,否则可能造成重复支付等资金风险。

微信官方文档提供有相关的参数错误码


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Spring Cloud Eureka 服务上下线监控的实现
下一篇:服装研发管理平台供应商(中国服装优质制造商联盟)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~