最近在忙於做畢業設計,剛好用到支付寶充值功能,就過來寫個帖子。
1.到支付寶網站注冊賬號
官網:https://openhome.alipay.com/platform/developerIndex.htm
2.點擊研發服務進入沙箱環境
配置RSA2,推薦使用支付寶提供的密匙工具。同步異步接口也可以不設置,下文會在java代碼中設置
這里異步調用接口需要公網可以訪問,如果經濟不允許的情況下可以使用花生殼內網穿透工具:
我的個人配置:開通HTTP協議需要花費6元永久域名
3.沙箱賬號
用於登錄沙箱版支付寶app測試
4.接入項目
創建一個配置類
/** * @author 碼農界的小學生 * @description:阿里支付配置信息 * @title: AliDevPayConfig * @projectName graduation-project * @description: TODO * @date 2020/4/23 19:06 */ @Configuration public class AliDevPayConfig implements Serializable { // 這個是支付完成后的跳轉路徑 可以是一個頁面地址等 public static String returnUrl = "http://www.graduation.com/#/addIncoming"; //服務器異步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問 // 這個是支付成功失敗以后的通知接口會返回相應的參數 public static String notifyUrl = "http://3111h4q179.zicp.vip/cms/alipay/notify"; /**支付寶分配給開發者的應用ID*/ public static String aliPayAppId = "你的appid"; /** * 商戶id */ public static String uid = "2088102180918899"; /**支付寶網關*/ public static String aliPayGateWay = "https://openapi.alipaydev.com/gateway.do"; public static String mcloud_api_domain = "http://mcloudmonitor.com/gateway.do"; /**私鑰*/ public static String aliPayPrivateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCtPPBOHRZyOPH2Qn4IAWmY+qrJaYSs5PZwRtAxm7oPcgChnacGr8uTZKtZtNFMwoI1RXqutWAWjMhVNHv9JcAdZbL7LsXO8AuP09YcFpGGXEWFoze3RGeN4Oiy1JhC21nkZONXn2RlmR44dHNLvH3p213MjR6omV16qG0SqFyCQ6m3DPVvXn+aclw+0vZPa6wvjKFn57WdgFrrwHSKMvuPoz5qW4Yv7wu4isXyOowczyfX0DERVvcdYdaIPUOEBEN6EcKbVq8/FC1zMq79REBU/iVtVjWunRe6FMq+jbzNsVvZdwm2FEG2hcnw+GmvZUMIstUf3dm3yZiMqULPCGf/AgMBAAECggEAdingx4czrkmFUTHdgVxlSMGCCMv+gWfTaJYEoDHWYX6jS5mbOgZi13CNKC0brj3mTqvLmKuClR8F7ohUIkHDnsmloYsvxY0adcpKevIx5PG/Qf4onMr9z1qfnotAKCoyUIU4RKYl9t7QLDXSBtDVGdRVUJbZWKrzhhyn+Vf5cafOyyQEgMAonAYqkLweZilyFO5TGlgLKJsKXhQjltZrPxVebQ9PowIz47NvQVOBya+WGTAkyN1Bri10ZLxr62VGhUjUGKcRL0qVxtaXpafARcW5HU1U/aJlkX9stHZwRlLsxdN5MV1DwlKInX9shYHOHheCsohlB7ZaZYmwrVulEQKBgQD1cmknrwkiYgocPq7NhQ89IddmWgduqkTE9FbaDXtM7YrvTIPGJDCE5d71R+sw8GG36M0OQxitdB72mbv6md+FxqmAtlD6d0L5V0mJfRErW4W48NhCI03XIWUcy3JrtqVF1N7qlB7D5IkW3DBqFVHf2iO97oMczhhsQsVnrH0VmwKBgQC0r7zyS6DwV1Pb8q3n1dmWD/wg4PuV35PC/uZ5CXiYWOcbaZZM1+3QQ56F/qZugwsb7aXbl7lL67hZ70GcQJPC8YBHebrBK9q/8C29TkPigzY0jWgM4rFbcb/raRKP3Oy1T4itIUH1/nuWwZT2AoT8lLRbLmeUeDCvg3GsbrhvbQKBgQCxhkvKOQ5pQPHBFhFGcsvf0l9CFzGy+BH/Rh6fXgrlTBYmGHhi0oAJT12gmKDiZ6q14vqVKzBpHEjc4bqVeb+yuUqV3sfZMHNPdrOobr4BVxPz/Lbdtz0wsWW5muiqQZNuW5XToshRtTT2RNH7mGn8d4FMeXt5VRNTEkRHRPm/qwKBgEXtGS+gCznYYhDmG110io+jwgyrZVI8Q4Aci+9dtfknttEKDOvSSSvnb2smAR0Vw+/cCesxDboPELpleLvS1hyEwANpXdgyc6cCeYEgz+7SnuC5tQH/nWnpXL/rWw6oDkeg7yEplNBx2zyd0Ftg4DysBByhmd6AoT7bnNuBwgkFAoGAVYXQYh+YgM5mKaagBZOWqwhkP4Pr8Oo44G5RaswP/O7R4ulgQ48BsaPifngek+tDTetX3nlZjogb1YtIEEJNJ1SSPsvEZGzR0cwgysp+wRjER5O+M2rvNWc3G+a4wM864eYuCq1n73xL9FqXYIJXjRlmLobejYiOqYa02bRIpQc="; /**支付寶公鑰 注意是支付寶公鑰 不是應用公鑰*/ public static String aliPayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAix4U83rjS6rT8w8njXFEU+SAYH/zCCRQc98PpUDEBBx3qY7CaJPL0QPETs1WyufqZYRSKbW0Ml9wTA/SXgOp3bJn5v78vhe2LSFtmr0gCyNJXtSDrz91XgR/oK3T5j0yy8NgOMBjdjnI2a6cpqrt3YXkc02hhJTfG+3o6f+gGw6wtU7CC0BTGoH//lk+prNerjeFQLZd7hB0ANlC5JdSfDBHtr/+gPcL7ap84nEJA1TSOCnQP8h2UYd5MAwqwyqitK3B9hEUCWI7Mp3VgI+CAGVXXnUzL74hUK26yrTczucX9bEPUUAyrlxWIUZ3OsX07KwpL1PLnKH/HYJStFG8TQIDAQAB"; public static String FORMAT = "JSON"; /**請求使用的編碼格式,如utf-8,gbk,gb2312等*/ public static String CHARSET = "utf-8"; /**商戶生成簽名字符串所使用的簽名算法類型,目前支持RSA2和RSA,推薦使用RSA2*/ public static String SIGN_TYPE = "RSA2"; }
Controller:
/** * @author 碼農界的小學生 * @description: * @title: PayController * @projectName graduation-project * @description: TODO * @date 2020/4/23 21:39 */ @RequestMapping("/cms/alipay") @RestController public class PayController implements PayControllerApi { @Autowired private PayService payService; @Override @RequestMapping(value = "/pay") public String aliPay(@RequestParam("id")String id, @RequestParam("type")String type,@RequestParam("money")String money) throws IOException { return payService.aliPay(id,type,money); } @Override @RequestMapping ("/notify") public void payNotice(HttpServletRequest request,HttpServletResponse response) throws Exception { payService.alipayNotify(request,response); } }
Service:
/** * @author 碼農界的小學生 * @description:調用支付寶接口業務邏輯 * @title: PayService * @projectName graduation-project * @description: TODO * @date 2020/4/23 21:43 */ @Service public class PayService { @Autowired private OrderClient orderClient; @Autowired private OrderCollectionRepository orderCollectionRepository; @Autowired private SuperRepository superRepository; @Autowired private UserRoleRepository userRoleRepository; @Autowired private UserRepository userRepository; /** * 調用支付寶接口 * @return */ public String aliPay(String id,String type,String money) { //非法參數 拋出異常 if(StringUtils.isEmpty(id) || StringUtils.isEmpty(type) || StringUtils.isEmpty(money)){ ExceptionCast.cast(CommonCode.INVALID_PARAM); } //實例化客戶端(參數:網關地址、商戶appid、商戶私鑰、格式、編碼、支付寶公鑰、加密類型),為了取得預付訂單信息 AlipayClient alipayClient = new DefaultAlipayClient(AliDevPayConfig.aliPayGateWay,AliDevPayConfig.aliPayAppId, AliDevPayConfig.aliPayPrivateKey,AliDevPayConfig.FORMAT,AliDevPayConfig.CHARSET,AliDevPayConfig.aliPayPublicKey, AliDevPayConfig.SIGN_TYPE); //實例化具體API對應的request類 AlipayTradePagePayRequest payRequest = new AlipayTradePagePayRequest(); payRequest.setNotifyUrl(AliDevPayConfig.notifyUrl); payRequest.setReturnUrl(AliDevPayConfig.returnUrl); //SDK已經封裝掉了公共參數,這里只需要傳入業務參數。以下方法為sdk的model入參方式 AlipayTradePagePayModel payModel = new AlipayTradePagePayModel(); //商戶訂單號 UUID uuid = UUID.randomUUID(); String uid = uuid.toString(); payModel.setOutTradeNo(uid); //對一筆交易的具體描述信息。這里存儲用戶id payModel.setBody(id); //商品名稱 payModel.setSubject(type); //交易超時時間 這里的30m就是30分鍾 payModel.setTimeoutExpress("30m"); //支付金額 后面保留2位小數點..不能超過2位 payModel.setTotalAmount(money); // //電腦網站支付銷售產品碼,不同的支付方式productCode不同 銷售產品碼(固定值) payModel.setProductCode("FAST_INSTANT_TRADE_PAY"); payRequest.setBizModel(payModel); try { // 這里和普通的接口調用不同,使用的是sdkExecute //返回支付寶訂單信息(預處理) AlipayTradePagePayResponse alipayTradePagePayResponse = alipayClient.pageExecute(payRequest); //就是orderString 可以直接給APP請求,無需再做處理。 String result = alipayTradePagePayResponse.getBody(); return result; }catch (Exception e){ e.printStackTrace(); } return null; } /** * 支付成功后接口回調 加上事務注解 * @param request * @return */ @Transactional public void alipayNotify(HttpServletRequest request, HttpServletResponse response) throws AlipayApiException, UnsupportedEncodingException { //獲取支付寶POST過來反饋信息 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] + ","; } //亂碼解決,這段代碼在出現亂碼時使用。 //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8"); params.put(name, valueStr); } //調用SDK簽名驗證 //切記alipaypublickey是支付寶的公鑰,請去open.alipay.com對應應用下查看。 //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type) boolean signVerified = AlipaySignature.rsaCheckV1(params, AliDevPayConfig.aliPayPublicKey, AliDevPayConfig.CHARSET,AliDevPayConfig.SIGN_TYPE); if(signVerified){ //商戶訂單號 String uid = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8"); //用戶id String userId = new String(request.getParameter("body").getBytes("ISO-8859-1"),"UTF-8"); //健身房會員卡類型 String type = new String(request.getParameter("subject").getBytes("ISO-8859-1"),"UTF-8"); //金額 String money = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8"); /*
這里編寫業務邏輯
*/ } } }
5.項目調用支付寶接口流程
前端項目調用方法請求/cms/alipay/pay ,然后跳轉到支付頁面,支付完成后會同步跳轉returnUrl返回到商品頁面。支付寶支付后會異步請求notifyUrl,這里通過花生殼內網穿透工具代理到/cms/alipay/notify,然后完成業務邏輯。
6.效果圖
點擊會員充值調用對應的js方法:
submitPay(item){ if (!this.params.id){ this.$message.error("請先登錄"); return ; } this.params.type = item.type; this.params.money = item.money; let querys = querystring.stringify(this.params); window.location ="http://www.graduation.com/cms/alipay/pay?"+querys; }
跳轉到支付頁面:
完成支付后自動跳轉到原來頁面:
哈哈,界面過於丑陋,咋們不要注重外表。前端頁面基本上都是自己一點一點組裝起來的,現在看到前端頭疼,索性丑就丑點吧。