开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情
1. 交易
发起交易
官方文档地址 文档地址
[接入流程]
- 前端发起支付
- 后端创建订单
- 后端访问支付宝发起交易接口-订单号
- 后端返回form表单到前端
- 前端自动提交表单,重定向到支付宝扫码支付页面
- 支付
- 扫码
- 账号密码
- 操作完成,等待重定向到后端设置好的url
[核心代码]
@Override
public String tradeCreate(Long productId) {
/**
* 订单服务 createOrderByProductId
* 获取商品信息
* 生成订单
* */
Order order = orderService.createOrderByProductId(productId);
/**
* 支付
* 创建请求对象
* 封装数据
* */
// 创建请求对象
AlipayTradePagePayRequest request=new AlipayTradePagePayRequest();
// 封装数据
AlipayTradePagePayModel bizModel=new AlipayTradePagePayModel();
bizModel.setOutTradeNo(order.getOrderNo());
bizModel.setTotalAmount(order.getTotalFee().toString()); //单位是 元
bizModel.setSubject(order.getTitle());
bizModel.setProductCode("FAST_INSTANT_TRADE_PAY"); // 默认的
request.setBizModel(bizModel);
request.setNotifyUrl(notifyUrl+"/api/ali-pay/trade/notify");
request.setReturnUrl(returnUrl); // 用户支付后支付宝会以GET方法请求returnUrl,并且携带out_trade_no,trade_no,total_amount等参数.
AlipayTradePagePayResponse response=null;
try{
//完成签名并执行请求
response=alipayClient.pageExecute(request);
if(response.isSuccess()){
log.debug("调用成功");
return response.getBody();
}
else{
log.error("调用失败");
log.error(response.getMsg(), response.getCode());
return null;
}
}catch(AlipayApiException e){
log.error("调用异常");
log.error(response.getMsg(), response.getCode());
return null;
}
}
交易通知
官方文档地址 文档地址
[接入流程]
- 后端编写post接口,并且路径和下单时传入的notifyUrl一致
- 用户支付完成,支付宝自动向该接口推送消息
- 后端根据下单传入的订单号查询订单
- 后端修改订单状态
[核心代码]
@PostMapping("/trade/notify")
public Object tradeNotify(@RequestParam Map<String,String> params){
log.debug("收到支付宝回调");
log.info("\n{}",params);
Object object = aliPayService.tradeNotify(params);
return object;
}
@Override
public Object tradeNotify(Map<String, String> data) {
//验签
boolean signVerified=false;
try{
signVerified= AlipaySignature.rsaCheckV1(data,aliPayPublicKey, AlipayConstants.CHARSET_UTF8,AlipayConstants.SIGN_TYPE_RSA2);
//验签成功
if(signVerified){
log.debug("验签成功");
//从数据库中查出对应的订单
// Order order = orderService.;
synchronized(this){
// 通知可能会重复,必须处理 可能 24h8次 (需要做幂等)
// 处理订单状态
// 处理支付记录
// 记录支付日志
log.info("订单{}的支付记录处理成功,支付记录id为.",data.get("out_trade_no"));
}
//除了success外其他返回均认为是失败
return "success";
}
//验签失败
else{
log.error("验签失败");
return "failure";
}
}
catch(AlipayApiException e){
log.error("验签异常");
return "failure";
}
}
查询交易
官方文档地址 文档地址
[接入流程]
- 根据系统的订单号或者支付宝的单号查询交易信息
[核心代码]
private Map<String,Object> queryPay(String orderNo){
//请求
AlipayTradeQueryRequest request=new AlipayTradeQueryRequest();
//数据
AlipayTradeQueryModel bizModel=new AlipayTradeQueryModel();
bizModel.setOutTradeNo(orderNo);
request.setBizModel(bizModel);
try{
//完成签名并执行请求
AlipayTradeQueryResponse response=alipayClient.execute(request);
if(response.isSuccess()){
log.debug("查询订单{}成功",orderNo);
HashMap<String,Object> resultMap= JSONObject.parseObject(response.getBody(),HashMap.class);
return resultMap;
}
else{
log.error("查询订单{}失败,响应数据是{}.",orderNo,response.getBody());
return null;
}
}
catch(AlipayApiException e){
log.error("查询订单{}异常",orderNo);
return null;
}
}
关闭交易
官方文档地址 文档地址
[接入流程]
- 根据系统的订单号或者支付宝的单号关闭交易信息
[核心代码]
@Override
public void closeOrder(String orderNo) {
// 远程关单
cancelPay(orderNo);
// 处理业务
// xxx
}
private boolean cancelPay(String orderNo){
//请求
AlipayTradeCloseRequest request=new AlipayTradeCloseRequest();
//数据
AlipayTradeCloseModel bizModel=new AlipayTradeCloseModel();
bizModel.setOutTradeNo(orderNo);
request.setBizModel(bizModel);
try{
//完成签名并执行请求
AlipayTradeCloseResponse response=alipayClient.execute(request);
if(response.isSuccess()){
log.debug("订单{}取消成功",orderNo);
}
else{
log.debug("订单{}未创建,因此也可认为本次取消成功.",orderNo);
}
return true;
}
catch(AlipayApiException e){
log.error("订单{}取消异常",orderNo);
return false;
}
}
2. 退款
发起退款
官方文档地址 文档地址
[接入流程]
-
全部退款
- 根据系统的订单号或者支付宝的单号发起退款
- 退款金额不能大于总金额
- 后端访问支付宝退款接口
- 支付宝同步返回退款信息
- 后端记录退款详情
-
部分退款
- 生成退款单No.
- 根据系统的订单号或者支付宝的单号发起退款,且必须填写退款单No.
- 退款金额不能大于总金额,可分多笔退款单多次退款
- 后端访问支付宝退款接口
- 支付宝同步返回退款信息
- 后端记录退款详情
[核心代码]
@Override
public Object refund(String orderNo) {
//请求
AlipayTradeRefundRequest request=new AlipayTradeRefundRequest();
//数据
AlipayTradeRefundModel bizModel=new AlipayTradeRefundModel();
//订单号
bizModel.setOutTradeNo(orderNo);
//退款单号 可选 如需部分退款,则此参数必传。
String outRequestNo = orderNo + "-refund-" + UUID.randomUUID().toString().substring(0, 10);
bizModel.setOutRequestNo(outRequestNo);
bizModel.setRefundAmount("1.0"); // 退款金额。需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数。
bizModel.setRefundReason("不喜欢了");
request.setBizModel(bizModel);
HashMap<String,Object> resultMap=new HashMap<>();
try{
//完成签名并执行请求
AlipayTradeRefundResponse response=alipayClient.execute(request);
//成功则说明退款成功了
resultMap.put("data",response.getBody());
if(response.isSuccess()){
resultMap.put("isRefundSuccess",true);
log.info("订单{} 退款单号{}退款成功",orderNo,outRequestNo);
}
else{
resultMap.put("isRefundSuccess",false);
log.error("订单{}退款失败",orderNo);
}
return resultMap;
}
catch(AlipayApiException e){
resultMap.put("isRefundSuccess",false);
log.error("订单{}退款异常",orderNo);
return resultMap;
}
}
查询退款
官方文档地址 文档地址
[接入流程]
-
全部退款
- 根据系统的订单号或者支付宝的单号查询交易信息
-
部分退款
- 根据系统的订单号或者支付宝的单号发起查询,且必须填写退款单No.
- 单笔退款详情只有一个,如需查询一个订单下的所有退款,需要轮询退款单No.
[核心代码]
@Override
public Map<String,Object> queryRefund(String orderNo, String outRequestNo){
AlipayTradeFastpayRefundQueryRequest request=new AlipayTradeFastpayRefundQueryRequest();
AlipayTradeFastpayRefundQueryModel bizModel=new AlipayTradeFastpayRefundQueryModel();
//订单号
bizModel.setOutTradeNo(orderNo);
//退款单号
bizModel.setOutRequestNo(outRequestNo);
//想要额外返回的数据(也就是文档中响应可选的数据)
ArrayList<String> extraResponseDatas=new ArrayList<>();
extraResponseDatas.add("refund_status");
bizModel.setQueryOptions(extraResponseDatas);
request.setBizModel(bizModel);
try{
//完成签名并执行请求
AlipayTradeFastpayRefundQueryResponse response=alipayClient.execute(request);
if(response.isSuccess()){
log.debug("退款{}查询成功",outRequestNo);
return JSONObject.parseObject(response.getBody(),HashMap.class);
}
else{
log.info("退款{}查询失败",outRequestNo);
return null;
}
}
catch(AlipayApiException e){
log.debug("退款{}查询异常",outRequestNo);
return null;
}
}
3. 账单
对账
官方文档地址 文档地址
[账单类型]
- trade
- 商户基于支付宝交易收单的业务账单(交易账单)
- signcustomer
- 基于商户支付宝余额收入及支出等资金变动的账务账单(账号财务账单)
[日期]
-
日账单
- yyyy-MM-dd : 只能查前一日(次日9点后查前日)
-
月账单
- yyyy-MM : 只能查上月(下月3日后查上月)
[接入流程]
- 根据类型和日期请求对账接口
- 从返回体拿到bill_download_url字段并下载(zip压缩的csv)
[核心代码]
@Override
public String queryBillDownloadUrl(String billType, String billDate) {
//请求
AlipayDataDataserviceBillDownloadurlQueryRequest request=new AlipayDataDataserviceBillDownloadurlQueryRequest();
//数据
AlipayDataDataserviceBillDownloadurlQueryModel bizModel=new AlipayDataDataserviceBillDownloadurlQueryModel();
bizModel.setBillType(billType);
bizModel.setBillDate(billDate);
request.setBizModel(bizModel);
try{
//完成签名并执行请求
AlipayDataDataserviceBillDownloadurlQueryResponse response=alipayClient.execute(request);
if(response.isSuccess()){
log.debug("获取账单下载url成功");
return response.getBillDownloadUrl();
}
else{
log.error("获取账单下载url失败");
return null;
}
}
catch(AlipayApiException e){
log.error("获取账单下载url异常");
return null;
}
}