微信支付java版本之Native付款 - Go语言中文社区

微信支付java版本之Native付款


最近工作中接触到一些关于微信支付方面的东西,看到给的DEMO都是PHP版本的,再加上微信支付文档写的确实不敢恭维,趟过不少坑之后闲下来做个总结。


一、前期准备

做微信开发首先要申请一个公共账号,申请成功后会以邮件形式发给你一些必要信息,公共账号中有开发文档以及开发中必要信息,以及测试的数据查询。



二、工具类

1.MD5加密工具类

package com.pay.utils.weixin;
import java.security.MessageDigest;
public class MD5Util {
	public final static String MD5(String s) {
        char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};       
        try {
            byte[] btInput = s.getBytes();
            // 获得MD5摘要算法的 MessageDigest 对象
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            // 使用指定的字节更新摘要
            mdInst.update(btInput);
            // 获得密文
            byte[] md = mdInst.digest();
            // 把密文转换成十六进制的字符串形式
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
       }
	}
}

2.CommonUtil工具类,用于装换成微信所需XML。以下return new String(xml.toString().getBytes(),"ISO8859-1");将工具类中的utf-8改成iso8859-1,否则微信订单中的中文会出现乱码,改后可以正确显示。

package com.pay.utils.weixin;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.Map.Entry;

public class CommonUtil {

	public static String CreateNoncestr(int length) {
		String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
		String res = "";
		for (int i = 0; i < length; i++) {
			Random rd = new Random();
			res += chars.indexOf(rd.nextInt(chars.length() - 1));
		}
		return res;
	}

	public static String CreateNoncestr() {
		String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
		String res = "";
		for (int i = 0; i < 16; i++) {
			Random rd = new Random();
			res += chars.charAt(rd.nextInt(chars.length() - 1));
		}
		return res;
	}

	public static String FormatQueryParaMap(HashMap<String, String> parameters)
			throws SDKRuntimeException {

		String buff = "";
		try {
			List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(
					parameters.entrySet());

			Collections.sort(infoIds,
					new Comparator<Map.Entry<String, String>>() {
						public int compare(Map.Entry<String, String> o1,
								Map.Entry<String, String> o2) {
							return (o1.getKey()).toString().compareTo(
									o2.getKey());
						}
					});

			for (int i = 0; i < infoIds.size(); i++) {
				Map.Entry<String, String> item = infoIds.get(i);
				if (item.getKey() != "") {
					buff += item.getKey() + "="
							+ URLEncoder.encode(item.getValue(), "utf-8") + "&";
				}
			}
			if (buff.isEmpty() == false) {
				buff = buff.substring(0, buff.length() - 1);
			}
		} catch (Exception e) {
			throw new SDKRuntimeException(e.getMessage());
		}

		return buff;
	}

	public static String FormatBizQueryParaMap(HashMap<String, String> paraMap,
			boolean urlencode) throws SDKRuntimeException {

		String buff = "";
		try {
			List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(
					paraMap.entrySet());

			Collections.sort(infoIds,
					new Comparator<Map.Entry<String, String>>() {
						public int compare(Map.Entry<String, String> o1,
								Map.Entry<String, String> o2) {
							return (o1.getKey()).toString().compareTo(
									o2.getKey());
						}
					});

			for (int i = 0; i < infoIds.size(); i++) {
				Map.Entry<String, String> item = infoIds.get(i);
				//System.out.println(item.getKey());
				if (item.getKey() != "") {
					
					String key = item.getKey();
					String val = item.getValue();
					if (urlencode) {
						val = URLEncoder.encode(val, "utf-8");

					}
					buff += key.toLowerCase() + "=" + val + "&";

				}
			}

			if (buff.isEmpty() == false) {
				buff = buff.substring(0, buff.length() - 1);
			}
		} catch (Exception e) {
			throw new SDKRuntimeException(e.getMessage());
		}
		return buff;
	}

	public static boolean IsNumeric(String str) {
		if (str.matches("\d *")) {
			return true;
		} else {
			return false;
		}
	}

	public static String ArrayToXml(HashMap<String, String> arr) {
		String xml = "<xml>";
		
		Iterator<Entry<String, String>> iter = arr.entrySet().iterator();
		while (iter.hasNext()) {
			Entry<String, String> entry = iter.next();
			String key = entry.getKey();
			String val = entry.getValue();
			if (IsNumeric(val)) {
				xml += "<" + key + ">" + val + "</" + key + ">";

			} else
				xml += "<" + key + "><![CDATA[" + val + "]]></" + key + ">";
		}

		xml += "</xml>";
		 try {
			return new String(xml.toString().getBytes(),"ISO8859-1");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}  
		 return "";
	}

}


3.ClientCustomSSL工具类,用于生成sign以及创建微信订单
package com.pay.utils.weixin;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.util.StringUtils;



/**
 * This example demonstrates how to create secure connections with a custom SSL
 * context.
 */
public class ClientCustomSSL {

	 public static String GetBizSign(HashMap<String, String> bizObj)
			throws SDKRuntimeException {
		HashMap<String, String> bizParameters = new HashMap<String, String>();

		List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(
				bizObj.entrySet());
		System.out.println(infoIds);
		Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
			public int compare(Map.Entry<String, String> o1,
					Map.Entry<String, String> o2) {
				return (o1.getKey()).toString().compareTo(o2.getKey());
			}
		});
System.out.println("--------------------");
		System.out.println(infoIds);
		for (int i = 0; i < infoIds.size(); i++) {
			Map.Entry<String, String> item = infoIds.get(i);
			if (item.getKey() != "") {
				bizParameters.put(item.getKey().toLowerCase(), item.getValue());
			}
		}
		//bizParameters.put("key", "12345678123456781234567812345671");
		String bizString = CommonUtil.FormatBizQueryParaMap(bizParameters,
				false);
		bizString += "&key=12345678123456781234567812345671";
		System.out.println("***************");
		
		System.out.println(bizString);

//		return SHA1Util.Sha1(bizString);
		return MD5Util.MD5(bizString);

	}
	/**
	 * 微信创建订单
	 * @param nonceStr
	 * @param orderDescribe
	 * @param orderNo
	 * @param price
	 * @param timeStart
	 * @param timeExpire
	 * @return
	 * @throws SDKRuntimeException
	 */
	 public static String CreateNativePackage(String nonceStr,String orderDescribe,String orderNo,String price,String timeStart,String timeExpire) throws SDKRuntimeException {
		HashMap<String, String> nativeObj = new HashMap<String, String>();
		nativeObj.put("appid", "见公众账号"); 			                //公众账号Id
		nativeObj.put("mch_id", "见邮件");		  			//商户号
		nativeObj.put("nonce_str", nonceStr);   			        //随机字符串
		nativeObj.put("body", orderDescribe);			  		//商品描述
		nativeObj.put("attach", "tradeno");			  		//附加数据
		nativeObj.put("out_trade_no", orderNo); 		                //商户订单号(全局唯一)
		nativeObj.put("total_fee", price);			 		//总金额(单位为分,不能带小数点)
		nativeObj.put("spbill_create_ip","192.168.0.144");		        //终端Ip
		nativeObj.put("time_start", timeStart);			                //交易起始时间
		nativeObj.put("time_expire", timeExpire);			        //交易结束时间
		nativeObj.put("notify_url",	CustomizedPropertyPlaceholderConfigurer.getContextProperty("wxurl")+"/weixin_callback/weixinCallback/init.action");					                                //回调通知地址
		nativeObj.put("trade_type", "NATIVE");					//交易类型
		
		String sign = GetBizSign(nativeObj);
		
		nativeObj.put("sign", sign.toUpperCase());
		
		return CommonUtil.ArrayToXml(nativeObj);

	}  	 
          /**
* 微信订单支付查询
* @param nonceStr
* @param orderDescribe
* @param orderNo
* @param price
* @param timeStart
* @param timeExpire
* @return
* @throws SDKRuntimeException
*/
public static String SearchNativePackage(String transactionId,String outTradeNo,String nonceStr) throws SDKRuntimeException {
HashMap<String, String> nativeObj = new HashMap<String, String>();
nativeObj.put("appid", "见公众共账号"); //公众账号Id
nativeObj.put("mch_id", "见邮件");//商户号
nativeObj.put("nonce_str", nonceStr);//随机字符串
if(!StringUtils.isEmpty(transactionId)){
nativeObj.put("transaction_id", transactionId); 
}
if(!StringUtils.isEmpty(outTradeNo)){
nativeObj.put("out_trade_no", outTradeNo);//随机字符串
}
String sign = GetBizSign(nativeObj);
nativeObj.put("sign", sign.toUpperCase());  
return CommonUtil.ArrayToXml(nativeObj);
 /**
* 微信退款
* @param outTradeNo
* @param outRefundNo
 * @param totalFee
* @param refundFee
* @return
* @throws SDKRuntimeException
*/
public static String RefundNativePackage(String outTradeNo,String outRefundNo,String totalFee,String refundFee,String nonceStr) throws SDKRuntimeException {
HashMap<String, String> nativeObj = new HashMap<String, String>();
nativeObj.put("appid", "见公众账号");//公众账号Id
nativeObj.put("mch_id", "见邮件");//商户号
nativeObj.put("nonce_str", nonceStr);//随机字符串
nativeObj.put("out_trade_no", outTradeNo);//商户订单号(全局唯一)
nativeObj.put("out_refund_no", outRefundNo);//商户退款单号(全局唯一)
nativeObj.put("total_fee", totalFee);//总金额(单位为分,不能带小数点)
nativeObj.put("refund_fee", refundFee);//退款金额(单位为分,不能带小数点)
nativeObj.put("op_user_id", "邮件");
String sign = GetBizSign(nativeObj);
nativeObj.put("sign", sign.toUpperCase());
return CommonUtil.ArrayToXml(nativeObj);
}

/**
* 微信待支付
 * @param nonceStr
* @param orderDescribe
* @param orderNo
* @param price
* @param timeStart
* @param timeExpire
* @return
* @throws SDKRuntimeException
*/
public static String CreateJsApiPackage(String nonceStr,String orderDescribe,String orderNo,String price,String timeStart,String timeExpire,String openId) throws SDKRuntimeException {
HashMap<String, String> nativeObj = new HashMap<String, String>();
nativeObj.put("appid", "见公众账号");//公众账号Id
nativeObj.put("openid", openId);//公众账号Id
nativeObj.put("mch_id", "见邮件")//商户号
nativeObj.put("nonce_str", nonceStr);//随机字符串
nativeObj.put("body", orderDescribe);//商品描述
nativeObj.put("attach", "tradeno");//附加数据
nativeObj.put("out_trade_no", orderNo);//商户订单号(全局唯一)
nativeObj.put("total_fee", price);//总金额(单位为分,不能带小数点)
nativeObj.put("spbill_create_ip","192.168.0.144");//终端Ip
nativeObj.put("time_start", timeStart);//交易起始时间
nativeObj.put("time_expire", timeExpire)//交易结束时间
nativeObj.put("notify_url",CustomizedPropertyPlaceholderConfigurer.getContextProperty("wxurl")+"/weixin_callback/weixinCallback/init.action");//通知地址
nativeObj.put("trade_type", "JSAPI");//交易类型
String sign = GetBizSign(nativeObj);
nativeObj.put("sign", sign.toUpperCase());
return CommonUtil.ArrayToXml(nativeObj);
}
/**
* 微信关闭订单
* @param nonceStr
* @param orderDescribe
* @param orderNo
* @param price
* @param timeStart
* @param timeExpire
* @param openId
* @return
* @throws SDKRuntimeException
*/
public static String CreateCloseOrder(String outTradeNo,String nonceStr) throws SDKRuntimeException {
HashMap<String, String> nativeObj = new HashMap<String, String>();
nativeObj.put("appid", "见公众账号");//公众账号Id
nativeObj.put("mch_id", "见邮件");//商户号
nativeObj.put("out_trade_no", outTradeNo);//商户订单号(全局唯一)
nativeObj.put("nonce_str", nonceStr);//随机字符串
 String sign = GetBizSign(nativeObj);
nativeObj.put("sign", sign.toUpperCase());
 return CommonUtil.ArrayToXml(nativeObj);
}
}

4.调用微信支付接口

package com.pay.controller.weixin;

import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

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.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.pay.bo.PayHist;
import com.pay.constants.PayHistoryPayStatus;
import com.pay.constants.PayHistoryPayType;
import com.pay.service.WeiXinPayService;
import com.pay.utils.weixin.ClientCustomSSL;
import com.pay.utils.weixin.CloseWeiXinOrderUtils;
import com.pay.utils.weixin.CustomizedPropertyPlaceholderConfigurer;


@RestController
@RequestMapping("/Pay")
public class WeiXinPayController {
	
	
	@Autowired
	WeiXinPayService weiXinPayService;
	private static long standardTime = 1662652800000L;
	
	/**
	 * 返回生成二维码的url
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value="/getUrl",method=RequestMethod.POST)
	@ResponseStatus(HttpStatus.OK)
	public Object getUrl(HttpServletResponse response,@RequestBody String body){
		try{
			JSONObject jsonO = JSONObject.fromObject(body);
			PayHist ph = null;
//			List<Map<String,Object>> td = weiXinPayService.getTrade(orderNo);
			Date dt = new Date();
			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
			String nonceStr = sdf.format(dt).toString();
			Date now = new Date();
			
			String tradePayNo = jsonO.get("orderNo").toString()+String.format("%10d",standardTime - now.getTime()).substring(0, 10);
			System.out.println("订单标号orderNo======="+jsonO.get("orderNo").toString());
			System.out.println("10位随机数======="+String.format("%10d",standardTime - now.getTime()).substring(0, 10));
			String price = Math.round(Float.valueOf(jsonO.get("price").toString())*100)+"";
			Long timeExpireStrOld = dt.getTime();
			Long timeNew = Long.parseLong(CustomizedPropertyPlaceholderConfigurer.getContextProperty("weixin.send2finish.overtime").toString());
			Long timeExpireNew = timeExpireStrOld+timeNew;
			Date dtTimeExpire = new Date(timeExpireNew);
			SimpleDateFormat dtSdf = new SimpleDateFormat("yyyyMMddHHmmss");
			String timeExpire = dtSdf.format(dtTimeExpire).toString();
			System.out.println("nonceStr=="+nonceStr);
			System.out.println("orderNo=="+jsonO.get("orderNo").toString());
			System.out.println("price=="+price);
			System.out.println("timeStart=="+nonceStr);
			System.out.println("timeExpire=="+timeExpire);
			
			
			JSONObject result = (JSONObject) setUrl(nonceStr,"订单",tradePayNo,price,nonceStr,timeExpire);
			
			if(result.get("status").toString().equals("success")){
				ph = new PayHist();
				ph.setTradePayUrl(result.getString("weixinPayUrl"));//此字段为支付链接,可以此链接生成二维码扫码支付
				ph.setPayTradeNo(jsonO.get("orderNo").toString());
				ph.setTradePayNo(tradePayNo);
				ph.setPayStatus(PayHistoryPayStatus.WECHAT_PAY_STATUS_WAIT);
				ph.setPayType(PayHistoryPayType.WECHAT);
				ph.setAppKey(jsonO.getString("appKey").toString());
				ph.setPayAmount(price);
				
				result.put("payTradeNo", ph.getPayTradeNo());
				result.put("tradePayNo", ph.getTradePayNo());
				result.put("payStatus", ph.getPayStatus());
				result.put("payType", ph.getPayType());
				
			}			
			return result;
			
			
		}catch(Exception e){
			e.printStackTrace();
			JSONObject result = new JSONObject();
			result.put("status","error");
			result.put("msg",e.getMessage());
//			return result.toString();
		}
		return null;
	
		
	}

	public Object setUrl(String nonceStr,String orderDescribe,String orderNo,String price,String timeStart,String timeExpire) {
		try{
			
			KeyStore keyStore = KeyStore.getInstance("PKCS12");
			FileInputStream instream = new FileInputStream(new File(微信证书绝对路径));
			try {
				keyStore.load(instream, "商户ID".toCharArray());
			}finally {
				instream.close();
			}

			// Trust own CA and all self-signed certs
			SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore,<span style="font-family: Arial, Helvetica, sans-serif;">商户ID</span>.toCharArray()).build();
			// Allow TLSv1 protocol only
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
					sslcontext, new String[] { "TLSv1" }, null,
					SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
			CloseableHttpClient httpclient = HttpClients.custom()
					.setSSLSocketFactory(sslsf).build();
			// HttpGet httpget = new
			// HttpGet("https://api.mch.weixin.qq.com/secapi/pay/refund");
			HttpPost httppost = new HttpPost(
					"https://api.mch.weixin.qq.com/pay/unifiedorder");
			
			String xml = ClientCustomSSL.CreateNativePackage(nonceStr,orderDescribe,orderNo,price,timeStart,timeExpire);
			try {

				
				StringEntity se = new StringEntity(xml);
				
				httppost.setEntity(se);

				System.out.println("executing request" + httppost.getRequestLine());

				CloseableHttpResponse responseEntry = httpclient.execute(httppost);
				try {
					HttpEntity entity = responseEntry.getEntity();

					System.out.println("----------------------------------------");
					System.out.println(responseEntry.getStatusLine());
					if (entity != null) {
						System.out.println("Response content length: "
								+ entity.getContentLength());
				/*	BufferedReader bufferedReader = new BufferedReader(
								new InputStreamReader(entity.getContent()));
						String text;
						while ((text = bufferedReader.readLine()) != null) {
							System.out.println("======="+text);
						}*/		
												
						SAXReader saxReader = new SAXReader();
						Document document = saxReader.read(entity.getContent());
						Element rootElt = document.getRootElement();
						System.out.println("根节点:" + rootElt.getName());
						System.out.println("==="+rootElt.elementText("result_code"));
						System.out.println("==="+rootElt.elementText("return_msg"));
						String resultCode = rootElt.elementText("result_code");
						JSONObject result = new JSONObject();				
						
						Document documentXml =DocumentHelper.parseText(xml);
						Element rootEltXml = documentXml.getRootElement();
						
						if(resultCode.equals("SUCCESS")){
							System.out.println("=================prepay_id===================="+ rootElt.elementText("prepay_id"));
							System.out.println("=================sign===================="+ rootEltXml.elementText("sign"));
							result.put("weixinPayUrl",  rootElt.elementText("code_url"));
							result.put("prepayId",  rootElt.elementText("prepay_id"));
							result.put("status","success");
							result.put("msg","success");
						}else{
							result.put("status","false");
							result.put("msg",rootElt.elementText("err_code_des"));
						}
						
						
						return result;

					}
					EntityUtils.consume(entity);
				}
				finally {
					responseEntry.close();
				}
			}
			finally {
				httpclient.close();
			}
			return null;
			
			
		}catch(Exception e){
			e.printStackTrace();
			JSONObject result = new JSONObject();
			result.put("status","error");
			result.put("msg",e.getMessage());
			return result;
		}
	}
	
}

httpclient  jar包下载地址:http://download.csdn.net/detail/wangxuewei111/8460181

json jar包现在地址:http://download.csdn.net/detail/wangxuewei111/8460185


 
  



版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/wangxuewei111/article/details/43954857
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-06-13 11:00:48
  • 阅读 ( 545 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢