WxPayServiceImpl.java 8.6 KB
package org.theyeasy.weixin.service.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Map;
import java.util.Random;

import javax.annotation.PostConstruct;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;
import javax.servlet.jsp.jstl.core.Config;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.theyeasy.weixin.service.WxPayService;
import org.theyeasy.weixin.util.MD5Util;
import org.theyeasy.weixin.util.WxMessageUtil;

import com.sun.org.apache.xerces.internal.parsers.XMLParser;
import com.w1hd.zzhnc.config.WxPayConfig;
import com.w1hd.zzhnc.vo.Vo_msg;

@Service
public class WxPayServiceImpl implements WxPayService{
	@Autowired 
	WxPayConfig config;
	
	protected final Logger log = LoggerFactory.getLogger(this.getClass());
	
	private String mch_appid = "";
	private String mchid = "";
	private String key = "";
	private String cert_file="";
	private String spbill_create_ip="";
	 
	
	@PostConstruct
    public void init() {
		mch_appid = config.getMchappid();
		mchid = config.getMchid();
		key = config.getKey();
		cert_file = config.getCertFile();
		spbill_create_ip = config.getIp();
	}
	
	@Override
	public Vo_msg payMoney(String partner_trade_no, String openid, int amount, String desc) {
		Vo_msg msg = new Vo_msg(-1,null,"未知错误");
		try {					
			KeyStore keyStore = KeyStore.getInstance("PKCS12");
			FileInputStream instream = new FileInputStream(new File(cert_file));
			try {
				keyStore.load(instream, mchid.toCharArray());
			} finally {
				instream.close();
			}

			String nonce_str = getRandomString(30);
			String sign = getSign(nonce_str, partner_trade_no, openid, "NO_CHECK", amount, desc, spbill_create_ip);
			System.out.println("sign=" + sign);
			
			//构造xml参数
			StringBuffer sb = new StringBuffer();
			sb.append("<xml>\n");
			sb.append("<mch_appid>").append(mch_appid).append("</mch_appid>").append("\n");
			sb.append("<mchid>").append(mchid).append("</mchid>").append("\n");
			sb.append("<nonce_str>").append(nonce_str).append("</nonce_str>").append("\n");
			sb.append("<partner_trade_no>").append(partner_trade_no).append("</partner_trade_no>").append("\n");
			sb.append("<openid>").append(openid).append("</openid>").append("\n");
			sb.append("<check_name>").append("NO_CHECK").append("</check_name>").append("\n");
			sb.append("<amount>").append(amount).append("</amount>").append("\n");
			sb.append("<desc>").append(desc).append("</desc>").append("\n");
			sb.append("<spbill_create_ip>").append(spbill_create_ip).append("</spbill_create_ip>").append("\n");
			sb.append("<sign>").append(sign).append("</sign>").append("\n");
			sb.append("</xml>");
			String param = sb.toString();
			System.out.println(param);
			String uri = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
			// Trust own CA and all self-signed certs
			SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchid.toCharArray()).build();
			// Allow TLSv1 protocol only
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
			CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
			try {
				HttpPost httppost = new HttpPost(uri);
				httppost.setEntity(new StringEntity(param, Charset.forName("UTF-8")));
				
				httppost.setHeader("Content-Type","text/xml");  
				httppost.setHeader("charset","utf-8");  
	             		       
				CloseableHttpResponse response = httpclient.execute(httppost);
				try {
					HttpEntity entity = response.getEntity();

					System.out.println("----------------------------------------");
					System.out.println(response.getStatusLine());
					if (entity != null) {
						System.out.println("Response content length: " + entity.getContentLength());
						BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
						StringBuffer sb2 = new StringBuffer();
						String text;
						while ((text = bufferedReader.readLine()) != null) {
							sb2.append(text);
						}
						log.info(sb2.toString());
						Map<String, String> requestMap = WxMessageUtil.parseXml(sb2.toString());
			        	String code = requestMap.get("return_code");
			        	String resultCode = requestMap.get("result_code");
			        	if(code.equals("SUCCESS")&&resultCode.equals("SUCCESS")) //成功
			        	{
			        		String payment_no = requestMap.get("payment_no");
			        		msg = new Vo_msg(0, null, payment_no);
			        	}
			        	else {
			        		String errmsg = requestMap.get("err_code_des");
			        		msg = new Vo_msg(-1,null,errmsg);
			        		log.info("企业付款到零钱失败:" + errmsg);
						}			        
					}
					EntityUtils.consume(entity);
				} finally {
					response.close();
				}
			} finally {
				httpclient.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
			msg = new Vo_msg(-1, null, "系统处理失败!");
		}
		return msg;
	}

	
	/**
	 * 获取签名sign
	 * @param nonce_str  随机字符串,最长32位
	 * @param partner_trade_no  订单号
	 * @param openid   粉丝的openid
	 * @param check_name  是否实名验证
	 * @param amount   金额(单位:分)
	 * @param desc  付款描述
	 * @param spbill_create_ip  调用api的ip
	 * @return
	 */
	private String getSign(String nonce_str,String partner_trade_no, String openid, String check_name, int amount, String desc, String spbill_create_ip) {

		String[] array = new String[9];
		array[0] = "mch_appid=" + mch_appid;
		array[1] = "mchid=" + mchid;
		array[2] = "nonce_str=" + nonce_str;
		array[3] = "partner_trade_no=" + partner_trade_no;
		array[4] = "openid=" + openid;
		array[5] = "check_name=" + check_name;
		array[6] = "amount=" + amount;
		array[7] = "desc=" + desc;
		array[8] = "spbill_create_ip=" + spbill_create_ip;

		StringBuffer sb = new StringBuffer();
		// 字符串排序
		Arrays.sort(array);
		for (int i = 0; i <array.length; i++) {
			sb.append(array[i]).append("&");
		}

		sb.append("key=" + key);
		String signTemp = sb.toString();
		System.out.println(signTemp);
		String sign = MD5Util.getMD5(signTemp);

		return sign;
	}

	

	/**
	 * 生成签名数据_HmacSHA1加密(用以验证微信服务端发过来的签名),对getSignStr的结果进行加密
	 * 
	 * @param data
	 *            待加密的数据
	 * @param key
	 *            加密使用的key
	 * @throws InvalidKeyException
	 * @throws NoSuchAlgorithmException
	 */
	public static String hash_hmac(String signStr, String key) {
		try {
			byte[] keyBytes = key.getBytes();
			// 根据给定的字节数组构造一个密钥。
			SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA256");
			Mac mac = Mac.getInstance("HmacSHA256");
			mac.init(signingKey);

			byte[] rawHmac = mac.doFinal(signStr.getBytes());

			String hexBytes = byte2hex(rawHmac).toUpperCase();
			return hexBytes;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "error";
	}

	/**
	 * byte To Hex
	 * @param b
	 * @return
	 */
	public static String byte2hex(final byte[] b) {
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			// 以十六进制(基数 16)无符号整数形式返回一个整数参数的字符串表示形式。
			stmp = (java.lang.Integer.toHexString(b[n] & 0xFF));
			if (stmp.length() == 1) {
				hs = hs + "0" + stmp;
			} else {
				hs = hs + stmp;
			}
		}
		return hs;
	}
	 
	
	/**
	 * 构造指定长的随机字符串
	 * @param length
	 * @return 指定长度的随机字符串
	 */
	public static String getRandomString(int length) { // length表示生成字符串的长度
		String base = "abcdefghijklmnopqrstuvwxyz0123456789";
		Random random = new Random();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < length; i++) {
			int number = random.nextInt(base.length());
			sb.append(base.charAt(number));
		}
		return sb.toString();
	}
}