吐槽一下
支付項目采用springMvc+Dubbo架構實現,只對外提供接口。
話說,為什么微信支付比支付寶來的晚了那么一點,一句話,那一陣挺忙的,然后就沒有時間整理,最近做完支付寶支付,順便也把微信支付的也整理一下。
這里再吐槽一下,微信支付的DEMO基本為零,很多代碼都是從網上查找的(也可能我么有仔細找API)。
前期醞釀准備
掃碼支付,目前來說個人是不可以申請的,包括現在支付寶的即時到帳個人相關業務也取消了。所以這里必須有一個微信支付商戶平台,具體怎么申請的,我也不清楚,只是拿來用的。
商戶平台是要配合綁定微信公眾賬號使用的,具體操作申請下來已經綁定了,這里你也只管用就是了。
什么是掃碼支付?
場景介紹
用戶掃描商戶展示在各種場景的二維碼進行支付。
步驟1:商戶根據微信支付的規則,為不同商品生成不同的二維碼(如圖6.1),展示在各種場景,用於用戶掃描購買。
步驟2:用戶使用微信“掃一掃”(如圖6.2)掃描二維碼后,獲取商品支付信息,引導用戶完成支付(如圖6.3)。


支付二維碼
圖6.1 支付二維碼
打開微信掃一掃二維碼
圖6.2 打開微信掃一掃二維碼
確認支付頁面
圖6.3 確認支付頁面
步驟(3):用戶確認支付,輸入支付密碼(如圖6.4)。
步驟(4):支付完成后會提示用戶支付成功(如圖6.5),商戶后台得到支付成功的通知,然后進行發貨處理。
用戶確認支付,輸入密碼
圖6.4 用戶確認支付,輸入密碼
支付成功提示
圖6.5 支付成功提示

如何集成到項目中去?
ConfigUtil參數配置:
import java.util.Map;import java.util.ResourceBundle;import java.util.SortedMap;import java.util.TreeMap;/*** 相關配置參數* 創建者 張志朋* 創建時間 2016年9月28日**/public class ConfigUtil {/*** 服務號相關信息*/public final static String APP_ID = "2016";//服務號的應用IDpublic final static String APP_SECRET = "2016";//服務號的應用密鑰public final static String TOKEN = "weixinCourse";//服務號的配置tokenpublic final static String MCH_ID = "2016";//商戶號public final static String API_KEY = "2016";//API密鑰public final static String SIGN_TYPE = "MD5";//簽名加密方式public final static String CERT_PATH = "apiclient_cert.p12";//微信支付證書存放路徑地址static ResourceBundle resource = ResourceBundle.getBundle("config");//微信支付統一接口的回調actionpublic final static String NOTIFY_URL = resource.getString("WEIXIN_NOTIFY_URL");/*** 微信基礎接口地址*///獲取token接口(GET)public final static String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";//oauth2授權接口(GET)public final static String OAUTH2_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";//刷新access_token接口(GET)public final static String REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";// 菜單創建接口(POST)public final static String MENU_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";// 菜單查詢(GET)public final static String MENU_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN";// 菜單刪除(GET)public final static String MENU_DELETE_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";/*** 微信支付接口地址*///微信支付統一接口(POST)public final static String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信退款接口(POST)public final static String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";//訂單查詢接口(POST)public final static String CHECK_ORDER_URL = "https://api.mch.weixin.qq.com/pay/orderquery";//關閉訂單接口(POST)public final static String CLOSE_ORDER_URL = "https://api.mch.weixin.qq.com/pay/closeorder";//退款查詢接口(POST)public final static String CHECK_REFUND_URL = "https://api.mch.weixin.qq.com/pay/refundquery";//對賬單接口(POST)public final static String DOWNLOAD_BILL_URL = "https://api.mch.weixin.qq.com/pay/downloadbill";//短鏈接轉換接口(POST)public final static String SHORT_URL = "https://api.mch.weixin.qq.com/tools/shorturl";//接口調用上報接口(POST)public final static String REPORT_URL = "https://api.mch.weixin.qq.com/payitil/report";public static void commonParams(SortedMap<Object, Object> packageParams){// 賬號信息String appid = ConfigUtil.APP_ID; // appidString mch_id = ConfigUtil.MCH_ID; // 商業號// 生成隨機字符串String currTime = PayCommonUtil.getCurrTime();String strTime = currTime.substring(8, currTime.length());String strRandom = PayCommonUtil.buildRandom(4) + "";String nonce_str = strTime + strRandom;packageParams.put("appid", appid);// 公眾賬號IDpackageParams.put("mch_id", mch_id);// 商戶號packageParams.put("nonce_str", nonce_str);// 隨機字符串}/*** 該接口主要用於掃碼原生支付模式一中的二維碼鏈接轉成短鏈接(weixin://wxpay/s/XXXXXX),減小二維碼數據量,提升掃描速度和精確度。* @Author 張志朋* @param urlCode void* @Date 2016年10月26日* 更新日志* 2016年10月26日 張志朋 首次創建**/@SuppressWarnings("rawtypes")public static void shorturl(String urlCode){try {String key = ConfigUtil.API_KEY; // keySortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();ConfigUtil.commonParams(packageParams);packageParams.put("long_url", urlCode);// URL鏈接String sign = PayCommonUtil.createSign("UTF-8", packageParams, key);packageParams.put("sign", sign);// 簽名String requestXML = PayCommonUtil.getRequestXml(packageParams);String resXml = HttpUtil.postData(ConfigUtil.SHORT_URL, requestXML);Map map = XMLUtil.doXMLParse(resXml);String returnCode = (String) map.get("return_code");if("SUCCESS".equals(returnCode)){String resultCode = (String) map.get("return_code");if("SUCCESS".equals(resultCode)){urlCode = (String) map.get("short_url");}}} catch (Exception e) {e.printStackTrace();}}
參數必填項 APP_ID 和APP_SECRET 是從微信公眾號里面獲取的,而MCH_ID和API_KEY是從商戶平台獲取的。CERT_PATH 證書可選,但是如果做退款接口必須要使用證書。NOTIFY_URL 為回調地址,自定義路徑,但是一定要微信平台可以調用到你的url。
如何生成二維碼訂單?
文檔有詳細的參數說明,具體生成需要xml解析,這里就不放了,好多的說,有需要的可以留言。
支付回調:
/*** 二維碼支付* 創建者 張志朋* 創建時間 2016年10月31日**/@Controller@RequestMapping(value = "weixin")public class WeixinPayController {@Autowiredprivate IWeixinPayService weixinpayBack;/*** 微信支付回調* @Author 張志朋* @param request* @param response* @throws Exception void* @Date 2016年9月28日* 更新日志* 2016年9月28日 張志朋 首次創建**/@SuppressWarnings({ "unchecked", "rawtypes" })@RequestMapping(value = "pay")public void weixin_notify(HttpServletRequest request, HttpServletResponse response) throws Exception {LogUtil.info("支付成功回調");// 讀取參數InputStream inputStream = request.getInputStream();StringBuffer sb = new StringBuffer();String s;BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));while ((s = in.readLine()) != null) {sb.append(s);}in.close();inputStream.close();// 解析xml成mapMap<String, String> m = new HashMap<String, String>();m = XMLUtil.doXMLParse(sb.toString());// 過濾空 設置 TreeMapSortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();Iterator it = m.keySet().iterator();while (it.hasNext()) {String parameter = (String) it.next();String parameterValue = m.get(parameter);String v = "";if (null != parameterValue) {v = parameterValue.trim();}packageParams.put(parameter, v);}// 賬號信息String key = ConfigUtil.API_KEY; // key// 判斷簽名是否正確if (PayCommonUtil.isTenpaySign("UTF-8", packageParams, key)) {// ------------------------------// 處理業務開始// ------------------------------String resXml = "";if ("SUCCESS".equals((String) packageParams.get("result_code"))) {// 這里是支付成功String orderNo = (String) packageParams.get("out_trade_no");String attach = (String) packageParams.get("attach");//回調K12LogUtil.info(attach+"(訂單號:"+orderNo+"付款成功)");// 通知微信.異步確認成功.必寫.不然會一直通知后台.八次之后就認為交易失敗了.resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";weixinpayBack.updateAccOrder(orderNo);} else {LogUtil.info("支付失敗,錯誤信息:" + packageParams.get("err_code"));resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[報文為空]]></return_msg>" + "</xml> ";}// ------------------------------// 處理業務完畢// ------------------------------BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());out.write(resXml.getBytes());out.flush();out.close();} else {LogUtil.info("通知簽名驗證失敗");}}}
大體就這個樣子,后續的可能就是安全優化了。涉及到錢可不是小問題。
原文地址:http://blog.52itstyle.com/archives/180
