• 支付宝沙箱环境配置

首先进入支付宝开放平台的沙箱支付(如果没有支付宝开发平台账号的需要注册,需要相应的认证信息填写)点击进入沙箱环境用支付宝登录。

点击沙箱工具后进入沙箱管理界面

这里的应用公钥需要下载一个工具获取密钥工具下载,下载安装之后打开软件是这样的界面

点击生成密钥。会得到一对密钥分别是应用公钥和应用私钥,应用公钥是生成支付宝公钥必需的前置条件,应用私钥是我们后面springboot集成支付宝支付需要的

按照步骤把应用公钥复制到开放平台中得到支付宝公钥,这一步就不在赘述。

  • 现在我们已经完成了沙箱环境的所有前置条件的获取,包括支付宝公钥,应用私钥,支付宝网关地址,appId,现在可以开始代码的编写了。

  • springboot 环境配置

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

在你的yml文件里面配置支付宝沙箱相关参数

alipay:
  appId: 
  appPrivateKey: 
  alipayPublicKey: 
  notifyUrl: #如果是在本地测试需要下载内网穿透工具,用来支付宝的调的回调接口

支付宝支付的相关配置代码AlipayConfig.java

@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {

    private String appId;
    private String appPrivateKey;
    private String alipayPublicKey;
    private String notifyUrl;

    public String getAppId() {
        return appId;
    }

    public void setAppId(String appId) {
        this.appId = appId;
    }

    public String getAppPrivateKey() {
        return appPrivateKey;
    }

    public void setAppPrivateKey(String appPrivateKey) {
        this.appPrivateKey = appPrivateKey;
    }

    public String getAlipayPublicKey() {
        return alipayPublicKey;
    }

    public void setAlipayPublicKey(String alipayPublicKey) {
        this.alipayPublicKey = alipayPublicKey;
    }

    public String getNotifyUrl() {
        return notifyUrl;
    }

    public void setNotifyUrl(String notifyUrl) {
        this.notifyUrl = notifyUrl;
    }
}

添加相关的支付接口

@RestController
@RequestMapping("/alipay")
public class AliPayController {

    // 支付宝沙箱网关地址
    private static final String GATEWAY_URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
    private static final String FORMAT = "JSON";
    private static final String CHARSET = "UTF-8";
    //签名方式
    private static final String SIGN_TYPE = "RSA2";

    @Resource
    private AliPayConfig aliPayConfig;

    @Resource
    private DonationProjectService ordersService;

    @Resource
    private DonationRecordService recordService;

    @GetMapping("/pay")
    public void pay(@RequestParam("projectId") Integer projectId, @RequestParam("userId") Integer userId,
                    @RequestParam("amount") BigDecimal amount, @RequestParam("username") String username,
                    @RequestParam("userImg") String userImg,
                    HttpServletResponse httpResponse) throws Exception {
        LambdaQueryWrapper<DonationProject> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DonationProject::getId, projectId);
        // 查询捐赠信息
        DonationProject orders = ordersService.getOne(queryWrapper);
        if (orders == null) {
            return;
        }
        // 生成捐赠记录
        DonationRecord donationRecord = new DonationRecord();
        donationRecord.setProjectId(projectId);
        donationRecord.setUserId(userId);
        donationRecord.setUsername(username);
        donationRecord.setUserImg(userImg);
        donationRecord.setAmount(amount);
        donationRecord.setPaymentNo(IdUtil.fastSimpleUUID());
        donationRecord.setPayStatus("待支付");
        donationRecord.setCreateTime(LocalDateTime.now());
        recordService.createRecord(donationRecord);

        // 1. 创建Client,通用SDK提供的Client,负责调用支付宝的API
        AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),
                aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);

        // 2. 创建 Request并设置Request参数
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setNotifyUrl(aliPayConfig.getNotifyUrl());
        JSONObject bizContent = new JSONObject();
        bizContent.set("out_trade_no", donationRecord.getPaymentNo());
        bizContent.set("total_amount", donationRecord.getAmount());
        bizContent.set("subject", orders.getTitle());   // 支付的名称
        bizContent.set("product_code", "FAST_INSTANT_TRADE_PAY");
        request.setBizContent(bizContent.toString());
        request.setReturnUrl("http://7g6zrz.natappfree.cc/alipay/redirect");
        // 执行请求,拿到响应的结果,返回给浏览器
        String form = "";
        try {
            form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        httpResponse.setContentType("text/html;charset=" + CHARSET);
        httpResponse.getWriter().write(form);
        httpResponse.getWriter().flush();
        httpResponse.getWriter().close();
    }

    @PostMapping("/notify")  // 注意这里必须是POST接口
    public void payNotify(HttpServletRequest request) throws Exception {
        if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
            System.out.println("=========支付宝异步回调========");

            Map<String, String> params = new HashMap<>();
            Map<String, String[]> requestParams = request.getParameterMap();
            for (String name : requestParams.keySet()) {
                params.put(name, request.getParameter(name));
            }

            String sign = params.get("sign");
            String content = AlipaySignature.getSignCheckContentV1(params);
            boolean checkSignature = AlipaySignature.rsa256CheckContent(content, sign, aliPayConfig.getAlipayPublicKey(), "UTF-8");
            // 支付宝验签
            if (checkSignature) {
                // 验签通过
                System.out.println("交易名称: " + params.get("subject"));
                System.out.println("交易状态: " + params.get("trade_status"));
                System.out.println("支付宝交易凭证号: " + params.get("trade_no"));
                System.out.println("商户订单号: " + params.get("out_trade_no"));
                System.out.println("交易金额: " + params.get("total_amount"));
                System.out.println("买家在支付宝唯一id: " + params.get("buyer_id"));
                System.out.println("买家付款时间: " + params.get("gmt_payment"));
                System.out.println("买家付款金额: " + params.get("buyer_pay_amount"));


                String tradeNo = params.get("out_trade_no");
                String gmtPayment = params.get("gmt_payment");
                String alipayTradeNo = params.get("trade_no");
                // 更新订单状态为已支付,设置支付信息
                LambdaQueryWrapper<DonationRecord> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(DonationRecord::getPaymentNo, tradeNo);
                DonationRecord record = recordService.getOne(queryWrapper);
                record.setPayStatus("捐赠成功");
                record.setPaymentTime(gmtPayment);
                record.setAlipayTradeNo(alipayTradeNo);
                recordService.updateById(record);

                // 更新捐赠项目
                DonationProject donationProject = ordersService.getById(record.getProjectId());
                donationProject.setCurrentAmount(donationProject.getCurrentAmount().add(record.getAmount()));
                donationProject.setDonationCount(donationProject.getDonationCount() + 1);
                // 判断是否达到目标金额,如果达到则更新状态为已完成
                if (donationProject.getCurrentAmount().compareTo(donationProject.getTargetAmount()) >= 0) {
                    donationProject.setStatus(1);
                }
                ordersService.updateById(donationProject);
            }
        }
    }

    /**
     * 支付成功跳转前端页面接口
     * @param request
     * @param response
     * @throws Exception
     */
    @GetMapping("/redirect")
    public void alipayRedirect(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 添加缓存控制头
        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Expires", "0");

        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            params.put(name, request.getParameter(name));
        }

        boolean signVerified = checkAlipaySignature(params);

        if (signVerified) {
            String orderNo = params.get("out_trade_no");
            LambdaQueryWrapper<DonationRecord> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DonationRecord::getPaymentNo, orderNo);
            DonationRecord record = recordService.getOne(queryWrapper);

            if (record != null && "捐赠成功".equals(record.getPayStatus())) {
                response.sendRedirect("http://localhost:8081/front/donation/detail/" + record.getProjectId());
            } else {
                response.sendRedirect("http://localhost:8081/404");
            }
        } else {
            response.sendRedirect("http://localhost:8081/404");
        }
    }

    private boolean checkAlipaySignature(Map<String, String> params) {
        try {
            String sign = params.get("sign");
            String content = AlipaySignature.getSignCheckContentV1(params);
            return AlipaySignature.rsa256CheckContent(
                    content,
                    sign,
                    aliPayConfig.getAlipayPublicKey(),
                    "UTF-8"
            );
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return false;
        }
    }

}

在你后端代码中的拦截器上忽略支付宝接口的配置

//允许直接访问的接口
                .excludePathPatterns(
                        "/sysUser/login",
                        "/sysUser/register",
                        "/file/**",
                        //swagger放行
                        "/swagger-ui/**",
                        "/swagger-ui.html",
                        "/swagger-resources/**",
                        "/images/**",
                        "/webjars/**",
                        "/v2/api-docs",
                        "/configuration/ui",
                        "/configuration/security",
                        "/doc.html",
                        "/alipay/**" //重点别忘了
                );

如果是微服务项目,需要在网关处添加相应白名单,允许不鉴权。

  • 按照上述配置之后,是可以成功进行沙箱支付。

  • 希望本文对你进一步了解沙箱支付的相关逻辑有更大的帮助。

  • 一入java深似海,争渡争渡!