微信支付java版本之Native付款

来源:互联网 发布:双子星股票交易软件 编辑:程序博客网 时间:2024/05/01 15:58

最近工作中接触到一些关于微信支付方面的东西,看到给的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 + ">";} elsexml += "<" + key + "><![CDATA[" + val + "]]></" + key + ">";}xml += "</xml>"; try {return new String(xml.toString().getBytes(),"ISO8859-1");} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.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", "见公众账号");                 //公众账号IdnativeObj.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");        //终端IpnativeObj.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", "见公众共账号"); //公众账号IdnativeObj.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", "见公众账号");//公众账号IdnativeObj.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", "见公众账号");//公众账号IdnativeObj.put("openid", openId);//公众账号IdnativeObj.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");//终端IpnativeObj.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", "见公众账号");//公众账号IdnativeObj.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 {@AutowiredWeiXinPayService 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 certsSSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore,<span style="font-family: Arial, Helvetica, sans-serif;">商户ID</span>.toCharArray()).build();// Allow TLSv1 protocol onlySSLConnectionSocketFactory 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





1 0