alipay 当面付扫码支付实战开发
alipay 当面付扫码支付开发
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 项目VO
与DTO
导入
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分钟后结束调用
alipay 当面付扫码支付实战开发的更多相关文章
- Spring使用支付宝扫码支付
前一段一直在研究支付宝的扫码支付,不得不说,支付宝的文档写的真是一个烂(起码在下刚开始看的时候是mengbi的).文档上面的示例和demo里面的示例长的完全不一样.往往文档上面的例子很简单,而demo ...
- php实现支付宝在线支付和扫码支付demo
### php实现支付宝在线支付和扫码支付demo 背景:在做一个公众号时增加了h5端,需要接入支付,非微信环境,选择了支付宝,以下简单记录下实现过程,并做了简单的封装,拿来即可使用,注意:本项目只是 ...
- ASP.NET Core 2.0 支付宝当面付之扫码支付
前言 自从微软更换了CEO以后,微软的战略方向有了相当大的变化,不再是那么封闭,开源了许多东西,拥抱开源社区,.NET实现跨平台,收购xamarin并免费提供给开发者等等.我本人是很喜欢.net的,并 ...
- Python实现支付宝当面付之——扫码支付
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/7680348.html 一:配置信息准备 登录蚂蚁金服开放平台:https://open.alipay.com/ ...
- .NET Core2.0 环境下MVC模式的支付宝扫码支付接口-沙箱环境开发测试
所有配置以及相关信息均可以从PC支付中获取 使用的生成二维码的组件名为QRCoder,该组件引用了一个第三方实现的System.Drawing类库,和支付宝官网类似 当面付SDK为Alipay.Aop ...
- Java微信公众平台开发之扫码支付模式一
官方文档点击查看准备工作:已通过微信认证的公众号,必须通过ICP备案域名(否则会报支付失败)借鉴了很多大神的文章,在此先谢过了大体过程:先扫码(还没有确定实际要支付的金额),这个码是商品的二维码,再生 ...
- Java之微信支付(扫码支付模式二)案例实战
摘要:最近的一个项目中涉及到了支付业务,其中用到了微信支付和支付宝支付,在做的过程中也遇到些问题,所以现在总结梳理一下,分享给有需要的人,也为自己以后回顾留个思路. 一:微信支付接入准备工作: 首先, ...
- 微信支付之扫码支付开发:我遇到的坑及解决办法(附:Ecshop 微信支付插件)
前段时间帮一个朋友的基于ecshop开发的商城加入微信扫描支付功能,本以为是很简单的事儿——下载官方sdk或开发帮助文档,按着里面的做就ok了,谁知折腾了两三天的时间才算搞定,中间也带着疑问在网上找了 ...
- php微信支付(仅pc端扫码支付模式二)详细步骤.----仅适合第一次做微信开发的程序员
本人最近做了微信支付开发,是第一次接触.其中走了很多弯路,遇到的问题也很多.为了让和我一样的新人不再遇到类似的问题,我把我的开发步骤和问题写出来,以供参考. 开发时间是2016/8/10,所以微信支付 ...
随机推荐
- python练习册 每天一个小程序 第0002题
1 #-*-coding:utf-8-*- 2 __author__ = 'Deen' 3 ''' 4 题目描述: 5 将 0001 题生成的 200 个激活码(或者优惠券)保存到 MySQL 关系型 ...
- 绕过WAF进行常见Web漏洞利用
前言 本文以最新版安全狗为例,总结一下我个人掌握的一些绕过WAF进行常见WEB漏洞利用的方法. PS:本文仅用于技术研究与讨论,严禁用于任何非法用途,违者后果自负,作者与平台不承担任何责任 PPS:本 ...
- Rocket Mq 常用API 及简单运维
RocketMQ 常用API 消息 消息消费模式 消息消费模式由消费者来决定,可以由消费者设置MessageModel来决定消息模式. 消息模式默认为集群消费模式 consumer.setMessag ...
- 西门子S210驱动器接线
参考:SINAMICS S210 操作说明 1.系统概述 P28 节2.2 单相版驱动器的系统组件和附件 2.电源接线 P56 节3.2 单相 230 V 版驱动器的连接示例 单相版驱动器在 IT 电 ...
- Spring Boot 增加删除修改 批量
1.批量删除 a.自定义Repositoy中写 前台处理https://blog.csdn.net/yhflyl/article/details/81557670首先前台先要获取所有的要删除数据的I ...
- 什么是 Swagger?你用 Spring Boot 实现了它吗?
Swagger 广泛用于可视化 API,使用 Swagger UI 为前端开发人员提供在线沙箱.Swagger 是用于生成 RESTful Web 服务的可视化表示的工具,规范和完整框架实现.它使文档 ...
- 使用Spring框架的好处是什么?
轻量:Spring 是轻量的,基本的版本大约2MB. 控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们. 面向切面的编程(AOP):Spring支持 ...
- 为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动 的区别在哪里?
Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联 集合对象时,可以根据对象关系模型直接获取,所以它是全自动的.而 Mybatis 在查询关联对象或关联集 ...
- thrift使用和源码分析
1 前言 thrift的官方文档比较差,很多细节没有介绍清楚,比如require.optional和default字段的区别是什么,为什么字段前面要写序号等,带着这些疑问,我们需要阅读生成的源码来了解 ...
- 解释 MySQL 外连接、内连接与自连接的区别 ?
先说什么是交叉连接: 交叉连接又叫笛卡尔积,它是指不使用任何条件,直接将一 个表的所有记录和另一个表中的所有记录一一匹配. 内连接 则是只有条件的交叉连接,根据某个条件筛选出符合条件的记录,不符合 条 ...