Loading

alipay 当面付扫码支付实战开发

参考官网地址:https://opendocs.alipay.com/open/194/105072

1、当面付介绍:

当面付包括付款码支付和扫码支付两种收款方式。适用于线下实体店支付、面对面支付、自助售货机等场景。

  • 付款码支付:商家使用扫码枪或其他扫码机具扫描用户出示的付款码,来实现收款。
  • 扫码支付:商家提供收款二维码,由用户通过支付宝扫码支付,来实现收款。

2、参数准备

• APPID
• 商家私钥
• 支付宝公钥
• 支付回调地址
• 网关地址
• 加密签名算法RSA2

3、JAVA 代码实战,项目基础功能准备

3.1 创建 springBoot 工程

3.2 导入依赖

<dependencies>
        <!--web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--测试依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>

        <!--实体依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- alipay sdk 支付依赖 -->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.22.57.ALL</version>
        </dependency>

        <!-- hutool 流行工具 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.22</version>
        </dependency>

        <!-- 谷歌二维码生成工具 -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.4.1</version>
        </dependency>

    </dependencies>

3.3 配置yml

# 支付宝支付参数配置
alipay:
  app_id: 公司支付宝的APPID
  merchant_private_key: 公司支付宝商户私钥
  alipay_public_key: 公司支付宝公钥
  notify_url: alipay 异步回调地址
  return_url: alipay 同步回调地址(我们做二维码扫码是异步操作,没用,可以不配置)
  sign_type: RSA2
  charset: utf-8
  gatewayUrl: https://openapi.alipay.com/gateway.do

3.4 定义配置类

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author: yijun.wen
 * @date: 2022/3/11 5:32 下午
 * @description: alipay 配置类
 */
@Data
@Component
public class AlipayConfig {

    /**
     * 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
     */

    @Value("${alipay.app_id}")
    public String app_id;

    /**
     * 商户私钥,您的PKCS8格式RSA2私钥
     */

    @Value("${alipay.merchant_private_key}")
    public String merchant_private_key;

    /**
     * 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
     */

    @Value("${alipay.alipay_public_key}")
    public String alipay_public_key;

    /**
     * 服务器异步通知页面路径  需http://格式的完整路径,不能加参数,必须外网可以正常访问
     */
    @Value("${alipay.notify_url}")
    public String notify_url;

    /**
     * 页面跳转同步通知页面路径 需http://格式的完整路径,不能加参数,必须外网可以正常访问(我们这里没用这个)
     */

    @Value("${alipay.return_url}")
    public String return_url;

    /**
     * 签名方式
     */

    @Value("${alipay.sign_type}")
    public String sign_type;

    /**
     * 字符编码格式
     */

    @Value("${alipay.charset}")
    public String charset;

    /**
     * 支付宝网关
     */
    @Value("${alipay.gatewayUrl}")
    public String gatewayUrl;

}

3.5 二维码生成工具类

package com.wyj.alipay.util;

import cn.hutool.extra.qrcode.BufferedImageLuminanceSource;
import com.google.zxing.*;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.OutputStream;
import java.util.Hashtable;

/**
 * @author: yijun.wen
 * @date: 2022/3/11 5:36 下午
 * @description:
 */
public class QrCodeUtil {

    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";
    // 二维码尺寸
    private static final int QRCODE_SIZE = 300;
    // LOGO宽度
    private static final int WIDTH = 90;
    // LOGO高度
    private static final int HEIGHT = 90;

    private static BufferedImage createImage(String content, String imgPath, boolean needCompress) throws Exception {
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
                hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        if (imgPath == null || "".equals(imgPath)) {
            return image;
        }
        // 插入图片
        insertImage(image, imgPath, needCompress);
        return image;
    }

    private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {
        File file = new File(imgPath);
        if (!file.exists()) {
            System.err.println("" + imgPath + "   该文件不存在!");
            return;
        }
        Image src = ImageIO.read(new File(imgPath));
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        if (needCompress) { // 压缩LOGO
            if (width > WIDTH) {
                width = WIDTH;
            }
            if (height > HEIGHT) {
                height = HEIGHT;
            }
            Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            // 绘制缩小后的图
            g.drawImage(image, 0, 0, null);
            g.dispose();
            src = image;
        }
        // 插入LOGO
        Graphics2D graph = source.createGraphics();
        int x = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - height) / 2;
        graph.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }

    public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception {
        BufferedImage image = createImage(content, imgPath, needCompress);
        mkdirs(destPath);
        ImageIO.write(image, FORMAT_NAME, new File(destPath));
    }

    public static BufferedImage encode(String content, String imgPath, boolean needCompress) throws Exception {
        BufferedImage image = createImage(content, imgPath, needCompress);
        return image;
    }

    public static void mkdirs(String destPath) {
        File file = new File(destPath);
        // 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    public static void encode(String content, String imgPath, String destPath) throws Exception {
        encode(content, imgPath, destPath, false);
    }


    public static void encode(String content, String destPath) throws Exception {
        encode(content, null, destPath, false);
    }

    public static void encode(String content, String imgPath, OutputStream output, boolean needCompress)
            throws Exception {
        BufferedImage image = createImage(content, imgPath, needCompress);
        ImageIO.write(image, FORMAT_NAME, output);
    }

    public static void encode(String content, OutputStream output) throws Exception {
        encode(content, null, output, false);
    }

    public static String decode(File file) throws Exception {
        BufferedImage image;
        image = ImageIO.read(file);
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result;
        Hashtable hints = new Hashtable();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }

    public static String decode(String path) throws Exception {
        return decode(new File(path));
    }
}
package com.wyj.alipay.util;

import lombok.Data;

/**
 * @author: yijun.wen
 * @date: 2022/3/11 5:39 下午
 * @description:
 */
@Data
public class QrCodeResponse {
    /**
     * 返回的状态码
     */
    private String code;

    /**
     * 返回的信息
     */
    private String msg;

    /**
     * 交易的流水号
     */
    private String out_trade_no;

    /**
     * 生成二维码的内容
     */
    private String qr_code;
}
package com.wyj.alipay.util;

import lombok.Data;

/**
 * @author: yijun.wen
 * @date: 2022/3/11 5:38 下午
 * @description:
 */
@Data
public class QrResponse {

    private QrCodeResponse alipay_trade_precreate_response;

    private String sign;

    public QrCodeResponse getAlipay_trade_precreate_response() {
        return alipay_trade_precreate_response;
    }

    public void setAlipay_trade_precreate_response(QrCodeResponse alipay_trade_precreate_response) {
        this.alipay_trade_precreate_response = alipay_trade_precreate_response;
    }
}

3.6 订单号生成工具类

类似雪花只试用单体项目

package com.wyj.alipay.util;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author: yijun.wen
 * @date: 2022/3/14 10:23 上午
 * @description:
 */
public class GenerateNum {
    /**
     * 全局自增数
     */
    private static int count = 0;

    /**
     * 每毫秒秒最多生成多少订单(最好是像9999这种准备进位的值)
     */
    private static final int total = 99;

    /**
     * 格式化的时间字符串
     */
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");

    /**
     * 获取当前时间年月日时分秒毫秒字符串
     *
     * @return
     */
    private static String getNowDateStr() {
        return sdf.format(new Date());
    }

    /**
     * 记录上一次的时间,用来判断是否需要递增全局数
     */

    private static String now = null;

    /**
     * 生成一个订单号
     */
    public static String generateOrder() {
        String dataStr = getNowDateStr();
        if (dataStr.equals(now)) {
            count++;
        } else {
            count = 1;
            now = dataStr;
        }
        // 算补位
        int countInteger = String.valueOf(total).length() - String.valueOf(count).length();
        //补字符串
        String bu = "";
        for (int i = 0; i < countInteger; i++) {
            bu += "0";
        }

        bu += String.valueOf(count);
        if (count >= total) {
            count = 0;
        }
        return dataStr + bu;
    }
}

3.7 项目VODTO导入

package com.wyj.alipay.model;

import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;

/**
 * @author: yijun.wen
 * @date: 2022/3/11 5:52 下午
 * @description:
 */
@Data
@NoArgsConstructor
public class ViewData<V> implements Serializable {

    protected int code;
    protected V data;
    protected Object error;

}

package com.wyj.alipay.model;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: yijun.wen
 * @date: 2022/3/11 5:50 下午
 * @description:
 */
@Data
public class PayDto implements Serializable {

    private Long userId;

    private String totalAmount;

    private int payType;
}

package com.wyj.alipay.model;

import lombok.Data;

import java.io.Serializable;

/**
 * @author: yijun.wen
 * @date: 2022/3/11 5:52 下午
 * @description:
 */
@Data
public class PayCallbackDto implements Serializable {

    private Long userId;

    private String payNumber;
}

package com.wyj.alipay.model;

import lombok.Data;

/**
 * @author: yijun.wen
 * @date: 2022/3/14 10:21 上午
 * @description:
 */
@Data
public class QrCodeVo {
    private Long UserId;

    private String payNumber;

    private String qrCode;
}

上述为准备工作,接下来开始核心代码

4、 创建alipay业务接口及实现类

4.1 整体业务接口

package com.wyj.alipay.service;

import com.alipay.api.AlipayApiException;
import com.wyj.alipay.model.PayCallbackDto;
import com.wyj.alipay.model.PayDto;
import com.wyj.alipay.model.ViewData;

import javax.servlet.http.HttpServletRequest;

/**
 * @author: yijun.wen
 * @date: 2022/3/11 5:44 下午
 * @description:
 */
public interface AlipayService {
    /**
     * 生成支付二维码
     *
     * @param payInfo
     * @return
     */
    ViewData alipay(PayDto payInfo);

    /**
     * 支付宝回调接口
     *
     * @param request
     * @return
     */
    boolean alipayCallback(HttpServletRequest request);

    /**
     * alipay 监听支付状态的接口
     *
     * @param payCallbackInfo
     * @return
     * @throws AlipayApiException
     */
    ViewData alipayCallback(PayCallbackDto payCallbackInfo) throws AlipayApiException;

}

4.2 二维码返回接口实现

package com.wyj.alipay.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
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.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.wyj.alipay.config.AlipayConfig;
import com.wyj.alipay.model.PayCallbackDto;
import com.wyj.alipay.model.PayDto;
import com.wyj.alipay.model.QrCodeVo;
import com.wyj.alipay.model.ViewData;
import com.wyj.alipay.service.IAlipayService;
import com.wyj.alipay.util.GenerateNum;
import com.wyj.alipay.util.QrCodeResponse;
import com.wyj.alipay.util.QrCodeUtil;
import com.wyj.alipay.util.QrResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.FileCopyUtils;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Base64;

/**
 * @author: yijun.wen
 * @date: 2022/3/14 10:19 上午
 * @description:
 */
@Service
@Slf4j
public class AlipayServiceImpl implements IAlipayService {

    @Autowired
    private AlipayConfig alipayConfig;

    @Override
    public ViewData alipay(PayDto payInfo) {
        ViewData<QrCodeVo> viewData = new ViewData<>();
        // 1:支付的用户
        Long userId = payInfo.getUserId();
        // 2: 支付金额
        String totalAmount = payInfo.getTotalAmount();
        // 3: 支付的产品名称
        String productName = "Alipay test";
        // 4: 支付的订单编号
        String payNumber = GenerateNum.generateOrder();
        // 5: 支付方式
        int payType = payInfo.getPayType();
        // 6:支付宝携带的参数在回调中可以通过request获取 参数
        JSONObject json = JSONUtil.createObj();
        json.set("memberId", userId);
        json.set("totalAmount", totalAmount);
        json.set("productName", productName);
        json.set("payNumber", payNumber);
        json.set("payType", payType);
        // 7:设置支付相关的信息
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        // 自定义订单号
        model.setOutTradeNo(payNumber);
        // 支付金额
        model.setTotalAmount(totalAmount);
        // 支付的产品名称
        model.setSubject(productName);
        // 支付的请求体参数
        model.setBody(json.toString());
        // 支付的超时时间
        model.setTimeoutExpress("5m");
        // 支付的库存 id(根据 cloudPKI 业务,这里我们用用户id )
        model.setStoreId(userId + "");
        // 调用 alipay 获取二维码参数
        QrCodeResponse qrCodeResponse = qrcodePay(model);

        try {
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            // 自定义二维码logo todo: 可以在二维码中间可以加上公司 logo
            //String logoPath = ResourceUtils.getFile("classpath:favicon.png").getAbsolutePath();
            String logoPath = "";
            // 生成二维码
            BufferedImage buffImg = QrCodeUtil.encode(qrCodeResponse.getQr_code(), logoPath, false);
            ImageOutputStream imageOut = ImageIO.createImageOutputStream(output);
            ImageIO.write(buffImg, "JPEG", imageOut);
            imageOut.close();
            ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
            byte[] data = FileCopyUtils.copyToByteArray(input);
            QrCodeVo qrCodeVo = new QrCodeVo();
            qrCodeVo.setQrCode(Base64.getEncoder().encodeToString(data));
            qrCodeVo.setPayNumber(payNumber);
            qrCodeVo.setUserId(userId);
            viewData.setData(qrCodeVo);
            return viewData;
        } catch (Exception ex) {
            ex.printStackTrace();
            return viewData;
        }
    }

    @Override
    public boolean alipayCallback(HttpServletRequest request) {
        return false;
    }

    @Override
    public ViewData alipayCallback(PayCallbackDto payCallbackInfo) throws AlipayApiException {
        return null;
    }

    /**
     * 扫码运行代码
     * 验签通过返回QrResponse
     * 失败打印日志信息
     * 参考地址:https://opendocs.alipay.com/apis/api_1/alipay.trade.app.pay
     *
     * @param model
     * @return
     */
    public QrCodeResponse qrcodePay(AlipayTradePrecreateModel model) {
        // 1: 获取阿里请求客户端
        AlipayClient alipayClient = getAlipayClient();
        // 2: 获取阿里请求对象
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        // 3:设置请求参数的集合,最大长度不限
        request.setBizModel(model);
        // 设置异步回调地址
        request.setNotifyUrl(alipayConfig.getNotify_url());
        // 设置同步回调地址
        request.setReturnUrl(alipayConfig.getReturn_url());
        AlipayTradePrecreateResponse alipayTradePrecreateResponse = null;
        try {
            alipayTradePrecreateResponse = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        QrResponse qrResponse = JSON.parseObject(alipayTradePrecreateResponse.getBody(), QrResponse.class);
        return qrResponse.getAlipay_trade_precreate_response();
    }

    /**
     * 获取AlipayClient对象
     *
     * @return
     */
    private AlipayClient getAlipayClient() {
        //获得初始化的AlipayClient
        AlipayClient alipayClient =
                new DefaultAlipayClient(alipayConfig.getGatewayUrl(), alipayConfig.getApp_id(), alipayConfig.getMerchant_private_key(),
                        "JSON", alipayConfig.getCharset(), alipayConfig.getAlipay_public_key(), alipayConfig.getSign_type());
        return alipayClient;
    }
}

4.3 创建 web 接口

package com.wyj.alipay.controller;

import com.wyj.alipay.model.PayDto;
import com.wyj.alipay.model.ViewData;
import com.wyj.alipay.service.IAlipayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author: yijun.wen
 * @date: 2022/3/14 10:57 上午
 * @description:
 */
@RestController
@RequestMapping("/api/pay/alipay/")
public class AlipayController {
    @Autowired
    private IAlipayService alipayService;

    /**
     * 生成支付宝支付二维码
     *
     * @param payInfo
     * @return
     */
    @PostMapping("/qr_code")
    public ViewData alipay(@RequestBody PayDto payInfo) {
        return alipayService.alipay(payInfo);
    }

}

4.4 使用 Postman 进行接口测试

qr_Code响应值为 Base64 编码

我们可以简单写个 html 页面来测试

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>My alipay qr_code</title>  
</head>
<body> 
<img src="data:image/jpeg;base64,《这里写 qr_Code 编码》">
</body>
</html>

4.5 测试效果

5、扫码后回调接口开发

5.1 支付回调接口实现

重写 AlipayServiceImpl alipayCallback方法

    /**
     * 支付宝回调
     *
     * @return
     * @throws Exception
     */
    @Override
    public boolean alipayCallback(HttpServletRequest request) {
        // 获取支付宝GET过来反馈信息
        Map<String, String> params = new LinkedHashMap<>();
        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] + ",";
            }
            try {
                params.put(name, new String(valueStr.getBytes("ISO-8859-1"), "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        // 计算得出通知验证结果
        log.info("1:获取支付宝回传的参数" + params);
        try {
            // 验签
            //RSA2密钥验签
            boolean checkV1 = AlipaySignature.rsaCheckV1(params, alipayConfig.alipay_public_key, alipayConfig.charset, alipayConfig.sign_type);
            log.info("验签成功");
            if (!checkV1) {
                log.info("验签失败接口参数:{}", params);
                return false;
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        // 返回公共参数
        String extparamString = request.getParameter("extra_common_param");
        log.info("2:支付宝交易返回的公共参数:{}", extparamString);
        String tradeNo = params.get("trade_no");
        //交易完成
        String body = params.get("body");
        log.info("3:【支付宝】交易的参数信息是:{},流水号是:{}", body, tradeNo);
        try {
            JSONObject bodyJson = new JSONObject(body);
            Long userId = bodyJson.getLong("userId");
            String payType = bodyJson.getStr("payType");
            String payNumber = bodyJson.getStr("payNumber");
            log.info("4:【支付宝】交易的参数信息是:payType:{},payNumber:{},userId:{}", payType, payNumber, userId);
            // todo 入库充值记录 修改库存等一系列 DB 操作
        } catch (Exception ex) {
            log.error("支付宝支付出现了异常,流水号是:{}", tradeNo);
            ex.printStackTrace();
            return false;
        }
        return true;
    }

5.2 创建 web 接口

下面代码拷贝到 AlipayController

检查 alipay 回调地址是否为当前接口地址

    /**
     * alipay 异步通知
     * 参考地址:https://opendocs.alipay.com/support/01ravg
     */
    @ResponseBody
    @PostMapping("/notifyUrl")
    public String notify_url(HttpServletRequest request) {
        boolean result = alipayService.alipayCallback(request);
        if (result) {
            // alipay 规范,请不要修改或删除
            return "success";
        } else {
            // 验证失败
            return "fail";
        }
    }

5.3 查看测试效果

注意:回调接口为 alipay 调用,必须外网能够访问

我这里打包部署到服务器上,给大家看下日志效果

重新按照步骤4生成二维码,支付宝扫码支付成功后,可见日志:

6、Alipay 支付状态查询

这个接口主要是给前端轮询调用获取支付状态使用

当然,还有一种解决方案,使用websocket,在步骤5中直接发送消息通知前端

6.1 监听支付状态的接口实现

重写 AlipayServiceImpl alipayCallback 方法

    @Override
    public ViewData alipayCallback(PayCallbackDto payCallbackInfo) throws AlipayApiException {
        ViewData<Object> viewData = new ViewData<>();
        // 1: 获取阿里请求客户端
        AlipayClient alipayClient = getAlipayClient();
        // 2: 获取阿里请求对象
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        // 3: 设置业务参数
        request.setBizContent(JSONUtil.toJsonStr(JSONUtil.createObj().set("out_trade_no", payCallbackInfo.getPayNumber())));
        //通过alipayClient调用API,获得对应的response类
        AlipayTradeQueryResponse response = alipayClient.execute(request);
        String body = response.getBody();
        JSONObject json = new JSONObject(new JSONObject(body).getStr("alipay_trade_query_response"));
        if ("10000".equals(json.getStr("code")) && "TRADE_SUCCESS".equals(json.getStr("trade_status"))) {
            viewData.setData("success");
        } else {
            viewData.setData("fail");
        }
        return viewData;
    }

6.2 创建 web 接口

    /**
     * alipay 监听支付状态的接口
     *
     * @param PayCallbackInfo
     * @return
     */
    @PostMapping("/alipaycallback")
    public ViewData alipayCallback(@RequestBody PayCallbackDto PayCallbackInfo) throws AlipayApiException {
        return alipayService.alipayCallback(PayCallbackInfo);
    }

6.3 测试

这里前端轮询逻辑,展示二维码 5 秒后,每3秒调用一次支付查询接口,得到响应success或5分钟后结束调用

posted @ 2022-03-22 19:14  Eajur  阅读(444)  评论(0)    收藏  举报