Springboot支付宝沙箱支付

420 阅读6分钟

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

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

1.1、进入个人沙箱环境

点击进入沙箱环境并用支付宝登陆\

第一步:配置沙箱应用环境

  1. 使用开发者账号登录 开放平台控制台 > 开发工具推荐,点击 沙箱 即可进入 沙箱环境

image.png

沙箱管理界面如图所示

image.png

image.png

  • appid,支付宝网关,自定义密钥等

appid,支付宝网关,自定义密钥等

这里是沙箱支付宝(虚拟)的账号和密码,可以用来支付

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

点击进入密钥工具 点击生成

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

应用私钥 应用公钥

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

进入最开始的沙箱管理界面,点击自定义密钥,点击设置(查看),我们选择的是RSA2密钥

选择“公钥”这一选项

将上一步骤生成的应用公钥填进来,会得到支付宝公钥这另一个密钥,记住并保存这个支付宝公钥

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

2、项目端的代码配置

2.1 maven 依赖

      <dependency>
                <groupId>com.alipay.sdk</groupId>
                <artifactId>alipay-sdk-java</artifactId>
                <version>4.16.2.ALL</version>
     </dependency>

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

  • APP_ID (appId,从沙箱管理页面获得)
  • APP_PRIVATE_KEY (应用私钥,最开始在密钥工具生成而来)
  • ALIPAY_PUBLIC_KEY (支付宝公钥,上一步骤获得)
  • GATEWAY_URL (支付宝网关地址,在开发平台沙箱管理页面中获得)
  • SIGN_TYPE (签名类型)
  • NOTIFY_URL (异步回调地址,须是公网IP,后面再解释)
  • RETURN_URL (同步回调地址,可以是私网IP)
package com.dm.sqlark.system.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 支付宝支付测试
 * @author luhui
 */

@RestController
@ApiSort(value = 101)
@Api(tags = "101.支付宝支付测试控制器")
@Slf4j
public class AliPayTestController {


    /**
     * appid
     */
    private final String APP_ID = "2021000122665251";
    /**
     * 应用私钥
     */
 private final String APP_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQChMDdq+vWT3c1GIbmQJVj4BM3OpnBc+HovRIVUpvnpgazcDLabX2UmN8UQAE35FmD6t8ApDRHsON8T7NfykUCjAqirUSVghXFPozOut0i3Lpdt1RiTjtMo4Jne8ZTlxSxSdfj7TGnK49+ESoK9VmYVQb8JF9mUdaMl/wa4vTv/N1Gqh+d5v5xF/oOlq89GP1SPQ7zwogbyaS69qNcKgep/5eJlrFHMyvvo5BSF5eKufJ6BkyaK6qfBQp+R4LnQy4hCcKnqXeqw9CGA2UCsz+ajueH900kgG+YOgwRlHSDFAyoKLGMS6v/H+o8TD6vmVmNmMGeB0kGecZltKxxX8icDAgMBAAECggEAKskVrLv4u8tAVcFV9EE1oIAF8TiU0tjR9gIGMjYwWB8ntzFYt11XCBH9qQWrrNaX33Uu+LaTb1SZQjy4BZcwxRRLmU3s0fYZ4b28VkAoeRdQ8sKBx4k927fioB8YGvV/klPmRy49VrGt/vuYQJHSfwn4n31JL/MZ31gWfKseZdvoGnkOkD1Bz4dz2p0Z/zYc/FDeOJGcnmFcN+3K1kZ6DJspir6+u+MzMWk7A5uhJEy323O5jsPyE94FyLLX4mt3wJvsEwN2aIWHPBu8NkjPov5USrzIyutYIPCztHTbIljRB9h203sLasqZ/9VDzB0c2vAielaV+alb/mscqQxXoQKBgQDtKDlBaTHDXLAR4L6oHh3NAR2NXv/WRw8L6K83VFAbo7LtZvrIOU/aRzM9ZtIxK8wHvLtAyms2L0LG7uZKJeTyyse+uMIa8jPihAMX1+H7VpsYxei3I90mSNKlg0sBzJl0vTNSg9IkbiZ5HuOOprz7litfztMlcCYdLKdTgzsL/wKBgQCt/smoz+yHjLHQ7A6UKyGk85qF168ufdIuO4uvEwEBQuYqpqDqfI3sLIuDo8bOS80TrRGCtLPwIYI0uArZx+4lNmJjtEs0o3Be/FJqutZnctK+fU0dnYffUbblIlPdDeYn9U1grIBqPvTrmDzHOkm/hPQObqO/lX5R0HNf/di0/QKBgQCSnFJBCMo1zyAd/UWAYxXjPXRKiFc63bUElLV1TA819w5PS2Fv1FZ0R536sIzyzvOUOO2+ESUUW0U5/EirwB94pTm0wz1kMSU4PIo4/EH9Aj5hoz/JsEcwOsbWgYMmOpkHnUuUEGAiG2J3cEwXTSb5lY187jyEIX++e3N54l/newKBgQCscIH9eyvo3whvjTOZpvFuIDu5gBvPEMWYKk1yknwBewLPrFp4aj7hnPgb29mxJLC3WmOrTVmzmBIKG4gtdBbR7IcwV0PdhEle6eTogAjzd3njbh1aR4CcU8jWZ+IDh73dRiCMugl+wqxLPZKmxF7In4SdOBIazvxRMzHo9Xc9zYJpap3c/43mr8lyOmJlRSl2/CYH1Nwex9gXIvtS5YENTplQa9T6FKD0H7md1R9MFjh+TejNDbg7CgME";

    /**
     * 编码
     */
    private final String CHARSET = "UTF-8";
    /**
     * 支付宝公钥
     */
    private final String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu0pi+itnyNHGVHj6EmhyG4zOTfPgsBk5fMpFelBegRdXto5GThAMSmwAmvFnaaLypd+Uf5LHHhilnZ1U2ghGm+VApbzf//qezHvF+bNHY1AolFyKlET9QQNE5c0lpDSE3Mo0iJxdwZgPIvHKqnyL9NoqU4791ALZTmaNZ2EArrbkVSozZ6X64HU6dDdYpACE19xci17DZUFs8J3f4y78aSrG5zUcrh0EOSeoJMUb3MGM4MDMA+EQrcuOEvIjHYfcZKUDCmIK3/S9iT6VP8b6s6mWXtYR2sLPsqAzEX99mmrZZGJQeYhgEHn3otyZI2H9im8QmtR0aZPxedZdlwIDAQAB";

    /**
     * 这是沙箱接口路径,正式路径为https://openapi.alipay.com/gateway.do
     */
    private final String GATEWAY_URL ="https://openapi-sandbox.dl.alipaydev.com/gateway.do";

    /**
     * 格式化
     */
    private final String FORMAT = "JSON";
    /**
     * 签名方式
     */
    private final String SIGN_TYPE = "RSA2";
    /**
     * 支付宝异步通知路径,付款完毕后会异步调用本项目的方法,必须为公网地址
     */
    private final String NOTIFY_URL = "http://www.sqlark.com/website/testHook";
    //

    /**
     * 支付宝同步通知路径,也就是当付款完毕后跳转本项目的页面,可以不是公网地址
     */
    private final String RETURN_URL = "http://localhost:6767/returnUrl";
    

    @ResponseBody
    @RequestMapping("/pay/alipay")
    public String alipay(HttpSession session,
                         @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 sendRequestToAlipay2(OrderNum,dona_money,"ghjk");
    }


    /**支付宝官方提供的接口,调整到支付宝页面,输入账号密码进行支付
     * @param outTradeNo 订单号
     * @param totalAmount 订单金额
     * @param subject  订单名称
     * @return
     * @throws AlipayApiException
     */
    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;
    }


    /**
     * 支付宝生成一个地址,扫码支付
     * @param outTradeNo
     * @param totalAmount
     * @param subject
     * @return
     * @throws AlipayApiException
     */
    private String sendRequestToAlipay2(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);

        AlipayTradePrecreateRequest alipayRequest = new AlipayTradePrecreateRequest();
        alipayRequest.setReturnUrl(RETURN_URL);
        alipayRequest.setNotifyUrl(NOTIFY_URL);

        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setOutTradeNo(outTradeNo);
        model.setTotalAmount(totalAmount.toString());
        model.setSubject(subject);
        alipayRequest.setBizModel(model);
        AlipayTradePrecreateResponse response = alipayClient.execute(alipayRequest);
        return response.getQrCode();
    }

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

        // 获取支付宝GET过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> 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";
        }
    }
}

2.3 下载支付沙箱App 登录沙箱账号

image.png

扫码下载,安装

2.4 扫码支付测试

1、访问 http://localhost:6767/pay/alipay?dona_money=10.2&dona_id=1

返回结果如下:

image.png

2、根据返回的Url 来生成二维码

访问 cli.im/url

image.png

3、登录沙箱 app 账号,进行扫码

1033b577e840a5768b79045b9625737.jpg

支付成功后,可以看到回调地址 image.png

2.5 pc端支付

1、调整控制器代码,重启应用

//调用封装好的方法(给支付宝接口发送请求)
    return sendRequestToAlipay(OrderNum,dona_money,"ghjk");

2、访问地址

http://localhost:6767/pay/alipay?dona_money=10.2&dona_id=1

跳转到页面

image.png

3、输入沙箱账号密码

image.png

4、支付成功后,回调到用户地址,当前地址可以不是公网地址

image.png

控制台输出如下:

\=================================同步回调=====================================
{charset=UTF-8, out\_trade\_no=2023060811310762338314203F4804A90B01C469BB351F, method=alipay.trade.page.pay.return, total\_amount=10.20, sign=T4VqLufnAUexj8i/rCuSGgR+VtzaleIj33hvSVCpn06OjUaX15W5HyL1UqOGK+SzRoDrx0MFZwCfF0tFX/CXQ3l2xLFOhLHzth2HSu2LqxjXXjWdCQg6udMh6J3pAn7FV3rqCd+pWA+eZFNMy1CovglEZ8RR2iRPh8z1k/oHUh/aKQ4VtkU45UXd6Gz0sL50Uv35r0UYNImAODORsq9HG4SyhinGlWKe3//TL7cW+ULzPkxHYuii4VhlCigsqmV2i5Dc4auHBlJEnkOHdgitARRBGjHjuuRs31mizacagQINwlNy63OZXh9BNHN0uI2gGLRmoEYKboCwFl0eJwlwOw==, auth\_app\_id=2021000122665251, trade\_no=2023060822001424540500151237, app\_id=2021000122665251, sign\_type=RSA2, version=1.0, seller\_id=2088721002424530, timestamp=2023-06-08 11:31:34}
商户订单号=2023060811310762338314203F4804A90B01C469BB351F
支付宝交易号=2023060822001424540500151237
付款金额=10.2