支付寶app支付java後臺流程及原理分析
java版支付寶app支付流程及原理分析
本實例是基於springmvc框架編寫
一、流程步驟
1.執行流程
當手機端app(就是你公司開發的app)在支付頁面時,調起服務端(後臺第1個創建訂單接口)接口,後臺把需要調起支付寶支付的參數返回給手機端,手機端拿到
這些參數後,拉起支付寶支付環境完成支付,完成支付後會調異步通知(第2個接口),此時需要給支付寶返回成功或者失敗信息,成功後會調用同步通知(第3個接口)
返回支付成功頁面,完成整個支付流程。
2.支付的配置文件AlipayConfig
1 public class AlipayConfig { 2 // 1.商戶appid 3 public static String APPID = "20170812********"; 4 5 // 2.私鑰 pkcs8格式的 6 public static String RSA_PRIVATE_KEY =""; 7 8 // 3.支付寶公鑰 9 public static String ALIPAY_PUBLIC_KEY = ""; 10 11 // 4.服務器異步通知頁面路徑 需http://或者https://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問 12 public static String notify_url = "http://www.xxx.com/alipay/notify_url.do"; 13 14 // 5.頁面跳轉同步通知頁面路徑 需http://或者https://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問 商戶可以自定義同步跳轉地址 15 public static String return_url = "http://www.xxx.com/alipay/return_url.do"; 16 17// 6.請求網關地址 18 public static String URL = "https://openapi.alipay.com/gateway.do"; 19 20 // 7.編碼 21 public static String CHARSET = "UTF-8"; 22 23 // 8.返回格式 24 public static String FORMAT = "json"; 25 26 // 9.加密類型 27 public static String SIGNTYPE = "RSA2"; 28 29 }
3.第1個創建訂單接口
1 /** 2 *@param userId 充值人 3 *@param tradeMoney 充值money(RMB) 4 *@throws AlipayApiException ModelAndView 5 */ 6 @RequestMapping(value="api/alipay/createOrder",method={RequestMethod.POST,RequestMethod.GET}) 7 @ResponseBody 8 public Model alipay( 9 @RequestParam("userId")String userId, 10 @RequestParam("tradeMoney")String tradeMoney,Model m) throws AlipayApiException{ 11 12 String orderStr = ""; 13 try { 14 15 /****** 1.封裝你的交易訂單開始 *****/ //自己用 16 17 此處封裝你的訂單數據,訂單狀態可以設置為等待支付 18 19 /****** 1.封裝你的交易訂單結束 *****/ 20 21 Map<String,String> orderMap = new LinkedHashMap<String,String>(); //訂單實體 22 Map<String,String> bizModel = new LinkedHashMap<String,String>(); //公共實體 23 24 /****** 2.商品參數封裝開始 *****/ //手機端用 25 // 商戶訂單號,商戶網站訂單系統中唯一訂單號,必填 26 orderMap.put("out_trade_no",trade.getOrderNumber()); 27 // 訂單名稱,必填 28 orderMap.put("subject","手機網站支付購買遊戲幣"); 29 // 付款金額,必填 30 orderMap.put("total_amount",tradeMoney); 31 // 商品描述,可空 32 orderMap.put("body","您購買遊戲幣"+tradeMoney +"元"); 33 // 超時時間 可空 34 orderMap.put("timeout_express","30m"); 35 // 銷售產品碼 必填 36 orderMap.put("product_code","QUICK_WAP_PAY"); 37 38 /****** 2.商品參數封裝結束 *****/ 39 40 /******--------------- 3.公共參數封裝 開始 ------------------------*****/ //支付寶用 41 //1.商戶appid 42 bizModel.put("app_id",AlipayConfig.APPID); 43 //2.請求網關地址 44 bizModel.put("method",AlipayConfig.URL); 45 //3.請求格式 46 bizModel.put("format",AlipayConfig.FORMAT); 47 //4.回調地址 48 bizModel.put("return_url",AlipayConfig.return_url); 49 //5.私鑰 50 bizModel.put("private_key",AlipayConfig.RSA_PRIVATE_KEY); 51 //6.商家id 52 bizModel.put("seller_id","2088102170411333"); 53 //7.加密格式 54 bizModel.put("sign_type",AlipayConfig.SIGNTYPE+""); 55 56 /******--------------- 3.公共參數封裝 結束 ------------------------*****/ 57 58 //實例化客戶端 59 AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE); 60 61 //實例化具體API對應的request類,類名稱和接口名稱對應,當前調用接口名稱:alipay.trade.app.pay 62 AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest(); 63 64 //SDK已經封裝掉了公共參數,這裏只需要傳入業務參數。以下方法為sdk的model入參方式(model和biz_content同時存在的情況下取biz_content)。 65 AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); 66 model.setPassbackParams(URLEncoder.encode((String)orderMap.get("body").toString()));; //描述信息 添加附加數據 67 model.setBody(orderMap.get("body")); //商品信息 68 model.setSubject(orderMap.get("subject")); //商品名稱 69 model.setOutTradeNo(orderMap.get("out_trade_no")); //商戶訂單號(自動生成) 70 model.setTimeoutExpress(orderMap.get("timeout_express")); //交易超時時間 71 model.setTotalAmount(orderMap.get("total_amount")); //支付金額 72 model.setProductCode(orderMap.get("product_code")); //銷售產品碼 73 model.setSellerId("20881021********"); //商家id 74 ali_request.setBizModel(model); 75 ali_request.setNotifyUrl(AlipayConfig.notify_url); //回調地址 76 77 AlipayTradeAppPayResponse response = client.sdkExecute(ali_request); 78 orderStr = response.getBody(); 79 System.err.println(orderStr); //就是orderString 可以直接給客戶端請求,無需再做處理。 80 81 m.addAttribute("result",orderStr); 82 m.addAttribute("status",0); 83 m.addAttribute("msg","訂單生成成功"); 84 85 } catch (Exception e) { 86 m.addAttribute("status",1); 87 m.addAttribute("msg","訂單生成失敗"); 88 } 89 90 return m; 91 }
4.第2個異步回調接口
1 /** 2 * 支付寶支付成功後.回調該接口 3 * @param request 4 * @return 5 * @throws IOException 6 */ 7 @RequestMapping(value="api/alipay/notify_url",method={RequestMethod.POST,RequestMethod.GET}) 8 @ResponseBody 9 public String notify(HttpServletRequest request,HttpServletResponse response) throws IOException { 10 Map<String, String> params = new HashMap<String, String>(); 11 //1.從支付寶回調的request域中取值 12 Map<String, String[]> requestParams = request.getParameterMap(); 13 14 for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) { 15 String name = iter.next(); 16 String[] values = requestParams.get(name); 17 String valueStr = ""; 18 for (int i = 0; i < values.length; i++) { 19 valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; 20 } 21 // 亂碼解決,這段代碼在出現亂碼時使用。如果mysign和sign不相等也可以使用這段代碼轉化 22 // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk"); 23 params.put(name, valueStr); 24 } 25 //2.封裝必須參數 26 String out_trade_no = request.getParameter("out_trade_no"); // 商戶訂單號 27 String orderType = request.getParameter("body"); // 訂單內容 28 String tradeStatus = request.getParameter("trade_status"); //交易狀態 29 30 //3.簽名驗證(對支付寶返回的數據驗證,確定是支付寶返回的) 31 boolean signVerified = false; 32 try { 33 //3.1調用SDK驗證簽名 34 signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET); 35 } catch (AlipayApiException e) { 36 e.printStackTrace(); 37 } 38 //4.對驗簽進行處理 39 if (signVerified) { //驗簽通過 40 if(tradeStatus.equals("TRADE_SUCCESS")) { //只處理支付成功的訂單: 修改交易表狀態,支付成功 41 Trade trade = tradeService.selectByOrderNumber(out_trade_no); 42 trade.setTradeStatus((byte)3); //支付完成 43 int returnResult = tradeService.updateByPrimaryKeySelective(trade); //更新交易表中狀態 44 if(returnResult>0){ 45 //response.getWriter().write("SUCCESS"); 46 return "success"; 47 }else{ 48 //response.getWriter().write("fail"); 49 return "fail"; 50 } 51 }else{ 52 return "fail"; 53 } 54 } else { //驗簽不通過 55 //response.getWriter().write("fail"); 56 System.err.println("驗簽失敗"); 57 return "fail"; 58 } 59 }
5.第3個同步通知接口
1 /** 2 * 支付寶支付成功後.通知頁面 3 *@param request 4 *@return 5 *@throws UnsupportedEncodingException 6 */ 7 @RequestMapping(value="api/alipay/return_url",method={RequestMethod.POST,RequestMethod.GET}) 8 @ResponseBody 9 public Model returnUrl(HttpServletRequest request,Model model) throws UnsupportedEncodingException { 10 System.err.println("同步通知。。。"); 11 try { 12 //1.從支付寶同步的request域中取值 13 Map properties = request.getParameterMap(); 14 //2.封裝成Map 15 Map<String, String> returnMap = new HashMap<String, String>(); 16 Iterator entries = properties.entrySet().iterator(); 17 Map.Entry entry; 18 String name = ""; 19 String value = ""; 20 while (entries.hasNext()) { 21 entry = (Map.Entry) entries.next(); 22 name = (String) entry.getKey(); 23 Object valueObj = entry.getValue(); 24 //對返回的值進行判斷 25 if(null == valueObj){ 26 value = ""; 27 }else if(valueObj instanceof String[]){ 28 String[] values = (String[])valueObj; 29 for(int i=0;i<values.length;i++){ 30 value = values[i] + ","; 31 } 32 value = value.substring(0, value.length()-1); 33 }else{ 34 value = valueObj.toString(); 35 } 36 returnMap.put(name, value); 37 } 38 //3.返回到手機端 39 model.addAttribute("returnMap", returnMap); 40 model.addAttribute("msg", "查詢成功"); 41 model.addAttribute("status", 0); 42 } catch (Exception e) { 43 model.addAttribute("msg", "查詢失敗"); 44 model.addAttribute("status", 1); 45 } 46 47 return model; 48 }
二、流程分析:
1.配置文件AlipayConfig註意事項:
(1)註意沙箱環境和正式環境的不同:
商戶appid :
沙箱:進入沙箱環境會自動分配
正式:商戶唯一的標識
請求網關地址:
沙箱:https://openapi.alipaydev.com/gateway.do
正式:https://openapi.alipay.com/gateway.do
(2)公鑰和私鑰
公鑰和私鑰是自己生成的不要配錯,與支付寶的公鑰不要混淆了。(詳情見:https://docs.open.alipay.com/204/105297)
2. 本案例只是對支付進行說明,退款等功能可進行舉一反三編寫。
3.本人由於能力水平有限.有不到之處請大家多多指教!!!
支付寶app支付java後臺流程及原理分析