呼叫微信和支付寶第三方介面方法總結
阿新 • • 發佈:2018-12-11
- <span style="white-space:pre"> </span> //判斷證書
- if (resHandler.getParameter("sign").equals(
- WeixinSignUtil.createSign("utf-8",
- resHandler.getAllParameters(), securit)))
- {
- // 商戶訂單號
- String out_trade_no = resHandler.getParameter("out_trade_no");
- String totalFee = resHandler.getParameter("total_fee");
- System.out.println("out_trade_no:" + out_trade_no);
- Map<String, Object> map = new HashMap<String, Object>();
- String result_code = resHandler.getParameter("result_code");
- if (result_code.equals("SUCCESS"))
- {
- <span style="font-family: Arial, Helvetica, sans-serif;">// 金額,以分為單位</span><pre name="code" class="java"><span style="white-space:pre"> </span>String total_fee = resHandler.getParameter("total_fee");</pre><pre name="code" class="java"><span style="white-space:pre"> </span>//進行支付後操作...</pre><span style="white-space:pre"></span>} else { return resHandler.getParameter("err_code_des"); } // 給微信伺服器返回success 否則30分鐘通知8次 return "success"; } else { System.out.println("通知簽名驗證失敗"); resHandler.sendToCFT("fail");
- response.setCharacterEncoding("utf-8"); return "FAIL"; } } catch (Exception e) { return "FAIL"; } }
- <pre></pre>
- <p></p>
- <pre></pre>
- 這是微信呼叫我們定義的請求來主動返回支付結果,但我們也可以寫介面主動呼叫微信來獲取訂單資訊
- <p></p>
- <p><span style="font-size:14px"><span style="font-size:14px">這裡需要ios或者安卓呼叫我們java後臺寫的介面來獲取支付結果:</span></span></p>
- <p><span style="font-size:14px"><span style="font-size:14px">介面如下:</span></span></p>
- <p><span style="font-size:14px"><span style="font-size:14px"></span></span></p>
- <pre name="code" class="java">/**
- * 客戶端微信支付成功後查詢後臺支付結果介面
- *
- * @param req
- * @param rsp
- * @return String 返回json字串 如果有違例,請使用@exception/throws [違例型別]
- * [違例說明:異常的註釋必須說明該異常的含義及什麼條件下丟擲該
- * @throws Exception
- * @see [類、類#方法、類#成員]
- */
- @RequestMapping(value = "/interface/payStatus", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
- @ResponseBody
- public String getPayStatus(HttpServletRequest req, HttpServletResponse rsp)
- throws Exception
- {
- Map<String, Object> resultMap = new HashMap<String, Object>();
- try
- {
- URL postUrl = new URL(
- "https://api.mch.weixin.qq.com/pay/orderquery");
- // 獲取請求內容
- String requestContent = getRequestContent(req);
- // 日誌
- interfaceLogger.info("request payStatus:" + requestContent);
- // 解析引數
- requestParam = parseAndCheckParam(requestContent, resultMap,
- requestParam, systemParam.getSystemKey());
- // 校驗引數
- checkStatusParam(resultMap);
- // 校驗token及獲取使用者資訊
- Map<String, Object> userInfo = checkTokenAndGetUserInfo(
- tokenService, appuserManager, requestParam, resultMap);
- String user_id = (String)userInfo.get("userId");
- String totalFee = (String)requestParam.get("totalFee");
- String type = (String)requestParam.get("orderType"); // 獲取訂單型別引數
- if (null == user_id)
- {
- resultMap.put("resultCode",
- ErrorCodeConstants.INVALID_TOKEN_ERROR);
- }
- SysParamServiceImpl sysParam = (SysParamServiceImpl)SpringContextHolder
- .getBean(SysParamServiceImpl.class);
- HttpsURLConnection con = (HttpsURLConnection)postUrl
- .openConnection();// 開啟連線
- con.setRequestMethod("POST");// post方式提交
- con.setDoOutput(true);// 開啟讀寫屬性,預設均為false
- con.setDoInput(true);
- con.setUseCaches(false);// Post請求不能使用快取
- con.setInstanceFollowRedirects(true);
- // DataOutputStream out = new
- // DataOutputStream(con.getOutputStream());
- PrintWriter out = new PrintWriter(con.getOutputStream());
- Map<String, Object> map = new HashMap<String, Object>();
- // 相關引數,可以定義一個Map做成動態的
- map.put("appid", sysParam.getStringParamByKey("c.wxpay.appid")); // appID
- map.put("mch_id", sysParam.getStringParamByKey("c.wxpay.partnerid")); // 商戶號
- map.put("nonce_str", RandomUtil.CreateRandom(32)); // 隨機數
- String orderId = requestParam.get("outTradeNo").toString();
- map.put("out_trade_no", orderId); // 訂單號
- // String mo="3000";
- // insertMoneyAccounting(orderId,mo); //利潤分配
- // 轉成sortedMap,微信支付後臺生成sign需要排序過的map
- SortedMap<String, Object> sort = new TreeMap<String, Object>(map);
- String secrit = sysParam.getStringParamByKey("c.wxpay.secret");
- // 生成sign
- String sign = WeixinSignUtil.createSign("UTF-8", sort, secrit);
- // 把sign放入map中
- map.put("sign", sign); // 簽名
- Document doc = DocumentHelper.createDocument();
- Element body = DocumentHelper.createElement("xml");
- buildMap2xmlBody(body, map);
- doc.add(body);
- // 傳送請求
- // out.writeUTF(doc.asXML());
- String outStr = doc.asXML();
- out.print(outStr);
- System.out.println(doc.asXML());
- out.flush();
- out.close();
- // 接收資料
- BufferedReader reader = new BufferedReader(new InputStreamReader(
- con.getInputStream(), "UTF-8"));
- String line;
- StringBuffer responseText = new StringBuffer();
- while ( (line = reader.readLine()) != null)
- {
- responseText.append(line).append("\r\n");
- }
- reader.close();
- con.disconnect();
- String resXml = responseText.toString() + ""; // 獲取從微信付款的結果
- // ,以String型別的xml格式返回
- System.out.println("result:" + resXml);
- // 解析xml
- Map<String, Object> m = new HashMap<String, Object>();
- Document d = DocumentHelper.parseText(resXml);
- Element rootElement = d.getRootElement();
- XmlToBean.ele2map(m, rootElement);
- String str = "";
- if (m.containsKey("trade_state"))
- {
- str = m.get("trade_state").toString();
- str = str.replace("{trade_state=", "");
- str = str.substring(0, str.length() - 1);
- if ("SUCCESS" == str || "SUCCESS".equals(str))
- {
- if ("0".equals(type)) {
- //支付成功後操作...
- }
- }
- else if ("REFUND" == str || "REFUND".equals(str))
- {
- str = "1"; // 轉入退款
- }
- else if ("NOTPAY" == str || "NOTPAY".equals(str))
- {
- str = "2"; // 未支付
- }
- else if ("CLOSED" == str || "CLOSED".equals(str))
- {
- str = "3"; // 已關閉
- }
- else if ("REVOKED" == str || "REVOKED".equals(str))
- {
- str = "4"; // 已撤銷
- }
- else if ("USERPAYING" == str || "USERPAYING".equals(str))
- {
- str = "5"; // 使用者支付中
- }
- else if ("PAYERROR" == str || "PAYERROR".equals(str))
- {
- str = "6"; // 支付失敗
- }
- resultMap.put("status", str);
- resultMap.put("resultCode",
- ErrorCodeConstants.RESULT_CODE_SUCCESS);
- }
- }
- catch (Exception e)
- {
- logger.error("loginOut:system exception!", e);
- resultMap.clear();
- resultMap.put("resultCode", ErrorCodeConstants.SYSTEM_ERROR);
- }
- interfaceLogger.info("response payStatus:" + resultMap.toString());
- return JsonUtil.Object2EncodeJsonSting(resultMap,
- systemParam.getSystemKey());
- }</pre><br>
- requestParam.get("XXX"),XXX是客戶端呼叫我們介面給我們傳的引數,需要給我們totalFee(金額),orderType(訂單型別)等<br>
- <p></p>
- <p><span style="font-size:14px"><span style="font-size:14px">然後我們返回支付結果給客戶端</span></span></p>
- <p><span style="font-size:14px; color:#ff0000">二、支付寶支付:</span></p>
- <p><span style="font-size:14px">支付寶支付流程上和微信支付稍微有所差別,支付寶不需要呼叫下單結果,但是也需要一個類似於微信prepayId的欄位來入庫,作用上跟prepayId差不多,名稱可以自己定義,我這邊暫時為aliPayInfo:</span></p>
- <p><span style="font-size:14px">首先看js程式碼:</span></p>
- <p><span style="font-size:14px"></span></p>
- <pre name="code" class="javascript">//支付寶支付
- function aliPay(outTradeNo){
- var orderType="0";
- var info = $("#aliPayInfo").val();//訂單資訊
- var totalAmount = $("#moeny").val();//總金額
- var orderName = $("#orderName").val();//訂單名稱
- //type 0:線路 1:景點 2:酒店 3:商城 4:VIP
- var prams = {
- aliPayInfo : info,
- type : orderType,
- orderNumber : outTradeNo,
- money : totalAmount,
- orderName : orderName
- };
- //先調支付寶確定是否下單 否則返回支付寶會話資訊
- $.ajax({
- url : '<%=basePath%>client/hotel/foundZFBOrder.do',
- type : "post",
- data : prams,
- cache : false,
- dataType : "json",
- success : function(data)
- {
- //alert("info +===="+data.info);
- if(data.isSuccess){
- if(isAndroid){
- ClientInterface.aliPay(data.info,outTradeNo,orderType,totalAmount);
- }else if(isiOS){
- window.location.href='http://localhost/aliPay/'+data.info+';'+outTradeNo+";"+orderType+";"+totalAmount;
- }
- }else{
- var title = "支付寶下單失敗";
- prompt(title);
- }
- },
- error : function(data){
- var title = "支付寶下單失敗";
- prompt(title);
- }
- });
- }</pre><br>
- <pre name="code" class="javascript"></pre>頁面上的aliPayInfo可以為空,因為第一次去呼叫支付寶時這個為空,如果不支付,但是還是入庫了,需要去資料庫裡查一下,那麼共用這個頁面的話aliPayInfo就不為空<p></p><p><span style="font-size:14px">然後去後臺寫這個ajax請求</span></p><p><span style="font-size:14px"></span></p><pre name="code" class="java">@RequestMapping(value="/foundZFBOrder", produces = "application/json;charset=UTF-8")
- @ResponseBody
- public Map<String, Object> foundZFBOrder(HttpServletRequest request){
- //支付寶資訊
- String aliPayInfo = request.getParameter("aliPayInfo");
- //金額
- String money = request.getParameter("money");
- //訂單名稱
- String orderName = request.getParameter("orderName");
- //訂單編號
- String orderNumber = request.getParameter("orderNumber");
- //訂單型別(0:線路 1:景點 2:酒店 3:商城 4:VIP)
- String type = request.getParameter("type");
- boolean isSuccess = false;
- //判斷是否生成過支付寶資訊
- if(StringUtils.isBlank(aliPayInfo)){
- //生成支付寶資訊
- aliPayInfo = AliPayUtil.orderInfo(money, orderName, orderNumber, type);
- //修改表中支付寶資訊
- if(StringUtils.isNotBlank(aliPayInfo)){
- isSuccess = true;
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("aliPayInfo", aliPayInfo);
- map.put("type", type);
- map.put("orderNumber", orderNumber);
- try {
- travelOrderService.updateOrderInfoByType(map);
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- /** 列印支付寶響應日誌 */
- if (interfaceLogger.isInfoEnabled()) {
- interfaceLogger.info("[HotelController][foundZFBOrder]ZFB " + table + " result :["
- + JSON.toJSONString(aliPayInfo) + "]");
- }
- }
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("info", aliPayInfo);
- map.put("isSuccess", isSuccess);
- return map;
- }</pre><br>
- <pre name="code" class="java"></pre>這裡的 aliPayInfo = AliPayUtil.orderInfo(money, orderName, orderNumber, type);<p></p><p><span style="font-size:14px">類似於微信的下單介面(<span style="font-size:14px">aliPayInfo </span>需要入庫),但不是下單介面,因為支付寶支付沒有下單介面,詳情可以檢視支付寶支付文件</span></p><p><span style="font-size:14px">下面繼續寫orderInfo方法:</span></p><pre name="code" class="java">/**
- *
- * @param amount 訂單金額
- * @param subject 訂單標題
- * @param body 訂單描述
- * @param outTradeNo訂單號
- * @return
- */
- public static String orderInfo(String amount,String subject,String outTradeNo,String type) {
- //獲取appid
- String appId=Const.APPID;
- Map<String, String> authInfoMap = OrderInfoUtil.buildOrderParamMap(appId,amount,subject,outTradeNo,type);
- String info = OrderInfoUtil.buildOrderParam(authInfoMap);
- String rsaPrivate =Const.RSAPRIVATE; //獲取商戶金鑰
- String sign = OrderInfoUtil.getSign(authInfoMap, rsaPrivate);
- final String orderInfo = info + "&" + sign;
- return orderInfo;
- }</pre><br>
- <span style="font-size:18px">這裡和微信一樣需要支付寶商戶的appid和RSAPRIVATE提供給我們開發者,</span><br>
- <p style="font-size:14px">然後編寫支付寶支付工具類:</p>
- <p style="font-size:14px"></p>
- <pre name="code" class="java">public class OrderInfoUtil {
- /**
- * 構造授權引數列表
- *
- * @param pid
- * @param app_id
- * @param target_id
- * @return
- */
- public static Map<String, String> buildAuthInfoMap(String pid, String app_id, String target_id) {
- Map<String, String> keyValues = new HashMap<String, String>();
- // 商戶簽約拿到的app_id,如:2013081700024223
- keyValues.put("app_id", app_id);
- // 商戶簽約拿到的pid,如:2088102123816631
- keyValues.put("pid", pid);
- // 服務介面名稱, 固定值
- keyValues.put("apiname", "com.alipay.account.auth");
- // 商戶型別標識, 固定值
- keyValues.put("app_name", "mc");
- // 業務型別, 固定值
- keyValues.put("biz_type", "openservice");
- // 產品碼, 固定值
- keyValues.put("product_id", "APP_FAST_LOGIN");
- // 授權範圍, 固定值
- keyValues.put("scope", "kuaijie");
- // 商戶唯一標識,如:kkkkk091125
- keyValues.put("target_id", target_id);
- // 授權型別, 固定值
- keyValues.put("auth_type", "AUTHACCOUNT");
- // 簽名型別
- keyValues.put("sign_type", "RSA");
- return keyValues;
- }
- /**
- * 構造支付訂單引數列表
- * @param pid
- * @param app_id
- * @param target_id
- * @return
- */
- public static Map<String, String> buildOrderParamMap(String appId,String amount,String subject,String outTradeNo,String type) {
- Map<String, String> keyValues = new HashMap<String, String>();
- keyValues.put("app_id", appId);
- keyValues.put("biz_content", "{\"timeout_express\":\"30m\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"total_amount\":\""+amount+"\",\"subject\":\""+subject+"\",\"out_trade_no\":\"" +outTradeNo + "\"}");
- keyValues.put("charset", "utf-8");
- keyValues.put("method", "alipay.trade.app.pay");
- keyValues.put("sign_type", "RSA");
- //獲取域名
- SysParamServiceImpl systemParam = (SysParamServiceImpl)SpringContextHolder.getBean(SysParamServiceImpl.class);
- //String notifyUrl="http://180.96.11.10:8080/tourism";
- String notifyUrl=systemParam.getStringParamByKey("sys.domain");
- notifyUrl=notifyUrl+"/interface/alipay/"+type;
- keyValues.put("notify_url", notifyUrl);
- String timestamp = "";
- Date date=new Date();
- SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //設定時間格式
- timestamp=sdf.format(date);
- keyValues.put("timestamp", timestamp);
- keyValues.put("version", "1.0");
- return keyValues;
- }
- /**
- * 構造支付訂單引數資訊
- *
- * @param map
- * 支付訂單引數
- * @return
- */
- public static String buildOrderParam(Map<String, String> map) {
- List<String> keys = new ArrayList<String>(map.keySet());
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < keys.size() - 1; i++) {
- String key = keys.get(i);
- String value = map.get(key);
- sb.append(buildKeyValue(key, value, true));
- sb.append("&");
- }
- String tailKey = keys.get(keys.size() - 1);
- String tailValue = map.get(tailKey);
- sb.append(buildKeyValue(tailKey, tailValue, true));
- return sb.toString();
- }
- /**
- * 拼接鍵值對
- *
- * @param key
- * @param value
- * @param isEncode
- * @return
- */
- private static String buildKeyValue(String key, String value, boolean isEncode) {
- StringBuilder sb = new StringBuilder();
- sb.append(key);
- sb.append("=");
- if (isEncode) {
- try {
- sb.append(URLEncoder.encode(value, "UTF-8"));
- } catch (UnsupportedEncodingException e) {
- sb.append(value);
- }
- } else {
- sb.append(value);
- }
- return sb.toString();
- }
- /**
- * 對支付引數資訊進行簽名
- *
- * @param map
- * 待簽名授權資訊
- *
- * @return
- */
- public static String getSign(Map<String, String> map, String rsaKey) {
- List<String> keys = new ArrayList<String>(map.keySet());
- // key排序
- Collections.sort(keys);
- StringBuilder authInfo = new StringBuilder();
- for (int i = 0; i < keys.size() - 1; i++) {
- String key = keys.get(i);
- String value = map.get(key).toString();
- authInfo.append(buildKeyValue(key, value, false));
- authInfo.append("&");
- }
- String tailKey = keys.get(keys.size() - 1);
- String tailValue =map.get(tailKey).toString();
- authInfo.append(buildKeyValue(tailKey, tailValue, false));
- String oriSign = SignUtils.sign(authInfo.toString(), rsaKey);
- String encodedSign = "";
- try {
- encodedSign = URLEncoder.encode(oriSign, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- return "sign=" + encodedSign;
- }
- /**
- * 要求外部訂單號必須唯一。
- * @return
- */
- private static String getOutTradeNo() {
- SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
- Date date = new Date();
- String key = format.format(date);
- Random r = new Random();
- key = key + r.nextInt();
- key = key.substring(0, 15);
- return key;
- }
- }</pre><br>
- <span style="color:#ff0000">keyValues.put("notify_url", notifyUrl);這個和微信一樣,需要設定一個供支付寶支付後返回給我們的支付結果通知的請求,需自己定義,可帶引數,必須在外網下才能呼叫</span><br>
- <p></p>
- <p style="font-size:14px">最後根據我們定義的請求,來寫接收支付寶返回給我們的結果:</p>
- <p style="font-size:14px"></p>
- <pre name="code" class="java">@RequestMapping(value = "/interface/alipay/{type}", produces = "text/html;charset=UTF-8")
- @ResponseBody
- public String getzfbPayResult(HttpServletRequest request,HttpServletResponse response){
- try{
- String reqcontent = getRequestContent(request);
- interfaceLogger.info("################### ################# WeiXinPayResultInterface::alipay,request msg:"+reqcontent);
- //解析url
- //reqcontent=stringFarmat(reqcontent);
- try {
- reqcontent= URLDecoder.decode(reqcontent, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- interfaceLogger.info("###########獲取引數解析url:[email protected]@@@@@@@@@@@@@@@@@@@@@@@@========="+reqcontent);
- //轉換為map
- Map<String, String> paramMap=stringtoArray(reqcontent);
- //獲取orderType
- String orderType=request.getRequestURI();
- int i=orderType.lastIndexOf("/");
- orderType=orderType.substring(i+1, orderType.length());
- //驗證簽名
- //支付寶公鑰
- String publicKey=Const.PUBLICKEY; //支付寶公鑰
- //字符集
- String charsetType="UTF-8";
- //驗證簽名
- boolean signVerified = AlipaySignature.rsaCheckV1(paramMap, publicKey, charsetType); //呼叫SDK驗證簽名
- interfaceLogger.info("###########驗證簽名結果:[email protected]@@@@@@@@@@@@@@@@@@@@@@@@========="+signVerified);
- if(signVerified){
- //驗證金額訂單號
- interfaceLogger.info("*****************驗證簽名成功:&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
- if(paramMap.containsKey("trade_status")){
- String resultStr=paramMap.get("trade_status");
- if(resultStr.equals("TRADE_SUCCESS")||resultStr.equals("TRADE_FINISHED")){
- //支付成功後操作...
- }
- return "success";
- }else{
- interfaceLogger.info("&&&&&&&&&&&&&&&&驗證簽名失敗:***************************");
- return "failure";
- }
- }catch (Exception e){
- interfaceLogger.info("###########待簽名字串str:[email protected]@@@@@@@@@@@@@@@@@@@@@@@@=========",e);
- e.printStackTrace();
- return "failure";
- }
- }
- </pre>這一步需要商戶提供給我們的PUBLICKEY支付寶公鑰來進行證書驗證。<pre name="code" class="java">-------------------------------------------------------------------------------------------------------------------------------------</pre>這裡介紹了app上面的兩種支付方式。下面介紹下微信和支付寶的二維碼支付
- <p></p>
- <p style="font-size:14px">先看java後臺程式碼:</p>
- <pre name="code" class="java"> /**
- *去支付介面(支付訂單)
- * @param request
- * @return
- * @throws Exception
- */
- @RequestMapping(value="/payOrder")
- public ModelAndView payOrder(HttpServletRequest request) throws Exception{
- ModelAndView mv = this.getModelAndView();
- PageData pd = new PageData();
- String type=request.getParameter("type");
- String orderId=request.getParameter("orderId");
- pd = this.getPageData();
- User user=SessionUtil.getUser(request);
- /* User user=new User();
- user.setUserId("wang");*/
- String userId="";
- if(null!=user){
- userId=user.getUserId();
- }
- pd.put("userId", userId);
- pd=travelOrderService.getAllOrderDetail(pd);
- String orderNumber="";
- String amount="0.01";//測試金額
- String orderName="";
- if(pd.containsKey("orderName")){
- if(!StringUtils.isBlank(pd.get("orderName")))
- orderName=pd.get("orderName").toString();
- }
- if(pd.containsKey("orderNumber")){
- if(!StringUtils.isBlank(pd.get("orderNumber")))
- orderNumber=pd.get("orderNumber").toString();
- }
- //元轉成分
- String flag = sysparam.getStringParamByKey("system.flag");
- if(flag=="1"||flag.equals("1")){
- //type為0,3,4時取amount,type為1,2時取js_amount
- if(type.equals("0")||type.equals("3")||type.equals("4")){
- if(pd.containsKey("amount")){
- if(!StringUtils.isBlank(pd.get("amount")))
- amount=pd.get("amount").toString();
- }
- }else if(type.equals("1")||type.equals("2")){
- if(pd.containsKey("js_amount")){
- if(!StringUtils.isBlank(pd.get("js_amount")))
- amount=pd.get("js_amount").toString();
- }
- }
- }
- if (logger.isInfoEnabled())
- {
- logger.info("PayController:payOrder:amount:[" + amount + "]==>");
- }
- //以分為單位
- amount=floatToString(amount);
- //獲取生成微信二維碼的url和prepayId
- Map<String, Object> map=weChatPay(orderNumber,amount,type);
- String imageUrl="";
- f(map.containsKey("urlCode")){
- if(!StringUtils.isBlank(map.get("urlCode"))){
- imageUrl=map.get("urlCode").toString();
- }
- }
- //獲取生成支付寶二維碼的url(金額要改成元!)
- amount=stringToFloat(amount);
- String aliPayCodeUrl=AliPayUtil.aliPay(orderNumber, orderName, amount, type);
- map.put("type", type);
- map.put("orderNumber", orderNumber);
- map.put("aliPayCodeUrl", aliPayCodeUrl);
- //將二維碼入庫
- travelOrderService.updateOrderInfoByType(map);
- //訂單編號
- pd.put("type", type);
- pd.put("orderId", orderId);
- mv.addObject("pd", pd);
- mv.addObject("productId", orderNumber);
- mv.addObject("imageUrl", imageUrl);
- mv.addObject("aliPayCodeUrl", aliPayCodeUrl);
- mv.setViewName("/pay/pay-4");
- return mv;
- }</pre><br>
- <p></p>
- <p style="font-size:14px">這裡我把微信和支付寶支付前生成的二維碼寫在同一個方法裡,<span style="font-size:14px">imageURL是微信二維碼url,aliPayCodeUrl是支付寶的二維碼</span>,和app支付不同的是,掃碼支付需要事先生成二維碼,並且二維碼需要入庫,並帶到頁面去用於顯示(下面會講)</p>
- <p style="font-size:14px">微信下單並生成urlCode</p>
- <p style="font-size:14px"></p>
- <pre name="code" class="java">/**
- * 微信下單並返回生成二維碼的url
- * 〈一句話功能簡述〉
- * 〈功能詳細描述〉
- * @param orderNo
- * @param TotalMoney
- * @param orderType
- * @return
- * @throws Exception String
- * 如果有違例,請使用@exception/throws [違例型別] [違例說明:異常的註釋必須說明該異常的含義及什麼條件下丟擲該
- * @see [類、類#方法、類#成員]
- */
- @SuppressWarnings("rawtypes")
- public Map<String, Object> weChatPay(String orderNo,String TotalMoney,String orderType) throws Exception{
- URL postUrl = new URL("https://api.mch.weixin.qq.com/pay/unifiedorder");
- HttpsURLConnection con = (HttpsURLConnection) postUrl.openConnection();//開啟連線
- con.setRequestMethod("POST");//post方式提交
- con.setDoOutput(true);//開啟讀寫屬性,預設均為false
- con.setDoInput(true);
- con.setUseCaches(false);//Post請求不能使用快取
- con.setInstanceFollowRedirects(true);
- DataOutputStream out = new DataOutputStream(con.getOutputStream());
- Map<String, Object> vo = new HashMap<String, Object>();
- //相關引數,可以定義一個Map做成動態的
- String appid = sysparam.getStringParamByKey("c.wxpay.appid");
- vo.put("appid", appid);
- vo.put("attach", "支付測試");
- vo.put("body", "PC端支付測試");
- String mchid = sysparam.getStringParamByKey("c.wxpay.partnerid");
- vo.put("mch_id",mchid);
- vo.put("nonce_str", RandomUtil.CreateRandom(32));
- /String notifyUrl=sysparam.getStringParamByKey("sys.pc.domain");
- if (logger.isInfoEnabled())
- {
- logger.info("微信支付回撥地址設定:notifyUrl:[" + notifyUrl + "]==>");
- }
- notifyUrl=notifyUrl+"/travelWeb/pay/getWeChatPayResult/"+orderType; //呼叫微信下發通知的介面
- vo.put("notify_url", notifyUrl);
- vo.put("out_trade_no", orderNo);
- vo.put("spbill_create_ip", "14.23.150.211");
- vo.put("total_fee", TotalMoney);
- vo.put("trade_type", "NATIVE");
- //轉成sortedMap,微信支付後臺生成sign需要排序過的map
- SortedMap<String,Object> sort=new TreeMap<String,Object>(vo);
- //String secrit = "YNKSK648KG70j1085YYolajdfYUI7865";
- String secrit =sysparam.getStringParamByKey("c.wxpay.secret");
- //生成sign
- String sign=WeixinSignUtil.createSign("UTF-8", sort,secrit);
- //把sign放入map中
- vo.put("sign", sign);
- org.dom4j.Document doc = DocumentHelper.createDocument();
- Element body = DocumentHelper.createElement("xml");
- XmlUtil.buildMap2xmlBody(body,vo);
- doc.add(body);
- //傳送請求
- out.writeUTF(doc.asXML());
- System.out.println(doc.asXML());
- out.flush();
- out.close();
- //接收資料
- BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
- String line;
- StringBuffer responseText = new StringBuffer();
- while ((line = reader.readLine()) != null) {
- responseText.append(line).append("\r\n");
- }
- reader.close();
- con.disconnect();
- String requestXML = responseText.toString()+"";
- if (logger.isInfoEnabled())
- {
- logger.info("weChatPay:輸出引數列表:[" + requestXML + "]==>");
- }
- //xml轉換為map
- Map map = XMLUtil.doXMLParse(requestXML);
- String urlCode = (String) map.get("code_url");
- String prepayId = (String) map.get("prepay_id");
- //返回生成二維碼的url和預支付交易會話id
- Map<String, Object> resultMap=new HashMap<String, Object>();
- resultMap.put("urlCode", urlCode);
- resultMap.put("prepayId", prepayId);
- return resultMap;
- }</pre>
- <p></p>
- <p style="font-size:14px">支付寶生成urlCode</p>
- <p style="font-size:14px"></p>
- <pre name="code" class="java">/**
- *
- * 〈一句話功能簡述〉
- * 〈功能詳細描述〉
- * @param orderNo
- * 訂單號
- * @param orderTitle
- * 訂單標題
- * @param orderPrice
- * 訂單總額
- * 如果有違例,請使用@exception/throws [違例型別] [違例說明:異常的註釋必須說明該異常的含義及什麼條件下丟擲該
- * @see [類、類#方法、類#成員]
- */
- public static String aliPay(String orderNo, String orderTitle,
- String orderPrice,String type)
- {
- String aliPayCodeUrl="";
- // 支付超時,定義為120分鐘
- String timeoutExpress = "120m";
- // 建立掃碼支付請求builder,設定請求引數
- String notifyUrl=sysParamService.getStringParamByKey("sys.pc.domain");
- notifyUrl=notifyUrl+"/travelWeb/pay/getAliPayResult/"+type; //呼叫支付寶下發通知的介面
- AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
- .setSubject(orderTitle)
- .setTotalAmount(orderPrice)
- .setOutTradeNo(orderNo)
- .setStoreId(storeId)
- .setTimeoutExpress(timeoutExpress)
- .setNotifyUrl(notifyUrl);//支付寶伺服器主動通知商戶伺服器裡指定的頁面http路徑,根據需要設定
- AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
- switch (result.getTradeStatus())
- {
- case SUCCESS:
- logger.info("支付寶預下單成功: )");
- AlipayTradePrecreateResponse response = result.getResponse();
- System.out.println("response.getQrCode()====="
- + response.getQrCode());
- aliPayCodeUrl=response.getQrCode();
- break;
- case FAILED:
- logger.error("支付寶預下單失敗!!!");
- break;
- case UNKNOWN:
- logger.error("系統異常,預下單狀態未知!!!");
- break;
- default:
- logger.error("不支援的交易狀態,交易返回異常!!!");
- break;
- }
- return aliPayCodeUrl;
- }</pre><br>
- <br>
- <p></p>
- <p style="font-size:14px"><br>
- </p>
- <p style="font-size:14px"><br>
- </p>
- 這個方法和app一樣,只是多返回了一個urlcode(urlcode生成二維碼,這兩個方法必須都要配置回撥地址<br>
- 下一步需要編寫生成兩種二維碼的方法:
- <p style="font-size:14px"></p>
- <pre name="code" class="java">/**
- * 生成支付寶二維碼
- * 〈一句話功能簡述〉
- * 〈功能詳細描述〉
- * @param response
- * @param req void
- * 如果有違例,請使用@exception/throws [違例型別] [違例說明:異常的註釋必須說明該異常的含義及什麼條件下丟擲該
- * @see [類、類#方法、類#成員]
- */
- @RequestMapping(value = "/createAliPayCode.do", method = RequestMethod.GET)
- public void createAliPayCode(HttpServletResponse response,HttpServletRequest req)
- {
- String imageUrl=req.getParameter("aliPayCodeUrl");
- //傳入二維碼連線,圖片高度和寬頻
- BufferedImage image=ImageUtil.createImage(imageUrl,1000,1000);
- try
- {
- ImageIO.write(image, "gif", response.getOutputStream());
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- /**
- * 微信支付二維碼
- * 〈一句話功能簡述〉
- * 〈功能詳細描述〉
- * @param response
- * @param req void
- * 如果有違例,請使用@exception/throws [違例型別] [違例說明:異常的註釋必須說明該異常的含義及什麼條件下丟擲該
- * @throws IOException
- * @throws JDOMException
- * @see [類、類#方法、類#成員]
- */
- @RequestMapping(value = "/createWXPayCode.do", method = RequestMethod.GET)
- public void createWXPayCode(HttpServletResponse response,HttpServletRequest req) throws IOException, JDOMException
- {
- String imageUrl=req.getParameter("imageUrl");
- //傳入二維碼連線,圖片高度和寬頻
- BufferedImage image=ImageUtil.createImage(imageUrl,1000,1000);
- try
- {
- ImageIO.write(image, "gif", response.getOutputStream());
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- }</pre>
- <p></p>
- <p style="font-size:14px">這裡生成二維碼的方法是用谷歌zhongxin(需要匯入jar包)</p>
- <p style="font-size:14px"></p>
- <pre name="code" class="java"> /**
- * 生成二維碼圖片方法
- * 〈一句話功能簡述〉
- * 〈功能詳細描述〉
- * @param text
- * @return BufferedImage
- * 如果有違例,請使用@exception/throws [違例型別] [違例說明:異常的註釋必須說明該異常的含義及什麼條件下丟擲該
- * @see [類、類#方法、類#成員]
- */
- @SuppressWarnings({"rawtypes", "unchecked"})
- public static BufferedImage createImage(String text,int width2,int height2)
- {
- //二維碼的圖片格式
- // String format = "gif";
- Hashtable hints = new Hashtable();
- //內容所使用編碼
- hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
- BufferedImage image = null;
- try
- {
- BitMatrix bitMatrix = new MultiFormatWriter().encode(text,
- BarcodeFormat.QR_CODE, width2, height2, hints);
- int width = bitMatrix.getWidth();
- int height = bitMatrix.getHeight();
- image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
- for (int x = 0; x < width; x++ )
- {
- for (int y = 0; y < height; y++ )
- {
- image.setRGB(x, y,
- bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF); //二維碼圖片為黑白兩色
- }
- }
- }
- catch (WriterException e)
- {
- e.printStackTrace();
- }
- return image;
- }</pre><br>
- <br>
- <p></p>
- <br>
- 這裡吧之前傳來的兩個值在面裡呼叫即可(img標籤配置src)
- <p style="font-size:14px"></p>
- <pre name="code" class="html"><div class="boder-line">
- <img src="<%=basePath%>/XX/pay/createWXPayCode.do?imageUrl=${imageUrl}"/>
- </div>
- <div class="boder-line">
- <img src="<%=basePath%>/XX/pay/createAliPayCode.do?aliPayCodeUrl=${aliPayCodeUrl}"/>
- </div></pre><br>
- 這樣開啟掃碼支付頁面就會有生成好的支付寶和微信支付二維碼圖片
- <p></p>
- <p style="font-size:14px">然後發起支付,最後根據配置的回撥地址返回支付結果</p>
- <p style="font-size:14px">微信如下:</p>
- <p style="font-size:14px"></p>
- <pre name="code" class="java"> /**
- * 微信支付結果回撥地址
- * 〈一句話功能簡述〉
- * 〈功能詳細描述〉
- * @param request
- * @param response
- * @throws Exception
- * @see [類、類#方法、類#成員]
- */
- @SuppressWarnings({"unchecked", "rawtypes"})
- @RequestMapping(value = "/getWeChatPayResult/{orderType}", produces = "text/html;charset=UTF-8")
- @ResponseBody
- public void getWeixinPayResult(HttpServletRequest request,
- HttpServletResponse response)
- throws Exception
- {
- //讀取引數
- InputStream inputStream ;
- StringBuffer sb = new StringBuffer();
- inputStream = request.getInputStream();
- String s ;
- BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
- while ((s = in.readLine()) != null){
- sb.append(s);
- }
- in.close();
- inputStream.close();
- //解析xml成map
- Map<String, String> m = new HashMap<String, String>();
- m = XMLUtil.doXMLParse(sb.toString());
- //獲取orderType
- String orderType=request.getRequestURI();
- int i=orderType.lastIndexOf("/");
- orderType=orderType.substring(i+1, orderType.length());
- logger.info("[PayController][getWeChatPayResult]:orderType:"+orderType);
- //過濾空 設定 TreeMap
- SortedMap<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 =sysparam.getStringParamByKey("c.wxpay.secret");
- logger.info("[PayController][getWeChatPayResult]:packageParams:"+packageParams.toString());
- //判斷簽名是否正確
- if(PayCommonUtil.isTenpaySign("UTF-8", packageParams,key)) {
- String resXml = "";
- if("SUCCESS".equals((String)packageParams.get("result_code"))){
- // 這裡是支付成功
- //////////執行自己的業務邏輯////////////////
- String mch_id = (String)packageParams.get("mch_id");
- String openid = (String)packageParams.get("openid");
- String is_subscribe = (String)packageParams.get("is_subscribe");
- String o