SpringBoot接入支付沙箱返回支付二维码
支付宝开放平台
扫码登录支付宝开放平台
沙箱环境
沙箱环境介绍
沙箱控制台
应用网关:该地址用于接收开放平台的异步通知。目前沙箱环境不需要配置此参数;
授权回调地址;第三方应用授权或获取用户信息中用于接收授权回调信息的地址。使用相关产品时需进行配置:
第三方应用授权:授权 url 中的 redirect_uri 必须与此值相同。
获取用户信息:授权 url 中的 redirect_uri 的域名必须与此值相同(例如:授权回调地址配置:https://auth.example.com/authCallBack 高亮部分需和授权url相同)。
RSA(SHA1)密钥:配置 RSA2(SHA256) 的应用公钥后,不需要配置 RSA(SHA1) 密钥。
AES 密钥:目前不再使用。
扫码测试的时候需要沙箱版支付宝App,目前只有安卓版
下载
配置
首先导入支付宝的依赖
<!--ali pay-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.1.0</version>
</dependency>
配置文件
alipay:
app-id: # AppID
private-key: # 应用私匙 需要用支付宝助手生成
public-key: # 支付宝公匙
gateway: https://openapi.alipaydev.com/gateway.do
支付宝公匙点击RSA2(SHA256)密钥设置,然后查看
应用私匙:
会生成txt文件,然后复制到配置文件中
APPID和网关就不说了,需要注意的是正式接入支付宝的网关和沙箱环境的应用网关,区分是alipay.com/alipaydev.com
代码实现
构建支付信息视图对象PayInfoVO.java
@Data
@AllArgsConstructor
@ToString
@EqualsAndHashCode
@NoArgsConstructor
@ApiModel("支付信息")
public class PayInfoVO implements Serializable {
@ApiModelProperty("二维码URL")
private String url;
@ApiModelProperty("订单编号")
private String orderId;
@ApiModelProperty("商家名称")
private String shopName;
}
PayServiceImpl
@Service("PayServiceImpl")
@Slf4j
public class PayServiceImpl implements PayService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private ShopMapper shopMapper;
@Value("${alipay.app-id}")
private String appId;
@Value("${alipay.private-key}")
private String privateKey;
@Value("${alipay.public-key}")
private String publicKey;
@Value("${alipay.gateway}")
private String gateway;
private AlipayClient alipayClient;
@PostConstruct
public void init() {
alipayClient = new DefaultAlipayClient(gateway,
appId, privateKey, "json", "utf-8", publicKey, "RSA2");
}
@Override
public PayInfoVO getPayInfo(String orderId) {
log.info("info ============= {}",orderId);
// 根据订单id得到订单详情
Order order = orderMapper.selectById(orderId);
String sellId = order.getSellId();
// 根据商家ID获取商家信息
Shop shop = shopMapper.selectById(sellId);
String shopSellName = shop.getSellName();
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
// 支付请求
request.setBizContent("{" +
" \"out_trade_no\":\"" + orderId + "\"," +//商户订单号
" \"total_amount\":\"" + order.getOrderPrice().setScale(2, RoundingMode.CEILING) + "\"," +
" \"subject\":\"" + shopSellName + "当面付" + "\"," +
" \"store_id\":\"00100\"," + // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持
" \"timeout_express\":\"5m\"}");//订单允许的最晚付款时间
AlipayTradePrecreateResponse response = null;
//支付宝二维码URL
String qrCode = "";
try {
response = alipayClient.execute(request);
if (!response.isSuccess()) {
throw new CustomException("生成支付宝订单失败:" + response.getMsg());
}
qrCode = response.getQrCode();
} catch (AlipayApiException e) {
throw new CustomException(e.getMessage());
}
// 封装支付信息 返回
PayInfoVO payInfoVO = new PayInfoVO();
payInfoVO.setOrderId(order.getOrderId());
payInfoVO.setShopName(shopSellName);
payInfoVO.setUrl(qrCode);
log.info("payInfo: {}",payInfoVO);
return payInfoVO;
}
}
controller
@Autowired
@Qualifier("PayServiceImpl")
private PayService payService;
@ApiOperation("返回支付二维码和支付信息")
@GetMapping("/qr/{orderId}")
public AjaxResult getPayInfo(@PathVariable String orderId) {
PayInfoVO payInfoVO = payService.getPayInfo(orderId);
return AjaxResult.success("支付成功", payInfoVO);
}
支付状态
@AllArgsConstructor
@Getter
public enum PayStatusEnum {
/** 等待扫码 */
WAIT_SCANNED(0,"等待扫码"),
/** 等待支付(已扫码,未支付) */
UN_PROCESSED(1,"等待支付"),
/** 商家已完成,等待骑手取餐 */
PROCESSED(2,"已支付"),
/** 订餐者关闭或者超时关闭 */
SHIPPING(3,"已取消"),
;
private Integer code;
private String msg;
public static PayStatusEnum valueOf(Integer code){
for (PayStatusEnum value : values()) {
if (value.code.equals(code)) {
return value;
}
}
return null;
}
}
支付结果对象
@Data
@ToString
public class PayResultDTO implements Serializable {
//支付ID
private Long payId;
// 支付状态
private Integer status;
// 支付金额
private BigDecimal amount;
// 支付信息
private String msg;
}
获取支付状态
// 根据orderId获取支付状态
public PayResultDTO getPayStatus(String orderId) {
log.info("status: ========= {}",orderId);
//创建API对应的request类
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("{" +
" \"out_trade_no\":\"" + orderId + "\"}");
AlipayTradeQueryResponse response = null;
Order order = new Order();
order.setOrderId(orderId);
PayResultDTO payResultDTO = new PayResultDTO();
try {
response = alipayClient.execute(request);
if (!response.isSuccess()) {
// 获取支付信息失败
payResultDTO.setStatus(PayStatusEnum.WAIT_SCANNED.getCode());
payResultDTO.setMsg("等待扫码");
return payResultDTO;
}
payResultDTO.setThirdPartId(response.getTradeNo());
switch (response.getTradeStatus()) {
case "WAIT_BUYER_PAY":
payResultDTO.setStatus(PayStatusEnum.UN_PROCESSED.getCode());
payResultDTO.setMsg("已扫码,等待用户支付");
break;
case "TRADE_CLOSED":
payResultDTO.setStatus(PayStatusEnum.SHIPPING.getCode());
payResultDTO.setMsg("支付已关闭");
break;
case "TRADE_SUCCESS":
payResultDTO.setStatus(PayStatusEnum.PROCESSED.getCode());
payResultDTO.setAmount(new BigDecimal(response.getTotalAmount()));
payResultDTO.setMsg("支付成功");
order.setPayStatus(Constants.PAY_STATUS_PAID);
// 这里写支付成功的逻辑,例如设置支付时间,订单状态什么的
break;
default:
break;
}
return payResultDTO;
} catch (AlipayApiException e) {
payResultDTO.setStatus(-1);
payResultDTO.setMsg("查询订单状态错误:" + e.getErrMsg());
return payResultDTO;
}
}
controller
获取支付状态
@ApiOperation("获取支付状态")
@GetMapping("/status/{orderId}")
public AjaxResult getPayStatus(@PathVariable String orderId){
PayResultDTO payStatus = payService.getPayStatus(orderId);
return AjaxResult.success("支付状态对象",payStatus);
}
最终测试
使用沙箱版App登录账户扫码支付
希望对大家有所帮助!