• Springboot支付宝沙箱支付---完整详细步骤


    1、进入支付宝开发平台—沙箱环境

    沙箱环境-支付宝文档中心

    1.1、进入个人沙箱环境

    点击进入沙箱环境并用支付宝登陆
    在这里插入图片描述
    沙箱管理界面如图所示

    • appid,支付宝网关,自定义密钥
      在这里插入图片描述

    • 这里是沙箱支付宝(虚拟)的账号和密码,可以用来支付
      在这里插入图片描述

    1.2、接下来进行几个密钥的生成

    点击进入密钥工具
    点击生成
    在这里插入图片描述

    这时我们拿到两个密钥,将它们保存,这两个密钥很重要

    • 应用私钥
    • 应用公钥

    1.3、拿到两个密钥后,进行自定义密钥配置

    进入最开始的沙箱管理界面,点击自定义密钥,点击设置(查看),我们选择的是RSA2密钥
    在这里插入图片描述
    选择“公钥”这一选项
    在这里插入图片描述
    将上一步骤生成的应用公钥填进来,会得到支付宝公钥这另一个密钥,记住并保存这个支付宝公钥
    在这里插入图片描述

    1.4、至此,我们沙箱环境的配置和基本参数都已经获取到。

    2、项目端的代码配置

    2.1、首先导入支付宝支付的依赖到pom.xml中

    这里我用的是springboot+maven+themyleaf项目

            
            
                com.alipay.sdk
                alipay-sdk-java
                4.16.2.ALL
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.2、创建支付的Controller类

    • 将从Controller中进入支付宝支付,需完成支付宝提供的接口
    • 创建PayController类,有如下代码

    创建Controller类后,首先设置如下私有属性

    • APP_ID (appId,从沙箱管理页面获得)

    • APP_PRIVATE_KEY (应用私钥,最开始在密钥工具生成而来)

    • ALIPAY_PUBLIC_KEY (支付宝公钥,上一步骤获得)

    • GATEWAY_URL (支付宝网关地址,在开发平台沙箱管理页面中获得)

    • SIGN_TYPE (签名类型)

    • NOTIFY_URL (异步回调地址,须是公网IP,后面再解释)

    • RETURN_URL (同步回调地址,可以是私网IP)

      @Controller
      public class PayController {
      @Autowired
      DonaItemService donaItemService;
      @Autowired
      DonaService donaService;
      //appid
      private final String APP_ID = “2021000119625133”;
      //应用私钥
      private final String APP_PRIVATE_KEY = “MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCDA1Y0+IjB/z4sIhJA0sgEaNGXV9+8t0fUMhrbjHjW88tz8d7jR8ev1aFMmyDKy/cSnlsoNDLwx71GCLiNQENYTvqdcsrYLMvQkmeIYT1OWcPYSl65P0TQRDBhakVdAIXvnts7KJ/nCROGMy8qrBG8ilSlNaOkiuXgp1OPIqLe2dCkrJp1spOJ3Wfq9uyqJO5xrgx6tby3MVPLu/nJ2PtzXt62Kpcj/S9Xxxk9FXOw8cwGDStMPU471VKpEP4kMnjfpUpB9/FfQ6oDfokIaq9dehN9xSitAD6p5cFct7oG94DHai5a+ST6X+OfTv03oE2DuA7ejaJn6cDGSB4IYmZRuDGdicqmPmLEHt3Kq79+EPxBYKUcWI4zQPXlA06Kcgb8HrJntjC836svSUrewWaG32g5MlJB8e1Z+1yL75E6k6R4rBJiVW2MC5VW+p/nQiY3FLfRq4a8V+VJ9uXM1h7L8TbOHtCAQKBgQDCSljMB8VnLFMKHOrcHCZNtjnDHsRYJQYEgNhhvwx2xUIgZNhzpiDmUSwR4TOaqF+Eg5bLfC+sQboANXpP5YUyt/rqUWqQ1fmEV5US9cfiYOi5rfjETK0q6VwagYRjXe84e039Q+D8bGypY+T+uuzFcJjudfWTjBkvkOzwt57/4QKBgQCsn/BLJvO4zueqIF/A5lHdA0R3C8K9ipNjmg9LvU3/5ZXOYx//CcLk82s83C2j9rgQKBgQCNTcaW3eW3K7a6rhFzh5UPQzoX+7VFfqR0BbEFtN7Pr/spZ/X4YVqWRyvkaZbC/9frRnEAKSXLP/pN1b9F1tdMa/2iUgefi3XMJ/z4v0T4iqE58A57UEEH68JMVYuNq5kwVnnZ9FONzhpbRftJuIRAJZaqAVZ0b0PAOMoQpNSbiQKBgHtAnpTuE0QFby+7hDsnTz+qC9dyQQWH3cBOn4RQzo1DUxvyQpZjAy0Oqn/F5x6RGMQU6SrirdUQbGWcANOpp9/L3YGHUrUjlT5Ehx2nPO//yTZSTWKM+p6+XALn1DGZbTChnL/5aEZsg5R4f55wL6RYezRzhq+w4wMixTQDyFLZ”;
      private final String CHARSET = “UTF-8”;
      // 支付宝公钥
      private final String ALIPAY_PUBLIC_KEY = “MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3CPgueDLkfB66s9ZsEUwyUbmkRknTFVyuBG4PkKI93OTOVC457ijEKknRYi8eKYo4Wl+7z4/nRXYCxc9XBynqtnJzronKm9Wv+7sswJI6g3Qn2SdjFxWHoQDrEqXKQALv2YVqE7R+BZqTS5TkDerQI1l+Nq3m7oemztrlx+96iAR5KxYO+tTr1u3XQZmjtjlqbty50DmxRCgEqJKYEu6CD+r1vi+2SXOUKnCJzsE8vHojS+Vk5oGbZYnX6Esw2TVeiCkmQ814CBwIDAQAB”;
      //这是沙箱接口路径,正式路径为https://openapi.alipay.com/gateway.do
      private final String GATEWAY_URL =“https://openapi.alipaydev.com/gateway.do”;
      private final String FORMAT = “JSON”;
      //签名方式
      private final String SIGN_TYPE = “RSA2”;
      //支付宝异步通知路径,付款完毕后会异步调用本项目的方法,必须为公网地址
      private final String NOTIFY_URL = “http://127.0.0.1/notifyUrl”;
      //支付宝同步通知路径,也就是当付款完毕后跳转本项目的页面,可以不是公网地址
      private final String RETURN_URL = “http://localhost:8080/returnUrl”;
      }

    2.3、在Controller类中创建点击支付跳转支付宝页面的方法

       //必须加ResponseBody注解,否则spring会寻找thymeleaf页面
        @ResponseBody
        @RequestMapping("/pay/alipay")
        public String alipay(HttpSession session,Model model,
                             @RequestParam("dona_money") float dona_money,
                            @RequestParam("dona_id") int dona_id) throws AlipayApiException {
            //把dona_id项目id 放在session中
            session.setAttribute("dona_id",dona_id);
    
            //生成订单号(支付宝的要求?)
            String time = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
            String user = UUID.randomUUID().toString().replace("-","").toUpperCase();
    
            String OrderNum = time+user;
    
            //调用封装好的方法(给支付宝接口发送请求)
            return sendRequestToAlipay(OrderNum,dona_money,"ghjk");
        }
            /*
        参数1:订单号
        参数2:订单金额
        参数3:订单名称
         */
         //支付宝官方提供的接口
        private String sendRequestToAlipay(String outTradeNo,Float totalAmount,String subject) throws AlipayApiException {
            //获得初始化的AlipayClient
            AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL,APP_ID,APP_PRIVATE_KEY,FORMAT,CHARSET,ALIPAY_PUBLIC_KEY,SIGN_TYPE);
    
            //设置请求参数
            AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
            alipayRequest.setReturnUrl(RETURN_URL);
            alipayRequest.setNotifyUrl(NOTIFY_URL);
    
            //商品描述(可空)
            String body="";
            alipayRequest.setBizContent("{"out_trade_no":"" + outTradeNo + "","
                            + ""total_amount":"" + totalAmount + "","
                            + ""subject":"" + subject + "","
                            + ""body":"" + body + "","
                            + ""product_code":"FAST_INSTANT_TRADE_PAY"}");
    
            //请求
            String result = alipayClient.pageExecute(alipayRequest).getBody();
            return result;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    解释,在前端页面点击支付后,将跳转Controller的==alipay()==方法

    • alipay 方法会接收一些前端的参数
    • alipay方法中再调用sendRequestToAlipay方法,sendRequestToAlipay方法中有支付宝官方给出的接口,只需在其中提供一些参数(支付宝严格规定的参数)

    在这里插入图片描述

    sendRequestToAlipay方法

    • 除了需要提供之前设置好的私有属性(URL,公钥,私钥,网关等等)外,还需要提供的参数
    • outTradeNo,订单号,必须为String64位,不能为空且不能重复
    • totalAmount,支付金额,不能为空
    • subject,订单名称,不能为空
    • body,商品描述,可以为空

    上面三个必填参数很重要且必须遵守支付宝的规定,在扫码支付的时候能看到且有用

    在这里插入图片描述

    跳转支付宝方法设置完毕,可以进行测试,首先我们在前端form表单中填入url访问刚刚写的controller方法

    图示使用thymeleaf模板引擎
    在这里插入图片描述

    • 设置完毕后,启动项目,点击提交表单

    在这里插入图片描述
    该页面访问的是支付宝官方提供的页面,至此沙箱支付已经完成了一半,接下来还要写return()方法使我们完成支付后有响应和页面跳转。

    2.4、登陆支付宝沙箱账号

    由于是沙箱环境,是虚拟的,所以上面那个支付宝扫码不能用真的支付宝去扫,而是需要下载一个沙箱支付宝APP
    在这里插入图片描述
    扫码进行下载
    在这里插入图片描述
    下载完成后的登陆账号密码,也是沙箱环境的账号和密码,同时支付时使用的密码也在其中
    在这里插入图片描述

    2.5、写支付完成后同步回调的方法

    • 扫码(或输入密码)支付完成后,支付宝会自动调用我们之前设置好的RETURN_URL(其实是本机调用),所以这个地址可以是私网地址

    在这里插入图片描述

    • 如图所示,RETURN_URL的值为http://localhost:8080/returnUrl,所以我们在项目中完成这个方法的书写,让其调用

    • 同样,还是在Controller中完成

      @RequestMapping(“/returnUrl”)
      public String returnUrlMethod(HttpServletRequest request,HttpSession session,Model model) throws AlipayApiException, UnsupportedEncodingException {
      System.out.println(“=同步回调=====”);

          // 获取支付宝GET过来反馈信息
          Map params = new HashMap();
          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);
          }
      
          System.out.println(params);//查看参数都有哪些
          //验证签名(支付宝公钥)
          boolean signVerified = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, SIGN_TYPE); // 调用SDK验证签名
          //验证签名通过
          if(signVerified){
              // 商户订单号
              String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
      
              // 支付宝交易流水号
              String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
      
              // 付款金额
              float money = Float.parseFloat(new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8"));
      
              System.out.println("商户订单号="+out_trade_no);
              System.out.println("支付宝交易号="+trade_no);
              System.out.println("付款金额="+money);
      
              //在这里编写自己的业务代码(对数据库的操作)
      		/*
      		################################
      		*/
              //跳转到提示页面(成功或者失败的提示页面)
              model.addAttribute("flag",1);
              model.addAttribute("msg","支持");
              return "common/payTips";
          }else{
              //跳转到提示页面(成功或者失败的提示页面)
              model.addAttribute("flag",0);
              model.addAttribute("msg","支持");
              return "common/payTips";
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
    • 图示框住的部分代码都是支付宝官方给出的一些回调操作,所以最好不要进行更改,个别参数的名称可以更改

    在这里插入图片描述
    在这里插入图片描述

    • 对数据库进行操作的代码可以在该方法中进行,也可以在异步回调方法中进行
    • 最后返回部分我返回的是thymeleaf页面,如果想直接返回String字符串或者其他类型数据库,可以在方法前面加上@ResponseBody注解

    2.6、异步回调方法

    • 上面为支付宝同步调用处理,但是官方建议应在异步调用方法中处理付款成功后的操作,但因异步调用的路径必须为公网地址,支付宝才可以发送请求给我们,故这里不写异步调用的方法了,需要注意的是,异步调用为post请求,且传递来的参数会多一些,但基本与同步调用的操作一致

    • 异步回调方法必须为公网IP,因为这个URL地址是支付宝官方来调用我们本机的,是我们完成支付操作后,支付宝需要进行一些金额的处理(与银行对接)所以需要几秒的时间,当支付宝处理完成后异步的调用我们的notify方法(一般在这个方法中进行数据库的操作),这个过程异步进行,所以用户一般感觉不到(用户感觉到的是同步调用的方法)。

    • 设置公网IP有两种方案,1、内网穿透,2、将项目部署到服务器,这里就不说了

    在这里插入图片描述

    • 如图为支付宝官方调用的图解

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    SecureCRT® 字选择和字定界符
    爬虫与反爬虫技术简介
    Android学习笔记 54. Gradle入门
    .net 6或5调用webservice自定义头。(金碟里的SessionId的传递)
    【Verilog】用双口RAM实现同步FIFO
    【论文笔记】Federated Learning for Wireless Communications: Motivation, Opportunities, and Challenges(综述)
    1.9、习题2-时延相关习题
    HTTPS协议的加密流程
    WPS论文编写问题集(参考文献制作、公式居中及编号、公式影响行间距...)_长期更新中ing...
    【发送邮件报错】535 Error:authentication failed
  • 原文地址:https://blog.csdn.net/m0_67402013/article/details/126114723