針對APP的後臺支付代碼(微信和支付寶)
阿新 • • 發佈:2018-11-13
pri pac edi all stat 微信開放平臺 gate java web 公鑰 APP支付:
1.微信支付:
這是app支付時,一個完整的流程
1.1首先要去微信開放平臺註冊,並創建APP
1.2取得微信支付的權限
1.3 商戶平臺有公眾號平臺和APP平臺兩種,一定要是APP平臺,可以在下面這個地方查看
1.4 我們需要在商戶平臺和開放平臺上獲取到以下數據:
開放平臺:
APPID、APP_SECRET:見1圖。
商戶平臺:
秘鑰(APP_KEY):微信商戶平臺(pay.weixin.qq.com)-->賬戶設置-->API安全-->密鑰設置
商戶號(MCH_ID):微信商戶平臺(pay.weixin.qq.com)-->賬戶設置-->商戶信息-->微信支付商戶號
數字證書(微信退款需要使用):微信商戶平臺(pay.weixin.qq.com)-->賬戶設置-->API安全-->證書下載
2.支付寶的操作流程簡單,文檔清楚(略)
3準備工作結束,我的產品是使用Hbuilder開發的HTML5的APP,後端是依托於Java Web程序。工作流程參照時序圖。主要代碼如下,詳情見文件
其中用到一些工具方法 或者客戶端創建代碼都在鏈接裏面有,我放在了碼雲上面 https://gitee.com/muziTM/payDemo
3.1 入口
/** * 支付類 包含支付寶和微信 * @author Tianming_Li **/ @Controller @RequestMapping("/payController") public class PayController { //訂單 @Autowired OrdersService orderService; //付費 @Autowired PayService payService; //退費 @Autowired RefundService refundService; //支付成功回調 @Autowired CallBackService callBackService;/** * 下單 * @param outTradeNo * @param payType * @param request * @param response * @param modelMap * @return */ @RequestMapping("/pay") public String pay(@RequestParam(name="outTradeNo") String outTradeNo,@RequestParam(name="payType") String payType, HttpServletRequest request,HttpServletResponse response, ModelMap modelMap){ //根據訂單號獲取到訂單信息 Orders order = orderService.selectOrdersInfoByOutTradeNo(outTradeNo); if("wxpay".equals(payType)){ return payService.wxPay(order, request, response, modelMap); }else{ return payService.aliPay(order); } } /** * 退款 * @param outTradeNo * @param payType * @param request * @param response * @return */ @RequestMapping("/refunds") public String refunds(@RequestParam(name="outTradeNo") String outTradeNo,@RequestParam(name="payType") String payType, HttpServletRequest request,HttpServletResponse response){ //根據訂單號獲取到訂單信息 Orders order = orderService.selectOrdersInfoByOutTradeNo(outTradeNo); if("wxpay".equals(payType)){ return refundService.wxRefund(order, request, response); }else{ return refundService.aliRefund(order); } } /** * 接收微信支付成功通知 * * @param request * @param response * @throws IOException */ @RequestMapping(value = "/getWxPayNotify") public void getWxPayNotify(HttpServletRequest request, HttpServletResponse response) throws IOException { callBackService.wxCallBack(request, response); } /** * 接收支付寶支付成功回調 * @param request * @param response * @throws IOException */ @RequestMapping("/getAliPayNotify") public void getAliPayNotify(HttpServletRequest request, HttpServletResponse response) throws IOException { callBackService.aliCallBack(request, response); } }
3.2 支付代碼
/** * 支付處理 * @author Tianming_Li * */ @Service("payService") public class PayServiceImpl implements PayService { protected static final Log logger = LogFactory.getLog(PayServiceImpl.class); @Override public String wxPay(Orders order, HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) { BaseDao dao = DaoUtils.getDao("sys"); StringBuilder sb = new StringBuilder(); sb.append("SELECT * FROM WX_PAY_CONFIG WHERE YY_ID = ‘"); sb.append(order.getYyId()); sb.append("‘"); //獲取到微信配置參數 WxPayConfig appPayConfig = dao.getObjectBySql(sb.toString(), WxPayConfig.class); Map<String, Object> map = new HashMap<String, Object>(); //初始化一個請求對象 WxRequestHandler wxRequestHandler = new WxRequestHandler(request, response); String payFee = order.getPayMoney(); int intPayFee = (int) (Float.valueOf(payFee) * 100); String nonceStr = WxUtils.getNonceStr(); String outTradeNo = order.getOutTradeNo(); String timestamp = WxUtils.getTimeStamp(); wxRequestHandler.setParameter("appid", appPayConfig.getAppId());//appId wxRequestHandler.setParameter("mch_id", appPayConfig.getMchId());//商戶號 wxRequestHandler.setParameter("nonce_str", nonceStr);//隨機字符串 wxRequestHandler.setParameter("body", appPayConfig.getBody());//商品描述 wxRequestHandler.setParameter("notify_url", appPayConfig.getNotifyUrl());//通知地址 wxRequestHandler.setParameter("out_trade_no", outTradeNo); wxRequestHandler.setParameter("spbill_create_ip", request.getRemoteAddr()); wxRequestHandler.setParameter("total_fee", String.valueOf(intPayFee)); wxRequestHandler.setParameter("trade_type", "APP"); //註意簽名生成方式,具體見官方文檔 wxRequestHandler.setParameter("sign", wxRequestHandler.createMD5Sign(appPayConfig.getAppKey())); String prepayid; try { prepayid = wxRequestHandler.sendPrepay(); if (prepayid != null && !prepayid.equals("")) { String signs ="appid=" + appPayConfig.getAppId() + "&noncestr=" + nonceStr + "&package=Sign=WXPay" + "&partnerid="+ appPayConfig.getPartnerId() //商戶id + "&prepayid=" + prepayid + "×tamp=" + timestamp + "&key=" + appPayConfig.getAppKey();//商戶平臺---api安全---密鑰 map.put("code", 200); map.put("info", "success"); map.put("prepayid", prepayid); map.put("sign", WxUtils.getMD5Encode(signs, "utf8").toUpperCase()); map.put("appid", appPayConfig.getAppId()); map.put("timestamp", timestamp); // 等於請求prepayId時的time_start map.put("noncestr", nonceStr); // 與請求prepayId時值一致 map.put("package", "Sign=WXPay"); // 固定常量 map.put("partnerid", appPayConfig.getPartnerId());//商戶id } else { map.put("code", 400); map.put("info", "獲取prepayid失敗"); } } catch (Exception e) { map.put("code", 405); map.put("info", "系統異常"); } return JSONUtils.toJSON(map); } @Override public String aliPay(Orders order) { //獲取配置參數 BaseDao dao = DaoUtils.getDao("sys"); StringBuilder sb = new StringBuilder(); sb.append("SELECT * FROM ALI_PAY_CONFIG WHERE YY_ID = ‘"); sb.append(order.getYyId()); sb.append("‘"); AliPayConfig appPayConfig = dao.getObjectBySql(sb.toString(), AliPayConfig.class); // 實例化客戶端(參數:網關地址、商戶appid、商戶私鑰、格式、編碼、支付寶公鑰、加密類型),為了取得預付訂單信息 AlipayClient alipayClient = new DefaultAlipayClient(appPayConfig.getUrl(), appPayConfig.getAppId(), appPayConfig.getRsaPrivateKey(), appPayConfig.getFormat(), appPayConfig.getCharset(), appPayConfig.getPublicKey(), appPayConfig.getSigntype()); // 實例化具體API對應的request類,類名稱和接口名稱對應,當前調用接口名稱:alipay.trade.app.pay AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); // SDK已經封裝掉了公共參數,這裏只需要傳入業務參數。以下方法為sdk的model入參方式(model和biz_content同時存在的情況下取biz_content)。 AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); //銷售產品碼,商家和支付寶簽約的產品碼,為固定值QUICK_MSECURITY_PAY BeanUtils.copy(order, model);//將訂單信息復制到model類中 request.setBizModel(model); // 回調地址 指向回調函數 example: https://ip:port/payController/getAliPayNotify.do request.setNotifyUrl(appPayConfig.getNotifyUrl()); String orderStr = ""; try { // 這裏和普通的接口調用不同,使用的是sdkExecute AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request); orderStr = response.getBody(); logger.info("訂單str:" + orderStr); } catch (AlipayApiException e) { logger.info(e.getMessage()); } return orderStr; } }
3.2回調代碼
@Service("callBackService") public class CallBackServiceImpl implements CallBackService { private static final Log LOGGER = LogFactory.getLog(CallBackServiceImpl.class); public static final String SUCCESS = "SUCCESS"; @SuppressWarnings("unchecked") @Override public void wxCallBack(HttpServletRequest request, HttpServletResponse response) throws IOException { PrintWriter writer = response.getWriter(); InputStream inputstream = request.getInputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] b = new byte[1024]; int len = 0; while((len = inputstream.read(b))!= -1){ outputStream.write(b, 0, len); } String result = new String(outputStream.toByteArray(), "utf-8"); inputstream.close(); outputStream.close(); Map<String, String> map = null; //解析微信通知返回的信息 try { map = WxUtils.doXMLParse(result); } catch (JDOMException e) { LOGGER.info("微信回調失敗:"+e.getMessage()); } // 若支付成功,則告知微信服務器收到通知 if (SUCCESS.equals(map.get("return_code")) && SUCCESS.equals(map.get("result_code"))) { /** * ... * 回調業務 */ //微信會一直調用接口,直到我們返回SUCCESS String notifyStr = WxUtils.setXML(SUCCESS, ""); writer.write(notifyStr); writer.flush(); } } @Override public void aliCallBack(HttpServletRequest request, HttpServletResponse response) throws IOException { LOGGER.info("進入支付寶回調"); // 獲取支付寶GET過來反饋信息 String reqWay = ""; if ("GET".equals(request.getMethod())) { reqWay = "GET"; } Map<String, String> params = new HashMap<String, String>(); Map<?, ?> requestParams = request.getParameterMap(); for (Iterator<?> iter = requestParams.keySet().iterator(); iter.hasNext();) { String name = (String) iter.next(); String[] values = (String[]) requestParams.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } // 亂碼解決,這段代碼在出現亂碼時使用。如果mysign和sign不相等也可以使用這段代碼轉化 if ("GET".equals(reqWay)) { try { valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8"); } catch (UnsupportedEncodingException e) { LOGGER.info("不支持的編碼:" + e.getMessage()); } } params.put(name, valueStr); } String tradeNo = request.getParameter("trade_no"); // 支付寶交易號 String tradeStatus = request.getParameter("trade_status"); // 支付狀態 String outTradeNo = request.getParameter("out_trade_no"); // 系統訂單號 String sellerId = request.getParameter("seller_id"); // 商戶號 LOGGER.info("支付寶交易號:" + tradeNo + ", 返回狀態:" + tradeStatus + ",訂單號 :" + outTradeNo); Map<String, Object> map = new HashMap<String, Object>(); String result = ""; try { if ("TRADE_SUCCESS".equals(tradeStatus)) { /** * ... * 回調業務 */ } else { result = "fail";// 為了保證不重復回調 } } catch (Exception e) { result = "fail"; } map.put(result, result); AliUtils.renderText(response, result); } }
3.4 微信退費的時候需要證書,密碼默認是商戶號,由於項目中使用了多個微信商戶號,因此有多個證書,路徑和密碼放在了數據庫中
public class WxRequestHandler{ /** * 退費 * @return */ public Map<String,String> sendWxChanel(String filePath,String pwd) throws Exception{ Map<String,String> map =null; Set es=this.getAllParameters().entrySet(); Iterator it=es.iterator(); StringBuilder sb = new StringBuilder("<xml>"); while(it.hasNext()){ Map.Entry entry = (Map.Entry) it.next(); String k = (String) entry.getKey(); String v = (String) entry.getValue(); sb.append("<"+k+">"+v+"</"+k+">"); } sb.append("</xml>"); String params=sb.substring(0); String requestUrl = this.getGateUrl(); TenpayHttpClient httpClient = new TenpayHttpClient(); httpClient.setReqContent(requestUrl); String resContent = ""; //filepath 文件路徑 pwd 密碼 if (httpClient.callHttpPost(requestUrl, params,true,filePath,pwd)) { resContent = httpClient.getResContent(); map=WxUtils.doXMLParse(resContent); } return map; } }
針對APP的後臺支付代碼(微信和支付寶)