Java实现微信的企业付款到零钱
一,问题
今天想接入微信中的企业付款到零钱的功能,然后去网上查了一些大佬的博客。然后也实现了。然后记录一下。
二,解决方案
企业付款到零钱的官方文档:
https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
2.1 下载商家证书,然后将apiclient_cert.p12放到项目中
①下载商家证书
账号中心=》API安全
②将apiclient_cert.p12放到项目中
2.2 将官方的demo下载下来,放到项目中
官方demo下载地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
2.3 准备好10个必须的参数
①先拿到9个参数
mch_appid:微信公众号的appid
mchid:商家ID
nonce_str:随机生成后数字,保证安全性
partner_trade_no:生成商户订单号
openid:支付给用户openid
check_name:是否验证真实姓名呢
amount:企业付款金额,单位为分。付款金额最少100分
desc:企业付款操作说明信息。必填。
spbill_create_ip:用户的ip地址
②根据上面的9个参数,得到第10个参数
sign:自己的签名。利用上面9个参数生成
2.4 发送去微信,让微信进行转账
2.5 源码
①TransferController:
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.jc.util.wxPay.WXPayUtil;
import controller.AuthUtil;
import paycontroller.HttpRequest;
/**
* @author: KOLO
* @date:2018年12月28日 上午9:58:07
* @version: 1.0 企业转账到零钱
*/
@Controller
@RequestMapping("/transfer")
public class TransferController {
/**
* @Title: transfer
* @Description: 企业转账到零钱
* @param:
* @return:
*/
@RequestMapping("/pay")
public @ResponseBody String transfer(HttpServletRequest request, HttpServletResponse response) {
// 1.0 拼凑企业支付需要的参数
String appid = AuthUtil.APPID; // 微信公众号的appid
String mch_id = AuthUtil.MCHID; // 商户号
String nonce_str = WXPayUtil.generateNonceStr(); // 生成随机数
String partner_trade_no = WXPayUtil.generateNonceStr(); // 生成商户订单号
String openid = "用户的OpenId"; // 支付给用户openid
String check_name = "NO_CHECK"; // 是否验证真实姓名呢
String re_user_name = "KOLO"; // 收款用户姓名(非必须)
String amount = "100"; // 企业付款金额,最少为100,单位为分
String desc = "恭喜你,完成了一个代买订单a6w3fswq51asdf6!"; // 企业付款操作说明信息。必填。
String spbill_create_ip = AuthUtil.getRequestIp(request); // 用户的ip地址
// 2.0 生成map集合
SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("mch_appid", appid); // 微信公众号的appid
packageParams.put("mchid", mch_id); // 商务号
packageParams.put("nonce_str", nonce_str); // 随机生成后数字,保证安全性
packageParams.put("partner_trade_no", partner_trade_no); // 生成商户订单号
packageParams.put("openid", openid); // 支付给用户openid
packageParams.put("check_name", check_name); // 是否验证真实姓名呢
packageParams.put("re_user_name", re_user_name);// 收款用户姓名
packageParams.put("amount", amount); // 企业付款金额,单位为分
packageParams.put("desc", desc); // 企业付款操作说明信息。必填。
packageParams.put("spbill_create_ip", spbill_create_ip); // 调用接口的机器Ip地址
try {
// 3.0 利用上面的参数,先去生成自己的签名
String sign = WXPayUtil.generateSignature(packageParams, AuthUtil.PATERNERKEY);
// 4.0 将签名再放回map中,它也是一个参数
packageParams.put("sign", sign);
// 5.0将当前的map结合转化成xml格式
String xml = WXPayUtil.mapToXml(packageParams);
// 6.0获取需要发送的url地址
String wxUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; // 获取退款的api接口
System.out.println("发送前的xml为:" + xml);
// 7,向微信发送请求转账请求
String returnXml = CertHttpUtil.postData(wxUrl, xml, AuthUtil.MCHID, AuthUtil.CERTPATH);
System.out.println("返回的returnXml为:" + returnXml);
// 8,将微信返回的xml结果转成map格式
Map<String, String> returnMap = WXPayUtil.xmlToMap(returnXml);
if (returnMap.get("return_code").equals("SUCCESS")) {
// 付款成功
System.out.println("returnMap为:" + returnMap);
}
return returnXml;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "error";
}
}
②CertHttpUtil
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
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 org.springframework.core.io.ClassPathResource;
import controller.AuthUtil;
/**
* 获取微信apiclient_cert.p12证书
*
* @author zengwei
* @email [email protected]
* @date 2018年4月5日 下午4:49:36
*/
public class CertHttpUtil {
private static int socketTimeout = 10000;// 连接超时时间,默认10秒
private static int connectTimeout = 30000;// 传输超时时间,默认30秒
private static RequestConfig requestConfig;// 请求器的配置
private static CloseableHttpClient httpClient;// HTTP请求器
/**
* 通过Https往API post xml数据
*
* @param url API地址
* @param xmlObj 要提交的XML数据对象
* @param mchId 商户ID
* @param certPath 证书位置
* @return
*/
public static String postData(String url, String xmlObj, String mchId, String certPath) {
// 加载证书
try {
initCert(mchId, certPath);
} catch (Exception e) {
e.printStackTrace();
}
String result = null;
HttpPost httpPost = new HttpPost(url);
// 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
httpPost.addHeader("Content-Type", "text/xml");
httpPost.setEntity(postEntity);
// 根据默认超时限制初始化requestConfig
requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
// 设置请求器的配置
httpPost.setConfig(requestConfig);
try {
HttpResponse response = null;
try {
response = httpClient.execute(httpPost);
} catch (IOException e) {
e.printStackTrace();
}
HttpEntity entity = response.getEntity();
try {
result = EntityUtils.toString(entity, "UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
} finally {
httpPost.abort();
}
return result;
}
/**
* 加载证书
*
* @param mchId 商户ID
* @param certPath 证书位置
* @throws Exception
*/
private static void initCert(String mchId, String certPath) throws Exception {
// 证书密码,默认为商户ID
String key = mchId;
// 证书的路径
String path = certPath;
// 指定读取证书格式为PKCS12
KeyStore keyStore = KeyStore.getInstance("PKCS12");
// 读取本机存放的PKCS12证书文件
ClassPathResource cp = new ClassPathResource(AuthUtil.CERTPATH);
InputStream instream = cp.getInputStream();
try {
// 指定PKCS12的密码(商户ID)
keyStore.load(instream, key.toCharArray());
} finally {
instream.close();
}
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray()).build();
SSLConnectionSocketFactory sslsf =
new SSLConnectionSocketFactory(sslcontext, new String[] {"TLSv1"}, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
}
}
③AuthUtil类
/**
* @author: KOLO
* @date:2018年12月19日 下午4:51:08
* @version: 1.0
*/
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import net.sf.json.JSONObject;
public class AuthUtil {
public static final String APPID = "商家的APPID";
public static final String APPSECRET = "商家的AppSecret";
public static final String MCHID = "商家的ID";
public static final String PATERNERKEY = "商家的**";
public static final String CERTPATH = "商家证书的路径";
public static JSONObject doGetJson(String url) throws ClientProtocolException, IOException {
JSONObject jsonObject = null;
// 首先初始化HttpClient对象
DefaultHttpClient client = new DefaultHttpClient();
// 通过get方式进行提交
HttpGet httpGet = new HttpGet(url);
// 通过HTTPclient的execute方法进行发送请求
HttpResponse response = client.execute(httpGet);
// 从response里面拿自己想要的结果
HttpEntity entity = response.getEntity();
if (entity != null) {
String result = EntityUtils.toString(entity, "UTF-8");
jsonObject = jsonObject.fromObject(result);
}
// 把链接释放掉
httpGet.releaseConnection();
return jsonObject;
}
/**
* @Title: getRequestIp
* @Description: 获取用户的ip地址
* @param:
* @return:
*/
public static String getRequestIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip.indexOf(",") != -1) {
String[] ips = ip.split(",");
ip = ips[0].trim();
}
return ip;
}
}