Java实现微信的企业付款到零钱

一,问题

今天想接入微信中的企业付款到零钱的功能,然后去网上查了一些大佬的博客。然后也实现了。然后记录一下。

二,解决方案

企业付款到零钱的官方文档:

https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2

2.1 下载商家证书,然后将apiclient_cert.p12放到项目中

①下载商家证书

账号中心=》API安全

Java实现微信的企业付款到零钱

Java实现微信的企业付款到零钱

②将apiclient_cert.p12放到项目中

Java实现微信的企业付款到零钱

2.2 将官方的demo下载下来,放到项目中

官方demo下载地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

Java实现微信的企业付款到零钱

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;
	}
}