本地开发环境支付回调调试方法可以参考:https://www.cnblogs.com/pxblog/p/11623053.html

需要自行引入相关依赖

官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2

用于企业向微信用户个人付款,目前支持向指定微信用户的openid付款。

官方提示

ClientCustomSSL.java

package com.weixinpay;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils; import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore; /**
* This example demonstrates how to create secure connections with a custom SSL
* context.
*/
public class ClientCustomSSL { public static String getInSsl(String url,File pkcFile,String storeId,
String params,String contentType)
throws Exception {
String text = "";
// 指定读取证书格式为PKCS12
KeyStore keyStore = KeyStore.getInstance("PKCS12");
// 读取本机存放的PKCS12证书文件
FileInputStream instream = new FileInputStream(pkcFile);
try {
// 指定PKCS12的密码(商户ID)
keyStore.load(instream, storeId.toCharArray());
} finally {
instream.close();
} // Trust own CA and all self-signed certs
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, storeId.toCharArray()).build();
// Allow TLSv1 protocol only
// 指定TLS版本
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
// 设置httpclient的SSLSocketFactory
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
try {
HttpPost post = new HttpPost(url);
StringEntity s = new StringEntity(params,"utf-8");
if(StringUtils.isBlank(contentType)){
s.setContentType("application/xml");
}
s.setContentType(contentType);
post.setEntity(s);
HttpResponse res = httpclient.execute(post);
HttpEntity entity = res.getEntity();
text= EntityUtils.toString(entity, "utf-8");
} finally {
httpclient.close();
}
return text;
} }

Num62.java

package com.weixinpay;

/**
* 62进制数字
*/
public class Num62 {
/**
* 62个字母和数字,含大小写
*/
public static final char[] N62_CHARS = {'0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z'}; }

PaymentConfig.java

package com.weixinpay;

public class PaymentConfig {
/*******微信支付参数*********/ //公众账号ID
public static final String appid="wxd3e"; //密钥 key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
public static final String appKey="abcde"; //商户号
public static final String mch_id="15849"; //转账请求接口地址
public static final String pay_url="https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; }

PayUtil.java

package com.weixinpay;

import org.apache.commons.lang.StringUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder; import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.util.*; public class PayUtil { /**
* UTF-8编码
*/
public static final String UTF8 = "UTF-8"; /**
* 将需要传递给微信的参数转成xml格式
* @param parameters
* @return
*/
public static String assembParamToXml(Map<String,String> parameters){
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set<String> es = parameters.keySet();
List<Object> list=new ArrayList<Object>(es);
Object[] ary =list.toArray();
Arrays.sort(ary);
list=Arrays.asList(ary);
Iterator<Object> it = list.iterator();
while(it.hasNext()) {
String key = (String) it.next();
String val=(String) parameters.get(key);
if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {
sb.append("<"+key+">"+"<![CDATA["+val+"]]></"+key+">");
}else {
sb.append("<"+key+">"+val+"</"+key+">");
}
}
sb.append("</xml>");
return sb.toString();
} /**
* 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
public static Map parseXMLToMap(String strxml) throws JDOMException, IOException {
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\""+UTF8+"\"");
if(null == strxml || "".equals(strxml)) {
return null;
}
Map m = new HashMap();
InputStream in = new ByteArrayInputStream(strxml.getBytes(UTF8));
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while(it.hasNext()) {
Element e = (Element) it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if(children.isEmpty()) {
v = e.getTextNormalize();
} else {
v =PayUtil.getChildrenText(children);
}
m.put(k, v);
}
//关闭流
in.close();
return m;
} /**
* 获取子结点的xml
* @param children
* @return String
*/
public static String getChildrenText(List children) {
StringBuffer sb = new StringBuffer();
if(!children.isEmpty()) {
Iterator it = children.iterator();
while(it.hasNext()) {
Element e = (Element) it.next();
String name = e.getName();
String value = e.getTextNormalize();
List list = e.getChildren();
sb.append("<" + name + ">");
if(!list.isEmpty()) {
sb.append(getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
}
return sb.toString();
} /**
* 微信支付签名sign
* @param param
* @param key
* @return
*/
public static String createSign(Map<String, String> param,String key){
//签名步骤一:按字典排序参数
List list=new ArrayList(param.keySet());
Object[] ary =list.toArray();
Arrays.sort(ary);
list=Arrays.asList(ary);
String str="";
for(int i=0;i<list.size();i++){
str+=list.get(i)+"="+param.get(list.get(i)+"")+"&";
}
//签名步骤二:加上key
str+="key="+key;
//步骤三:加密并大写
str=PayUtil.MD5Encode(str,"utf-8").toUpperCase();
return str;
} public static String MD5Encode(String origin,String charsetName){
String resultString=null;
try{
resultString=new String(origin);
MessageDigest md=MessageDigest.getInstance("MD5");
if(StringUtils.isBlank(charsetName)){
resultString=byteArrayToHexString(md.digest(resultString.getBytes()));
}else{
resultString=byteArrayToHexString(md.digest(resultString.getBytes(charsetName)));
}
}catch(Exception e){ }
return resultString;
} public static String byteArrayToHexString(byte b[]){
StringBuffer resultSb=new StringBuffer();
for(int i=0;i<b.length;i++){
resultSb.append(PayUtil.byteToHexString(b[i]));
}
return resultSb.toString();
} public static String byteToHexString(byte b){
int n=b;
if(n<0){
n+=256;
}
int d1=n/16;
int d2=n%16;
return PayUtil.hexDigits[d1]+PayUtil.hexDigits[d2];
} public static final String hexDigits[]={ "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; /**
* 元转换为分
* @param amount
*/
public static String changeY2F(Double amount){
String currency = amount.toString();
int index = currency.indexOf(".");
int length = currency.length();
Long amLong = 0l;
if(index == -1){
amLong = Long.valueOf(currency+"00");
}else if(length - index >= 3){
amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));
}else if(length - index == 2){
amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);
}else{
amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");
}
return amLong.toString();
} }

WeixinPay.java

package com.weixinpay;

import org.apache.commons.lang.RandomStringUtils;

import java.io.File;
import java.util.HashMap;
import java.util.Map; public class WeixinPay { /**
* 企业付款接口 用于企业向微信用户个人付款
* 目前支持向指定微信用户的openid付款。
* @param pkcFile 商户证书文件
* @param orderNo 订单编号
* @param weixinOpenId 要付款的用户openid
* @param realname 收款用户姓名
* @param payAmount 转账金额
* @param desc 企业付款备注
* @param ip ip地址
* @return
*/
public static Object[] payToUser(File pkcFile, String orderNo, String weixinOpenId, String realname
, Double payAmount, String desc, String ip) {
Map<String, String> paramMap = new HashMap<String, String>();
// 公众账号appid[必填]
paramMap.put("mch_appid", PaymentConfig.appid);
// 微信支付分配的商户号 [必填]
paramMap.put("mchid", PaymentConfig.mch_id);
// 终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB" [非必填]
paramMap.put("device_info", "WEB");
// 随机字符串,不长于32位。 [必填]
paramMap.put("nonce_str", RandomStringUtils.random(16, Num62.N62_CHARS)); // 商户订单号,需保持唯一性[必填]
paramMap.put("partner_trade_no", orderNo); // 商户appid下,某用户的openid[必填]
paramMap.put("openid", weixinOpenId); //校验用户姓名选项 NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名
paramMap.put("check_name", "OPTION_CHECK"); //收款用户姓名,如果check_name设置为FORCE_CHECK,则必填用户真实姓名
paramMap.put("re_user_name", realname);
// 企业付款金额,金额必须为整数 单位为分 [必填]
paramMap.put("amount", PayUtil.changeY2F(payAmount));
// 企业付款描述信息 [必填]
paramMap.put("desc", desc);
// 调用接口的机器Ip地址[必填]
paramMap.put("spbill_create_ip", ip);
// 根据微信签名规则,生成签名
paramMap.put("sign",
PayUtil.createSign(paramMap, PaymentConfig.appKey));
// 把参数转换成XML数据格式
String xmlWeChat = PayUtil.assembParamToXml(paramMap);
String resXml = "";
boolean postError = false;
try {
resXml = ClientCustomSSL.getInSsl(PaymentConfig.pay_url, pkcFile, PaymentConfig.mch_id
, xmlWeChat, "application/xml");
} catch (Exception e1) {
postError = true;
e1.printStackTrace();
}
Object[] result = new Object[2];
result[0] = postError;
result[1] = resXml;
return result;
} }

商户证书说明:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=4_3

控制器调用类

PayContoller.java

package com.weixinpay;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import java.io.File;
import java.util.HashMap;
import java.util.Map; @Controller
public class PayContoller { /**
* 企业付款到用户个人微信
* 简单demo 需要自行完善逻辑
* @return
*/
@RequestMapping(value = "/transfers")
public String transfers() { File pkcFile = new File("商户证书路径"); String orderNo = "订单编号 可以参考:https://www.cnblogs.com/pxblog/p/12818067.html"; String weixinOpenId = "用户的openid 可以参考:https://www.cnblogs.com/pxblog/p/10542698.html"; String realname = "用户的真实姓名"; //转账的金额 金额格式转换可以参考 https://www.cnblogs.com/pxblog/p/13186037.html
Double payAmount = 0.01; String desc = "企业付款备注"; String ip = "ip地址 可以参考:https://www.cnblogs.com/pxblog/p/13360768.html"; Object result[] = WeixinPay.payToUser(pkcFile, orderNo, weixinOpenId, realname, payAmount, desc, ip);
String resXml = (String) result[1];
boolean postError = (Boolean) result[0];
if (!postError) {
Map<String, String> map = new HashMap<String, String>();
try {
map = PayUtil.parseXMLToMap(resXml);
} catch (Exception e) {
e.printStackTrace();
}
String returnCode = map.get("return_code");
if (returnCode.equalsIgnoreCase("FAIL")) {
//支付失败
return map.get("return_msg");
} else if (returnCode.equalsIgnoreCase("SUCCESS")) {
if (map.get("err_code") != null) {
//支付失败
return map.get("err_code_des");
} else if (map.get("result_code").equalsIgnoreCase(
"SUCCESS")) {
//支付成功 paymentNo:微信付款单号 payment_time:付款成功时间
String paymentNo = map.get("payment_no");
String payment_time = map.get("payment_time");
try { //如果是体现操作,在这里处理体现订单的状态,把状态转为提现成功 } catch (Exception e) {
e.printStackTrace();
}
return "返回到成功的页面";
}
}
} return "返回通信失败的错误页面";
}
}

JAVA微信支付——企业付款(企业向微信用户个人付款、转账)的更多相关文章

  1. 微信支付之01------获取订单微信支付二维码的接口------Java实现

    [ 前言:以前写过一个获取微信二维码支付的接口,发现最近公司新开的项目会经常用到,现在我又翻出代码看了一遍,觉得还是把整个代码流程记下来的好 ] 借鉴博客: 他这篇博客写得不错,挺全的:https:/ ...

  2. 微信支付之h5方式(非微信内置浏览器中支付)

    这两天完成了公司网站手机和PC端的支付对接,就是支付宝和微信. 对接完后有所感触,我们来聊一聊,微信支付的坑,为什么这么说呢,因为我在对接完支付宝后是很愉快的,基本上在demo上稍加修改就ok了, 对 ...

  3. iOS中 最新微信支付/最全的微信支付教程详解 韩俊强的博客

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博! 亲们, 首先让我们来看一下微信支付的流程吧. 1. 注册微信开放平台,创建应用获取appid,appSecret, ...

  4. iOS中 最新微信支付/最全的微信支付教程具体解释 韩俊强的博客

    亲们, 首先让我们来看一下微信支付的流程吧. 1. 注冊微信开放平台,创建应用获取appid,appSecret,申请支付功能,申请成功之后会返回一些參数. 2. 下载微信支付sdk 3. clien ...

  5. ThinkPHP 5 整合支付宝微信支付(支付宝H5,微信H5、APP支付、公众号支付)

    因项目没有PC站所以没有写电脑网站支付. Pay.php支付控制器 <?php // +----------------------------------------------------- ...

  6. iOS版微信开发小结(微信支付,APP跳转微信公众号)

    最近公司心血来潮,一心要搞微信.废话不多说,直接上干货. 开发前准备: 1.在微信开发者平台获取开发者认证:(一年300元人民币) PS:具体流程按照微信流程指示操作即可,在这就不废话了. 2.下载微 ...

  7. C#开发微信门户及应用(35)--微信支付之企业付款封装操作

    在前面几篇随笔,都是介绍微信支付及红包相关的内容,其实支付部分的内容还有很多,例如企业付款.公众号支付或刷卡支付.摇一摇红包.代金券等方面的内容,这些都是微信接口支持的内容,本篇继续微信支付这一主题, ...

  8. thinkphp.2 thinkphp5微信支付 微信公众号支付 thinkphp 微信扫码支付 thinkphp 微信企业付款5

    前面已经跑通了微信支付的流程,接下来吧微信支付和微信企业付款接入到thinkphp中,版本是3.2 把微信支付类.企业付款类整合到一起放到第三方类库,这里我把微信支付帮助类和企业付款类放到同一个文件了 ...

  9. 企业移动互联网O2O微信支付流程图

    过去一周里最受关注的应该就是微信了,腾讯合作伙伴大会微信分论坛的火爆现场,没有亲临其境是无法想象的,近3000人报名,2000多人来到现场,试图进入只能容纳300人的会场…… 闲话不表,进入正题吧,本 ...

  10. Java之微信支付(扫码支付模式二)案例实战

    摘要:最近的一个项目中涉及到了支付业务,其中用到了微信支付和支付宝支付,在做的过程中也遇到些问题,所以现在总结梳理一下,分享给有需要的人,也为自己以后回顾留个思路. 一:微信支付接入准备工作: 首先, ...

随机推荐

  1. Topcoder 12519 ScotlandYard(点对 dp+最长路)

    题面传送门 题意: 有两个人 A 和 B 玩一个游戏.游戏规则大致是这样的: 有 \(n\) 个城市和三种交通工具公交.地铁和出租车. 给出三个 \(n\times n\) 的字符矩阵 \(b,m,t ...

  2. PicGo + Gitee +Typora实现markdown图床

    目录 1. PicGo安装 2.Gitee配置 3.配置PicGo 3.Typora的设置 网上有一些很详细的教程,我这里只记录要点,其余部分按以下教程步骤来就行. 1. PicGo安装 国内下载可能 ...

  3. Linux中shell去除空行的几种方法

    有时我们在处理和查看文件时,经常会有很多空行,为了美观或是有需要时,就有必要把这些除行去掉了,方法如下: #如需将结果输出加入重定向        > 文件名 1)用tr命令 代码如下: cat ...

  4. 数据分析体系 — 用户粘性的两个计算指标(DAU/MAU和月人均活跃天数)

    很多运营都了解DAU(日活跃用户数)和MAU(月活跃用户数)的重要性,但在某些情况下这两个数值本身并不能反映出太多问题,这个时候就要引用到[DAU/MAU]的概念,即[日活/月活] 用户粘性的两个计算 ...

  5. Linux—yum的python版本错误——高级解决方案

    彻底搞明白,python升级后,为什么会导致yum不可用 首先我们来分析下,python升级后,yum为什么会不可用? 先说个关于python的问题,Linux系统很多软件都依赖于python,因此不 ...

  6. Linux— rpm 命令

    rpm命令是RPM软件包的管理工具.rpm原本是Red Hat Linux发行版专门用来管理Linux各项套件的程序,由于它遵循GPL规则且功能强大方便,因而广受欢迎.逐渐受到其他发行版的采用.RPM ...

  7. shell 指令

    cat/proc/parttitions df -T pstree ext4 是linux 文件系统

  8. python格式化输出的两种方式对比

    1.%符号方法和format()函数方法 2.对比: 1 print('我今年%d岁' %22.125) 2 print('我今年{0:f}'.format(22.125)) 3 #报错 4 #槽中类 ...

  9. Android项目的settings.gradle和build.gradle

    gradle构建的项目中的build.gradle和settings.gradle文件 build.gradle 浅析(一) 史上最全的Android build.gradle配置教程 Android ...

  10. GO 总章

    GO 学习资源 go 代理 GO 语言结构 GO 数字运算 GO 时间处理 GO 定时器 GO 异常处理 go recover让崩溃的程序继续执行 GO Exit Fatal panic GO 通过进 ...