app集成微信支付服务器端开发(java)

一、微信支付太坑爹,废话不说了,下面是我的服务端微信支付开发过程和代码记录

二、首先去微信申请账户,这里有两个平台 

1、微信公众平台
2、微信开放平台(https://open.weixin.qq.com)这里选择第二个

三、账户开通、开发者认证之后就可以进行微信支付开发了

1、微信统一下单接口调用获取预支付id
  1. /** 
  2.      * 获取微信支付所需信息(统一下单接口调用) 
  3.      * @param backURL 
  4.      * @param mDealerOrderEntity 
  5.      * @param mCarInfoEntity 
  6.      * @return 
  7.      * @throws JSONException  
  8.      * @throws IOException  
  9.      * @throws JDOMException  
  10.      */  
  11.     public Map<String, String> getWechatOrderInfo(String notifyUrl, MDealerOrderEntity mDealerOrderEntity, String body, HttpServletRequest request, HttpServletResponse response) throws Exception {  
  12.         Map<String, String> resultMap = new HashMap<String, String>();  
  13.         //生成payPreId  
  14.         Map<String, String> payPreIdMap = WechatUtil.getPayPreId(mDealerOrderEntity.getGoodorderno(), body, notifyUrl, request.getRemoteAddr(), String.valueOf((int)(mDealerOrderEntity.getMoney()*100)));  
  15.         String prePayId = payPreIdMap.get("prepay_id");  
  16.         if(StringUtils.isNotEmpty(prePayId)) {  
  17.             //生成调用微信APP参数  
  18.             resultMap =  WechatUtil.genPayReq(prePayId);  
  19.         }  
  20.         return resultMap;  
  21.     }  

此方法返回的数据如下

{
        "appid": "123132131",
        "noncestr": "416e5cf0acb7e553a880b7647903da6e",
        "packageValue ": "Sign=WXPay",
        "partnerid ": "1276000000",
        "prepayid ": "wx2015101611341514a3cbbbf90572184370",
        "timestamp ": "1444966497",
        "sign": "1DD72B07607B0B41D2827954150D89E9" 
    }
2、服务器端接受微信支付结果通知
  1. /** 
  2.      * 处理微信支付通知 
  3.      * @param request 
  4.      * @return 
  5.      * @throws Exception 
  6.      */  
  7.     public String saveWechatNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  8.         Map<String, String> noticeMap = XMLUtil.parseXml(request);  
  9.         String transactionId = noticeMap.get("transaction_id");  
  10.         MWechatInfoEntity wechatInfoEntity = this.findEntityByProperty(MWechatInfoEntity.class"transactionId", transactionId);  
  11.         //如果wechatInfoEntity存在,说明请求已经处理过,直接返回  
  12.         if(wechatInfoEntity != null) {  
  13.             return "SUCCESS";  
  14.         }  
  15.         String sign = noticeMap.get("sign");  
  16.         noticeMap.remove("sign");  
  17.         // 验签通过  
  18.         if (WechatUtil.getSignVeryfy(noticeMap, sign)) {  
  19.             // 通信成功此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断  
  20.             if ("SUCCESS".equals(noticeMap.get("return_code"))) {  
  21.                 // 交易成功  
  22.                 if ("SUCCESS".equals(noticeMap.get("result_code"))) {  
  23.                     // 商户订单号  
  24.                     String goodorderno = noticeMap.get("out_trade_no");  
  25.                     MDealerOrderEntity mDealerOrderEntity = this.findEntityByProperty(MDealerOrderEntity.class"goodorderno", goodorderno);  
  26.                     MCarInfoEntity mCarInfoEntity = this.get(MCarInfoEntity.class, mDealerOrderEntity.getCarid());  
  27.                     // 订单更新时间  
  28.                     mDealerOrderEntity.setUpdatetime(new Date());  
  29.                     // ------------------------------  
  30.                     // 处理业务开始  
  31.                     // ------------------------------  
  32.                     // 这里写自己业务相关  
  33.                     // ------------------------------  
  34.                     // 处理业务完毕  
  35.                     // ------------------------------  
  36.                     noticeMap.put("sign", sign);  
  37.                     this.common99Service.saveWechatInfo(noticeMap, mDealerOrderEntity.getId());  
  38.                 } else {  
  39.                     // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。  
  40.                     System.out.println("查询验证签名失败或业务错误");  
  41.                     System.out.println("retcode:" + noticeMap.get("retcode") + " retmsg:" + noticeMap.get("retmsg"));  
  42.                 }  
  43.                 return "SUCCESS";  
  44.             } else {  
  45.                 System.out.println("后台调用通信失败");  
  46.             }  
  47.             return "SUCCESS";  
  48.         } else {  
  49.             System.out.println("通知签名验证失败");  
  50.         }  
  51.         return null;  
  52.     }  
3、上面代码用到的工具方法都在WechatUtil.java工具类中
  1. package com.jim.iweb.haocheok.tenpay.util;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.URISyntaxException;  
  5. import java.util.ArrayList;  
  6. import java.util.Collections;  
  7. import java.util.HashMap;  
  8. import java.util.LinkedList;  
  9. import java.util.List;  
  10. import java.util.Map;  
  11. import java.util.Random;  
  12.   
  13. import org.apache.commons.httpclient.HttpStatus;  
  14. import org.apache.http.NameValuePair;  
  15. import org.apache.http.client.config.RequestConfig;  
  16. import org.apache.http.client.methods.CloseableHttpResponse;  
  17. import org.apache.http.client.methods.HttpPost;  
  18. import org.apache.http.client.utils.URIBuilder;  
  19. import org.apache.http.entity.StringEntity;  
  20. import org.apache.http.impl.client.CloseableHttpClient;  
  21. import org.apache.http.impl.client.HttpClients;  
  22. import org.apache.http.message.BasicNameValuePair;  
  23. import org.apache.http.util.EntityUtils;  
  24. import org.jdom2.JDOMException;  
  25. import org.slf4j.Logger;  
  26. import org.slf4j.LoggerFactory;  
  27.   
  28. public class WechatUtil {  
  29.   
  30.     private static Logger logger = LoggerFactory.getLogger(WechatUtil.class);  
  31.     public static final String TAG = "Wechat.Util";  
  32.     private static final int timeout = 5000;  
  33.   
  34.     public static byte[] httpPost(String url, String entity) throws URISyntaxException, IOException {  
  35.         if (url == null || url.length() == 0) {  
  36.             logger.info(TAG, "httpPost, url is null");  
  37.             return null;  
  38.         }  
  39.         CloseableHttpClient httpClient = HttpClients.createDefault();  
  40.         URIBuilder uriBuilder = new URIBuilder(url);  
  41.         HttpPost httpPost = new HttpPost(uriBuilder.build());  
  42.         RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeout).setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build();  
  43.         httpPost.setConfig(requestConfig);  
  44.         // 避免汉字乱码导致请求失败,  
  45.         httpPost.setEntity(new StringEntity(entity, "UTF-8"));  
  46.         CloseableHttpResponse resp = null;  
  47.         try {  
  48.             resp = httpClient.execute(httpPost);  
  49.             if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {  
  50.                 logger.info(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode());  
  51.                 return null;  
  52.             }  
  53.             return EntityUtils.toByteArray(resp.getEntity());  
  54.         } catch (Exception e) {  
  55.             logger.info(TAG, "httpPost exception, e = " + e.getMessage());  
  56.             e.printStackTrace();  
  57.             return null;  
  58.         } finally {  
  59.             if (httpClient != null) {  
  60.                 httpClient.close();  
  61.             }  
  62.             if (resp != null) {  
  63.                 resp.close();  
  64.             }  
  65.         }  
  66.     }  
  67.   
  68.     /** 
  69.      * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串 
  70.      *  
  71.      * @param params 
  72.      *            需要排序并参与字符拼接的参数组 
  73.      * @return 拼接后字符串 
  74.      */  
  75.     public static String createLinkString(Map<String, String> params) {  
  76.   
  77.         List<String> keys = new ArrayList<String>(params.keySet());  
  78.         Collections.sort(keys);  
  79.   
  80.         String prestr = "";  
  81.   
  82.         for (int i = 0; i < keys.size(); i++) {  
  83.             String key = keys.get(i);  
  84.             String value = params.get(key);  
  85.   
  86.             if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符  
  87.                 prestr = prestr + key + "=" + value;  
  88.             } else {  
  89.                 prestr = prestr + key + "=" + value + "&";  
  90.             }  
  91.         }  
  92.   
  93.         return prestr;  
  94.     }  
  95.   
  96.     /** 
  97.      * 根据反馈回来的信息,生成签名结果 
  98.      *  
  99.      * @param Params 
  100.      *            通知返回来的参数数组 
  101.      * @param sign 
  102.      *            比对的签名结果 
  103.      * @return 生成的签名结果 
  104.      */  
  105.     public static boolean getSignVeryfy(Map<String, String> Params, String sign) {  
  106.         // 过滤空值、sign与sign_type参数  
  107.         // Map<String, String> sParaNew = AlipayCore.paraFilter(Params);  
  108.         // 获取待签名字符串  
  109.         String preSignStr = createLinkString(Params);  
  110.         preSignStr += "&key=" + ConstantUtil.API_KEY;  
  111.         // 获得签名验证结果  
  112.         String resultSign = MD5.getMessageDigest(preSignStr.getBytes()).toUpperCase();  
  113.         // String resultSign = MD5Util.MD5Encode(preSignStr.toString(), "UTF-8").toLowerCase();  
  114.         if (sign.equals(resultSign)) {  
  115.             return true;  
  116.         } else {  
  117.             return false;  
  118.         }  
  119.     }  
  120.   
  121.     /** 
  122.      * 装配xml,生成请求prePayId所需参数 
  123.      *  
  124.      * @param params 
  125.      * @return 
  126.      */  
  127.     public static String toXml(List<NameValuePair> params) {  
  128.         StringBuilder sb = new StringBuilder();  
  129.         sb.append("<xml>");  
  130.         for (int i = 0; i < params.size(); i++) {  
  131.             sb.append("<" + params.get(i).getName() + ">");  
  132.             sb.append(params.get(i).getValue());  
  133.             sb.append("</" + params.get(i).getName() + ">");  
  134.         }  
  135.         sb.append("</xml>");  
  136.         return sb.toString();  
  137.     }  
  138.   
  139.     /** 
  140.      * 生成签名 
  141.      */  
  142.     public static String genPackageSign(List<NameValuePair> params) {  
  143.         StringBuilder sb = new StringBuilder();  
  144.         for (int i = 0; i < params.size(); i++) {  
  145.             sb.append(params.get(i).getName());  
  146.             sb.append('=');  
  147.             sb.append(params.get(i).getValue());  
  148.             sb.append('&');  
  149.         }  
  150.         sb.append("key=");  
  151.         sb.append(ConstantUtil.API_KEY);  
  152.         String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();  
  153.         return packageSign;  
  154.     }  
  155.   
  156.     /** 
  157.      *  
  158.      * @param goodOrderNo 
  159.      * @param body 
  160.      * @param noticeUrl 
  161.      * @param ip 
  162.      * @param totalFee 
  163.      * @return 
  164.      */  
  165.     public static String genProductArgs(String goodOrderNo, String body, String noticeUrl, String ip, String totalFee) {  
  166.         StringBuffer xml = new StringBuffer();  
  167.         try {  
  168.             String nonceStr = getNonceStr();  
  169.             xml.append("</xml>");  
  170.             List<NameValuePair> packageParams = new LinkedList<NameValuePair>();  
  171.             packageParams.add(new BasicNameValuePair("appid", ConstantUtil.APP_ID));  
  172.             packageParams.add(new BasicNameValuePair("body", body));  
  173.             packageParams.add(new BasicNameValuePair("mch_id", ConstantUtil.MCH_ID));  
  174.             packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));  
  175.             packageParams.add(new BasicNameValuePair("notify_url", noticeUrl));  
  176.             packageParams.add(new BasicNameValuePair("out_trade_no", goodOrderNo));  
  177.             packageParams.add(new BasicNameValuePair("spbill_create_ip", ip));  
  178.             packageParams.add(new BasicNameValuePair("total_fee", totalFee));  
  179.             packageParams.add(new BasicNameValuePair("trade_type""APP"));  
  180.             String sign = genPackageSign(packageParams);  
  181.             packageParams.add(new BasicNameValuePair("sign", sign));  
  182.             String xmlstring = toXml(packageParams);  
  183.             return xmlstring;  
  184.         } catch (Exception e) {  
  185.             logger.info("genProductArgs fail, ex = " + e.getMessage());  
  186.             return null;  
  187.         }  
  188.     }  
  189.   
  190.     /** 
  191.      * 生成app支付签名 
  192.      *  
  193.      * @param params 
  194.      * @return 
  195.      */  
  196.     public static String genAppSign(List<NameValuePair> params) {  
  197.         StringBuilder sb = new StringBuilder();  
  198.         for (int i = 0; i < params.size(); i++) {  
  199.             sb.append(params.get(i).getName());  
  200.             sb.append('=');  
  201.             sb.append(params.get(i).getValue());  
  202.             sb.append('&');  
  203.         }  
  204.         sb.append("key=");  
  205.         sb.append(ConstantUtil.API_KEY);  
  206.         String appSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();  
  207.         logger.info("orion", appSign);  
  208.         return appSign;  
  209.     }  
  210.   
  211.     /** 
  212.      * 生成调用微信app支付所需参数 
  213.      *  
  214.      * @param prepayId 
  215.      * @return 
  216.      */  
  217.     public static Map<String, String> genPayReq(String prepayId) {  
  218.         Map<String, String> resultMap = new HashMap<String, String>();  
  219.         String timeStamp = getTimeStamp();  
  220.         String nonceStr = getNonceStr();  
  221.         List<NameValuePair> signParams = new LinkedList<NameValuePair>();  
  222.         signParams.add(new BasicNameValuePair("appid", ConstantUtil.APP_ID));  
  223.         signParams.add(new BasicNameValuePair("noncestr", nonceStr));  
  224.         signParams.add(new BasicNameValuePair("package""Sign=WXPay"));  
  225.         signParams.add(new BasicNameValuePair("partnerid", ConstantUtil.MCH_ID));  
  226.         signParams.add(new BasicNameValuePair("prepayid", prepayId));  
  227.         signParams.add(new BasicNameValuePair("timestamp", timeStamp));  
  228.         String sign = genAppSign(signParams);  
  229.         resultMap.put("appid", ConstantUtil.APP_ID);  
  230.         resultMap.put("noncestr", nonceStr);  
  231.         resultMap.put("packageValue""Sign=WXPay");  
  232.         resultMap.put("partnerid", ConstantUtil.MCH_ID);  
  233.         resultMap.put("prepayid", prepayId);  
  234.         resultMap.put("timestamp", timeStamp);  
  235.         resultMap.put("sign", sign);  
  236.         return resultMap;  
  237.     }  
  238.   
  239.     /** 
  240.      * 微信支付生成预支付订单 
  241.      *  
  242.      * @throws IOException 
  243.      * @throws JDOMException 
  244.      */  
  245.     public static Map<String, String> getPayPreId(String goodOrderNo, String body, String noticeUrl, String ip, String totalFee) throws Exception {  
  246.         String paramsXml = genProductArgs(goodOrderNo, body, noticeUrl, ip, totalFee);  
  247.         logger.info("orion", paramsXml);  
  248.         byte[] buf = WechatUtil.httpPost(ConstantUtil.URL, paramsXml);  
  249.         String contentXml = new String(buf);  
  250.         Map<String, String> resultMap = XMLUtil.doXMLParse(contentXml);  
  251.         return resultMap;  
  252.     }  
  253.   
  254.     public static String getNonceStr() {  
  255.         Random random = new Random();  
  256.         return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());  
  257.     }  
  258.   
  259.     public static String getTimeStamp() {  
  260.         return String.valueOf(System.currentTimeMillis() / 1000);  
  261.     }  
  262. }  
4、下面是用到的配置类
  1. package com.jim.iweb.haocheok.tenpay.util;  
  2.   
  3. public class ConstantUtil {  
  4.     /** 
  5.      * 商家可以考虑读取配置文件 
  6.      */  
  7.       
  8.     //初始化  
  9.     public static String APP_ID = "wxsdfsdfsf5fdbc";//微信开发平台应用id  
  10.     public static String APP_SECRET = "aab95csdfsdfsffdcsdfsfs0df34";//应用对应的凭证  
  11.     //商户号  
  12.     public static String MCH_ID = "1233312201";  
  13.     public static String PARTNER = "1233312201";//财付通商户号  
  14.     public static String API_KEY = "KgjyjirmjajdfjsdjfsjffVpT6RMbrB";  
  15.     public static String PARTNER_KEY = "KgjyjirmjajdfjsdjfsjffVpT6RMbrB";//商户号对应的密钥  
  16.     public static String URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//获取预支付id的接口url  
  17. }  
5、xml 解析工具类
  1. package com.jim.iweb.haocheok.tenpay.util;  
  2.   
  3. public class ConstantUtil {  
  4.     /** 
  5.      * 商家可以考虑读取配置文件 
  6.      */  
  7.       
  8.     //初始化  
  9.     public static String APP_ID = "wxsdfsdfsf5fdbc";//微信开发平台应用id  
  10.     public static String APP_SECRET = "aab95csdfsdfsffdcsdfsfs0df34";//应用对应的凭证  
  11.     //商户号  
  12.     public static String MCH_ID = "1233312201";  
  13.     public static String PARTNER = "1233312201";//财付通商户号  
  14.     public static String API_KEY = "KgjyjirmjajdfjsdjfsjffVpT6RMbrB";  
  15.     public static String PARTNER_KEY = "KgjyjirmjajdfjsdjfsjffVpT6RMbrB";//商户号对应的密钥  
  16.     public static String URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//获取预支付id的接口url  
  17. }  
5、xml 解析工具类
  1. package com.jim.iweb.haocheok.tenpay.util;  
  2.   
  3. import java.io.ByteArrayInputStream;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.util.HashMap;  
  7. import java.util.Iterator;  
  8. import java.util.List;  
  9. import java.util.Map;  
  10.   
  11. import javax.servlet.http.HttpServletRequest;  
  12.   
  13. import org.dom4j.io.SAXReader;  
  14. import org.jdom2.Document;  
  15. import org.jdom2.Element;  
  16. import org.jdom2.JDOMException;  
  17. import org.jdom2.input.SAXBuilder;  
  18.   
  19. /** 
  20.  * xml工具类 
  21.  *  
  22.  * @author miklchen 
  23.  * 
  24.  */  
  25. public class XMLUtil {  
  26.   
  27.     /** 
  28.      * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 
  29.      *  
  30.      * @param strxml 
  31.      * @return 
  32.      * @throws JDOMException 
  33.      * @throws IOException 
  34.      */  
  35.     public static Map doXMLParse(String strxml) throws JDOMException, IOException {  
  36.         strxml = strxml.replaceFirst("encoding=\".*\"""encoding=\"UTF-8\"");  
  37.   
  38.         if (null == strxml || "".equals(strxml)) {  
  39.             return null;  
  40.         }  
  41.   
  42.         Map m = new HashMap();  
  43.   
  44.         InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));  
  45.         SAXBuilder builder = new SAXBuilder();  
  46.         Document doc = builder.build(in);  
  47.         Element root = doc.getRootElement();  
  48.         List list = root.getChildren();  
  49.         Iterator it = list.iterator();  
  50.         while (it.hasNext()) {  
  51.             Element e = (Element) it.next();  
  52.             String k = e.getName();  
  53.             String v = "";  
  54.             List children = e.getChildren();  
  55.             if (children.isEmpty()) {  
  56.                 v = e.getTextNormalize();  
  57.             } else {  
  58.                 v = XMLUtil.getChildrenText(children);  
  59.             }  
  60.   
  61.             m.put(k, v);  
  62.         }  
  63.   
  64.         // 关闭流  
  65.         in.close();  
  66.   
  67.         return m;  
  68.     }  
  69.   
  70.     /** 
  71.      * 获取子结点的xml 
  72.      *  
  73.      * @param children 
  74.      * @return String 
  75.      */  
  76.     public static String getChildrenText(List children) {  
  77.         StringBuffer sb = new StringBuffer();  
  78.         if (!children.isEmpty()) {  
  79.             Iterator it = children.iterator();  
  80.             while (it.hasNext()) {  
  81.                 Element e = (Element) it.next();  
  82.                 String name = e.getName();  
  83.                 String value = e.getTextNormalize();  
  84.                 List list = e.getChildren();  
  85.                 sb.append("<" + name + ">");  
  86.                 if (!list.isEmpty()) {  
  87.                     sb.append(XMLUtil.getChildrenText(list));  
  88.                 }  
  89.                 sb.append(value);  
  90.                 sb.append("</" + name + ">");  
  91.             }  
  92.         }  
  93.   
  94.         return sb.toString();  
  95.     }  
  96.   
  97.     /** 
  98.      * 将requestxml通知结果转出啊成map 
  99.      * @param request 
  100.      * @return 
  101.      * @throws Exception 
  102.      */  
  103.     public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {  
  104.         // 解析结果存储在HashMap  
  105.         Map<String, String> map = new HashMap<String, String>();  
  106.         InputStream inputStream = request.getInputStream();  
  107.         // 读取输入流  
  108.         SAXReader reader = new SAXReader();  
  109.         org.dom4j.Document document = reader.read(inputStream);  
  110.         // 得到xml根元素  
  111.         org.dom4j.Element root = document.getRootElement();  
  112.         // 得到根元素的所有子节点  
  113.         List<org.dom4j.Element> elementList = root.elements();  
  114.         // 遍历所有子节点  
  115.         for (org.dom4j.Element e : elementList)  
  116.             map.put(e.getName(), e.getText());  
  117.         // 释放资源  
  118.         inputStream.close();  
  119.         inputStream = null;  
  120.         return map;  
  121.     }  
  122.   
  123. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值