之前在项目中使用过支付宝的沙箱测试支付和实际开发支付,是关于App对接支付宝接口的,由于前段时间有朋友询问怎么对接网页支付,通过研究支付包的开发文档,在这里总结一下对接支付宝的App支付接口和网页支付接口的具体细节。
前期准备
要先注册一个支付宝企业账号,获取appid,在支付宝平台获取支付宝公钥和自己的公钥与私钥,这些准备工作就不再这里具体操作
项目具体实现
1.搭建springboot项目框架
2.引入支付宝支付的sdk
com.alipay.sdk
alipay-sdk-java
3.0.0
3.创建支付宝配置文件pay.properties
#支付宝的支付网关
alipay_url=https://openapi.alipay.com/gateway.do
#商家appid,我们注册账号所得到的appid
app_id=XXXXXXX
#商家我们自己的私钥
app_private_key=这里是我们在支付宝开发平台生成的自己的私钥
#支付宝的公钥
alipay_public_key=我们在支付宝开发平台获取的支付宝公钥
# 同步回调地址 重定向地址本地浏览器,用户支付完之后,支付宝回调我们的接口,一定要加http获取https的完整路径,并且不能带参数
return_payment_url=http://localhost:8011/pay/ret
# 异步通知地址 公网接口(webService)
notify_payment_url=http://60.205.215.91/alipay/callback/notify
4.创建支付配置文件,生成支付客户端bean
package com.pay.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;
import org.springframework.context.annotation.PropertySource;
/**
* @param
* @return
*/
@Configuration
@PropertySource("classpath:alipay.properties")
public class AlipayConfig {
@Value("${alipay_url}")
private String alipay_url;
@Value("${app_private_key}")
private String app_private_key;
@Value("${app_id}")
private String app_id;
//返回的数据格式
public final static String format = "json";
//使用的编码方式
public final static String charset = "utf-8";
//签名的加密算法
public final static String sign_type = "RSA2";
public static String return_payment_url;
public static String notify_payment_url;
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;
}
@Value("${return_payment_url}")
public void setReturn_url(String return_payment_url) {
AlipayConfig.return_payment_url = return_payment_url;
}
@Value("${notify_payment_url}")
public void setNotify_url(String notify_payment_url) {
AlipayConfig.notify_payment_url = notify_payment_url;
}
/**
*生成的客户端bean
**/
@Bean
public AlipayClient alipayClient() {
AlipayClient alipayClient = new DefaultAlipayClient(alipay_url, app_id, app_private_key, format, charset, alipay_public_key, sign_type);
return alipayClient;
}
}
5.下面就是就是我们要具体的实现支付宝支付的具体细节,也是最重要的部分,一定要每步都要自己看
(1).网页对接支付宝支付
@RestController
public class PayController {
@Autowired
AlipayClient alipayClient;
/**
* @Author yyk
* @Description //TODO 支付成功后的异步回调函数
* @Date 2020/6/3 0:13
* @Param [request, modelMap]
* @return java.lang.String
**/
@RequestMapping("pay/return")
public String reCall(HttpServletRequest request){
// 回调请求中获取支付宝参数
String sign = request.getParameter("sign");
String trade_no = request.getParameter("trade_no");
String out_trade_no = request.getParameter("out_trade_no");
String trade_status = request.getParameter("trade_status");
String total_amount = request.getParameter("total_amount");
String subject = request.getParameter("subject");
String call_back_content = request.getQueryString();
// 通过支付宝的paramsMap进行签名验证,2.0版本的接口将paramsMap参数去掉了,导致同步请求没法验签
if(sign!=null){
// 验签成功
System.out.println("验签成功");
//做具体的业务请求
}
return "succsee";
}
/**
* @Author yyk
* @Description //TODO 请求支付接口
* @Date 2020/6/3 0:06
* @Param [request]
* @return java.lang.String
**/
@RequestMapping("alipay/pay")
public String alipay(HttpServletRequest request){
String form="";
//获取一个支付宝客户端
AlipayTradePagePayRequest alipayTradePagePayRequest = new AlipayTradePagePayRequest();
//把回调函数也放入里面
alipayTradePagePayRequest.setReturnUrl(AlipayConfig.return_payment_url);
alipayTradePagePayRequest.setNotifyUrl(AlipayConfig.notify_payment_url);
Map map = new HashMap<>();
//商户网站唯一订单号
map.put("out_trade_no","1A4566776576");
//销售产品码,商家和支付宝签约的产品码,注:目前仅支持FAST_INSTANT_TRADE_PAY
map.put("product_code","FAST_INSTANT_TRADE_PAY");
//订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]。(,这里要与微信支付区分,微信支付单位为分)
map.put("total_amount",0.01);
//商品的标题/交易标题/订单标题/订单关键字等。
map.put("subject","XXXXX");
String param = JSON.toJSONString(map);
//biz_content,请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递,具体参照各产品快速接入文档
//下面我会具体介绍哪些是公共参数,哪些是请求参数
alipayTradePagePayRequest.setBizContent(param);
try {
//最核心内容,其实跟App对接的区别也在这里,返回的是一个form表单支付成功后会跳到这个页面
form = alipayClient.execute(alipayTradePagePayRequest).getBody();
System.out.println(form);
} catch (AlipayApiException e) {
e.printStackTrace();
}
return form;
}
}
当执行完alipay/pay支付接口时会出现下面的页面,支付之后,会回调pay/return接口,同时调用异步接口,这里没有写。在同步回调接口中2.0版本以后不再进行验签,但是异步回调一定要验签。并且异步回调返回给支付宝的结果一定是sucess
注意:异步接口必须是公网能访问的
请求时的公共参数和请求参数
公共参数就是我们在AlipayConfig类中配置的那些属性值
请求参数是我们在controller中传入到biz_content中的参数
具体参数请参考支付宝开发文档
https://opendocs.alipay.com/apis/api_1/alipay.trade.page.pay#%E5%85%AC%E5%85%B1%E5%8F%82%E6%95%B0
(2).对接App接口
/**
* @Author yyk
* @Description //TODO 请求app支付接口
* @Date 2020/6/3 0:36
* @Param []
* @return java.lang.String
**/
@RequestMapping("/app")
public String appAlipay(HttpServletRequest request){
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay,这里和网页接口是由区别的
**AlipayTradeAppPayRequest aliPayRequest = new AlipayTradeAppPayRequest();**
//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setSubject(subject);
model.setOutTradeNo("q23er56gg");
model.setTimeoutExpress("30m");
model.setTotalAmount(String.valueOf(orderPrice));// 单位:元
model.setProductCode("QUICK_MSECURITY_PAY");
aliPayRequest.setBizModel(model);
//回调接口
aliPayRequest.setReturnUrl(AlipayConfig.return_payment_url);
aliPayRequest.setNotifyUrl(AlipayConfig.notify_payment_url);
try {
//这里和普通的接口调用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(aliPayRequest);
//把这个返回给前端,然后前端调支付宝接口
String body1 = response.getBody();
return body1;
} catch (AlipayApiException e) {
//e.printStackTrace();
return null;
}
/**
* @Author yyk
* @Description //TODO 支付成功后的异步回调函数
* @Date 2020/6/3 0:13
* @Param [request, modelMap]
* @return java.lang.String
**/
@RequestMapping("pay/return")
public String reCall(HttpServletRequest request){
// 回调请求中获取支付宝参数
String sign = request.getParameter("sign");
String trade_no = request.getParameter("trade_no");
String out_trade_no = request.getParameter("out_trade_no");
String trade_status = request.getParameter("trade_status");
String total_amount = request.getParameter("total_amount");
String subject = request.getParameter("subject");
String call_back_content = request.getQueryString();
//AlipaySignature.rsaCheck();
// 通过支付宝的paramsMap进行签名验证,2.0版本的接口将paramsMap参数去掉了,导致同步请求没法验签
boolean signVerified = false;
try {
//3.1调用SDK验证签名,params是我们获取的参数,alipayPublicKey是支付宝公钥
signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.setAlipay_public_key,
"UTF-8", "RSA2");
} catch (AlipayApiException e) {
e.printStackTrace();
}
if(signVerified ){
system.out.println("验签通过");
}
return "调用succsee";
}
}