本地开发环境支付回调调试方法可以参考: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. 洛谷 P3285 - [SCOI2014]方伯伯的OJ(平衡树)

    洛谷题面传送门 在酒店写的,刚了一整晚终于调出来了-- 首先考虑当 \(n\) 比较小(\(10^5\) 级别)的时候怎么解决,我们考虑将所有用户按排名为关键字建立二叉排序树,我们同时再用一个 map ...

  2. 洛谷 P4099 - [HEOI2013]SAO(树形 dp)

    题面传送门 题意: 有一个有向图 \(G\),其基图是一棵树 求它拓扑序的个数 \(\bmod (10^9+7)\) \(n \in [1,1000]\) 如果你按照拓扑排序的方法来做,那恐怕你已经想 ...

  3. VS Code 配置和使用

    背景 Visual Studio Code(简称VS Code)是一款由微软开发且跨平台的免费源代码编辑器[6].该软件支持语法高亮.代码自动补全(又称IntelliSense).代码重构.查看定义功 ...

  4. MySQL 数据库的下载、安装和测试

    实例:Ubuntu 20.04 安装 mysql-server_5.7.31-1ubuntu18.04_amd64.deb-bundle.tar 1. 下载安装MySQL(安装 MySQL 5.7) ...

  5. expr判断是否为整数

    判断一个变量值或字符串是否为整数 原理:利用expr计算时变量或字符串必须为整数的规则,把变量和一个整数(非零) 相加,判断命令返回是否为0,0--成功为整数 #!/bin/bash expr $1 ...

  6. python-django-查询详解

    倒数第二条性质可以实现链式的调用,通过第一次的过滤还可以再过滤倒数第一条就是结果集从数据库中查询出来之后不会再进行数据库的查询的我们使用的object就是模型管理器manager的一个对象 obj = ...

  7. 【R】如何去掉数据框中包含非数值的行?

    目录 1. 去掉指定列中包含NA/Inf/NaN的行 2. 去掉指定列中包含其他乱七八糟字符串的行 3. 去掉整个数据框中包含非数值的行 只包含NA.NaN和Inf的情况 针对其他字符情况 4. 总结 ...

  8. CentOS安装配置Hadoop 1.2.1(伪分布模式)

    CentOS安装配置Hadoop1.2.1 1.下载安装文件 下载2个安装文件 JAVA环境:jdk-6u21-linux-i586.bin Hadoop环境:hadoop-1.2.1.tar.gz ...

  9. JAVA中null,"",equals,==相互之间使用详解

    "equals" 与 "==" "equals"只是比较值是否相同 而"=="则是比较两个变量是不是同一个变量,也应时是 ...

  10. Git(一)【基本使用,集成IDEA,GitHub】

    目录 一.本地库操作 ①基本操作 1.初始化本地库 2.设置用户签名|用户名|邮箱 3.查看本地库状态 4.添加暂存区 5.提交到本地库 6.查看文件modify详情 ②历史版本以及回退 1.查看历史 ...