目录:
(1)支付功能实现
(2)保存支付信息
(3)编写支付宝支付接口
(1)支付功能实现
支付宝有了同步通知为什么还需要异步通知?
同步回调两个作用
第一是从支付宝的页面上返回自己的网站继续后续操作;
第二是携带支付状态的get参数;让自己的网站用于验证;同步通知后;还需要异步通知主要是为了防止出现意外情况;
因为涉及到金钱;这是一个对安全和稳定要求比较严格的场景;
如果同步通知的过程中;用户不小心关闭了浏览器;或者浏览器卡死了;
异步也能收到通知;记录支付状态;即便是用户端没问题;万一自己的服务器网络异常了一下呢?
如果自己的服务器没有正确返回接受到通知的状态;
支付宝的服务器会在一段时间内持续的往自己的服务器发送异步通知;
一直到成功;顺便去确认了下;这个一段时间是:
25 小时以内完成 8 次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h)
思路分析
- 将支付数据保存到数据库,以便跟支付宝进行对账
- 生成要支付的二维码
生成二维码需要的参数列表请参考官方文档
https://opendocs.alipay.com/open/270/105899
保存支付信息的表结构
表结构 payment_info
id | 主键自动生成 |
out_trade_no | 订单中已生成的对外交易编号。订单中获取 |
order_id | 订单编号 |
payment_type | 支付类型(微信与支付宝) |
| 交易号,回调时生成 |
total_amount | 订单金额。订单中获取 |
subject | 交易内容。利用商品名称拼接。 |
payment_status | 支付状态,默认值未支付。 |
create_time | 创建时间,当前时间。 |
callback_time | 回调时间,初始为空,支付宝异步回调时记录 |
callback_content | 回调信息,初始为空,支付宝异步回调时记录 |
(2)保存支付信息
接口 PaymentService
package com.atguigu.gmall.payment.service;
import com.atguigu.gmall.model.order.OrderInfo;
public interface PaymentService {
/**
* 保存交易记录
* @param orderInfo
* @param paymentType 支付类型(1:微信 2:支付宝)
*/
void savePaymentInfo(OrderInfo orderInfo, String paymentType);
}
定义PaymentMapper接口
package com.atguigu.gmall.payment.mapper;
@Mapper
public interface PaymentInfoMapper extends BaseMapper<PaymentInfo> {
}
实现类PaymentServiceImpl
package com.atguigu.gmall.payment.service.impl;
@Service
public class PaymentServiceImpl implements PaymentService {
@Autowired
private PaymentInfoMapper paymentInfoMapper;
@Override
public void savePaymentInfo(OrderInfo orderInfo, String paymentType) {
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("order_id", orderInfo.getId());
queryWrapper.eq("payment_type", paymentType);
Integer count = paymentInfoMapper.selectCount(queryWrapper);
if(count > 0) return;
// 保存交易记录
PaymentInfo paymentInfo = new PaymentInfo();
paymentInfo.setCreateTime(new Date());
paymentInfo.setOrderId(orderInfo.getId());
paymentInfo.setPaymentType(paymentType);
paymentInfo.setOutTradeNo(orderInfo.getOutTradeNo());
paymentInfo.setPaymentStatus(PaymentStatus.UNPAID.name());
paymentInfo.setSubject(orderInfo.getTradeBody());
//paymentInfo.setSubject("test");
paymentInfo.setTotalAmount(orderInfo.getTotalAmount());
paymentInfoMapper.insert(paymentInfo);
}
}
(3)编写支付宝支付接口
制作AlipayClient工具类
创建配置类
package com.atguigu.gmall.payment.config;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AlipayConfig {
//支付宝网关
@Value("${alipay_url}")
private String alipay_url;
//应用id
public static String app_id;
@Value("${app_id}")
public void setApp_id(String app_id){
AlipayConfig.app_id=app_id;
}
//应用私钥
@Value("${app_private_key}")
private String app_private_key;
//数据格式
public final static String format="json";
//字符编码集
public final static String charset="UTF-8";
//支付宝公钥
public static String alipay_public_key;
@Value("${alipay_public_key}")
public void setAlipay_public_key(String alipay_public_key){
AlipayConfig.alipay_public_key =alipay_public_key;
}
//签名算法
public final static String sign_type ="RSA2";
public static String return_payment_url;
@Value("${return_payment_url}")
public void setReturn_payment_url(String return_payment_url){
AlipayConfig.return_payment_url =return_payment_url;
}
public static String return_order_url;
@Value("${return_order_url}")
public void setReturn_order_url(String return_order_url){
AlipayConfig.return_order_url =return_order_url;
}
public static String notify_payment_url;
@Value("${notify_payment_url}")
public void setNotify_payment_url(String notify_payment_url){
AlipayConfig.notify_payment_url =notify_payment_url;
}
@Bean
public AlipayClient alipayClient(){
AlipayClient alipayClient = new DefaultAlipayClient(alipay_url,app_id,app_private_key,format,charset,alipay_public_key,sign_type);
return alipayClient;
}
}
编写支付宝下单
package com.atguigu.gmall.payment.service;
public interface AlipayService {
String createaliPay(Long orderId);
}
注入配置类中的AlipayClient:
实现类
package com.atguigu.gmall.payment.service.impl;
@Service
public class AlipayServiceImpl implements AlipayService {
@Autowired
private AlipayClient alipayClient;
@Autowired
private OrderFeignClient orderFeignClient;
@Autowired
private PaymentService paymentService;
@Override
public String createaliPay(Long orderId) {
// 根据订单Id 获取orderInfo
OrderInfo orderInfo = orderFeignClient.getOrderInfo(orderId);
if ("PAID".equals(orderInfo.getOrderStatus()) || "CLOSED".equals(orderInfo.getOrderStatus())){
return "该订单已经完成或已经关闭!";
}
// 调用保存交易记录方法!
paymentService.savePaymentInfo(orderInfo, PaymentType.ALIPAY.name());
//对接支付宝
String form = "";
// 创建 AlipayClient 对象! AlipayClient 这个对象注入到 spring 容器中!
// AlipayClient alipayClient = new DefaultAlipayClient( "https://openapi.alipay.com/gateway.do" , APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE); //获得初始化的AlipayClient
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); //创建API对应的request
// 同步回调地址 http://api.gmall.com/api/payment/alipay/callback/return
alipayRequest.setReturnUrl(AlipayConfig.return_payment_url);
// 异步回调地址
alipayRequest.setNotifyUrl( "http://domain.com/CallBack/notify_url.jsp" ); //在公共参数中设置回跳和通知地址
// 封装业务参数
HashMap<String, Object> map = new HashMap<>();
// 第三方业务编号! 订单号
map.put("out_trade_no",orderInfo.getOutTradeNo());
//销售产品码 类似商店物品后面的条形码,扫描会出现价格、销售等信息,计量商品是否合法,监控销量等
map.put("product_code","FAST_INSTANT_TRADE_PAY");
//金额
map.put("total_amount","0.01");
//订单标题
map.put("subject",orderInfo.getTradeBody());
// 设置二维码过期时间
map.put("timeout_express","10m");
alipayRequest.setBizContent(JSON.toJSONString(map));
try {
form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
} catch (AlipayApiException e) {
e.printStackTrace();
}
return form;
}
}
控制器:AlipayController
@Controller
@RequestMapping("/api/payment/alipay")
public class AlipayController {
@Autowired
private AlipayService alipayService;
@RequestMapping("submit/{orderId}")
@ResponseBody
public String submitOrder(@PathVariable Long orderId){
String from = alipayService.createaliPay(orderId);
return from;
}
}
前端页面
<ul class="payType">
<a th:href="@{http://api.gmall.com/api/payment/alipay/submit/{orderId}(orderId=${orderInfo.id})}" target="_blank"><li><img src="./img/_/pay2.jpg"></li></a>
</ul>
tadde_no为空因为还没有做回调处理