最近在忙于做毕业设计,刚好用到支付宝充值功能,就过来写个帖子。
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; }
跳转到支付页面:
完成支付后自动跳转到原来页面:
哈哈,界面过于丑陋,咋们不要注重外表。前端页面基本上都是自己一点一点组装起来的,现在看到前端头疼,索性丑就丑点吧。