JAVA微信支付——企业付款(企业向微信用户个人付款、转账)
本地开发环境支付回调调试方法可以参考: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微信支付——企业付款(企业向微信用户个人付款、转账)的更多相关文章
- 微信支付之01------获取订单微信支付二维码的接口------Java实现
[ 前言:以前写过一个获取微信二维码支付的接口,发现最近公司新开的项目会经常用到,现在我又翻出代码看了一遍,觉得还是把整个代码流程记下来的好 ] 借鉴博客: 他这篇博客写得不错,挺全的:https:/ ...
- 微信支付之h5方式(非微信内置浏览器中支付)
这两天完成了公司网站手机和PC端的支付对接,就是支付宝和微信. 对接完后有所感触,我们来聊一聊,微信支付的坑,为什么这么说呢,因为我在对接完支付宝后是很愉快的,基本上在demo上稍加修改就ok了, 对 ...
- iOS中 最新微信支付/最全的微信支付教程详解 韩俊强的博客
每日更新关注:http://weibo.com/hanjunqiang 新浪微博! 亲们, 首先让我们来看一下微信支付的流程吧. 1. 注册微信开放平台,创建应用获取appid,appSecret, ...
- iOS中 最新微信支付/最全的微信支付教程具体解释 韩俊强的博客
亲们, 首先让我们来看一下微信支付的流程吧. 1. 注冊微信开放平台,创建应用获取appid,appSecret,申请支付功能,申请成功之后会返回一些參数. 2. 下载微信支付sdk 3. clien ...
- ThinkPHP 5 整合支付宝微信支付(支付宝H5,微信H5、APP支付、公众号支付)
因项目没有PC站所以没有写电脑网站支付. Pay.php支付控制器 <?php // +----------------------------------------------------- ...
- iOS版微信开发小结(微信支付,APP跳转微信公众号)
最近公司心血来潮,一心要搞微信.废话不多说,直接上干货. 开发前准备: 1.在微信开发者平台获取开发者认证:(一年300元人民币) PS:具体流程按照微信流程指示操作即可,在这就不废话了. 2.下载微 ...
- C#开发微信门户及应用(35)--微信支付之企业付款封装操作
在前面几篇随笔,都是介绍微信支付及红包相关的内容,其实支付部分的内容还有很多,例如企业付款.公众号支付或刷卡支付.摇一摇红包.代金券等方面的内容,这些都是微信接口支持的内容,本篇继续微信支付这一主题, ...
- thinkphp.2 thinkphp5微信支付 微信公众号支付 thinkphp 微信扫码支付 thinkphp 微信企业付款5
前面已经跑通了微信支付的流程,接下来吧微信支付和微信企业付款接入到thinkphp中,版本是3.2 把微信支付类.企业付款类整合到一起放到第三方类库,这里我把微信支付帮助类和企业付款类放到同一个文件了 ...
- 企业移动互联网O2O微信支付流程图
过去一周里最受关注的应该就是微信了,腾讯合作伙伴大会微信分论坛的火爆现场,没有亲临其境是无法想象的,近3000人报名,2000多人来到现场,试图进入只能容纳300人的会场…… 闲话不表,进入正题吧,本 ...
- Java之微信支付(扫码支付模式二)案例实战
摘要:最近的一个项目中涉及到了支付业务,其中用到了微信支付和支付宝支付,在做的过程中也遇到些问题,所以现在总结梳理一下,分享给有需要的人,也为自己以后回顾留个思路. 一:微信支付接入准备工作: 首先, ...
随机推荐
- Topcoder 12519 ScotlandYard(点对 dp+最长路)
题面传送门 题意: 有两个人 A 和 B 玩一个游戏.游戏规则大致是这样的: 有 \(n\) 个城市和三种交通工具公交.地铁和出租车. 给出三个 \(n\times n\) 的字符矩阵 \(b,m,t ...
- PicGo + Gitee +Typora实现markdown图床
目录 1. PicGo安装 2.Gitee配置 3.配置PicGo 3.Typora的设置 网上有一些很详细的教程,我这里只记录要点,其余部分按以下教程步骤来就行. 1. PicGo安装 国内下载可能 ...
- Linux中shell去除空行的几种方法
有时我们在处理和查看文件时,经常会有很多空行,为了美观或是有需要时,就有必要把这些除行去掉了,方法如下: #如需将结果输出加入重定向 > 文件名 1)用tr命令 代码如下: cat ...
- 数据分析体系 — 用户粘性的两个计算指标(DAU/MAU和月人均活跃天数)
很多运营都了解DAU(日活跃用户数)和MAU(月活跃用户数)的重要性,但在某些情况下这两个数值本身并不能反映出太多问题,这个时候就要引用到[DAU/MAU]的概念,即[日活/月活] 用户粘性的两个计算 ...
- Linux—yum的python版本错误——高级解决方案
彻底搞明白,python升级后,为什么会导致yum不可用 首先我们来分析下,python升级后,yum为什么会不可用? 先说个关于python的问题,Linux系统很多软件都依赖于python,因此不 ...
- Linux— rpm 命令
rpm命令是RPM软件包的管理工具.rpm原本是Red Hat Linux发行版专门用来管理Linux各项套件的程序,由于它遵循GPL规则且功能强大方便,因而广受欢迎.逐渐受到其他发行版的采用.RPM ...
- shell 指令
cat/proc/parttitions df -T pstree ext4 是linux 文件系统
- python格式化输出的两种方式对比
1.%符号方法和format()函数方法 2.对比: 1 print('我今年%d岁' %22.125) 2 print('我今年{0:f}'.format(22.125)) 3 #报错 4 #槽中类 ...
- Android项目的settings.gradle和build.gradle
gradle构建的项目中的build.gradle和settings.gradle文件 build.gradle 浅析(一) 史上最全的Android build.gradle配置教程 Android ...
- GO 总章
GO 学习资源 go 代理 GO 语言结构 GO 数字运算 GO 时间处理 GO 定时器 GO 异常处理 go recover让崩溃的程序继续执行 GO Exit Fatal panic GO 通过进 ...