目录
- 一、沙箱环境
- 1. 配置密钥/证书
- 系统默认密钥
- 自定义密钥
- 二、代码实现
- 2.1 项目总体结构
- 2.2 编码
- 1. 添加相关依赖
- 2. 配置文件:支付宝应用参数
- 3. 配置文件类
- 4. 初始化支付宝
- 5. 调用 AliPayApi 中的接口
- 扫码支付
- 支付回调
- 订单关闭
- 支付退款
- 订单查询
- 退款查询
- 2.3 测试
- 三、总结
参考文档:
一、沙箱环境
记录一下犯的错误.
二级标题与官方文档的二级标题一致:方便于自己对比
1. 配置密钥/证书
系统默认密钥
使用 API 在线调试工具 调试 OpenAPI 必须使用 系统默认密钥。
不需要再配置 获取加签密钥/证书
,系统的默认密钥在支付宝API 在线调试工具中可以看到,具体如下所示:
私钥:
公钥:
自定义密钥
官网文档:自定义密钥 里面写的很详细。
普通公钥与公钥证书二选一就行,普通公钥与公钥证书区别最主要区别是否涉及资金类支出接口接入。
需要注意的是:配置公钥证书,组织与公司
已经进行了更改
其他的与官方文档对应即可。
二、代码实现
2.1 项目总体结构
2.2 编码
省略了一个工具类:OrderCodeUtils
:主要用于订单号生成。
1. 添加相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.19</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- IJPay -->
<dependency>
<groupId>com.github.javen205</groupId>
<artifactId>IJPay-AliPay</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2. 配置文件:支付宝应用参数
server:
port: 1314
alipay:
# 应用编号
appId:
# 应用私钥
privateKey:
# 支付宝公钥 (如果是证书模式,公钥与私钥在CSR目录)
publicKey:
# 通知地址或回调地址 !回调地址一定是外网可以访问到的域名!
domain:
# 支付宝支付网关
serviceUrl:
# 应用公钥证书 (证书模式必须)
# appCertPath:
# 支付宝公钥证书 (证书模式必须)
# aliPayCertPath:
# 支付宝根证书 (证书模式必须)
# aliPayRootCertPath:
3. 配置文件类
@Component
@Data
@ConfigurationProperties(prefix = "alipay")
public class AlipayProperties {
private String appId;
private String privateKey;
private String publicKey;
private String doMain;
private String serviceUrl;
}
4. 初始化支付宝
为什么要初始化支付宝?
支付宝初始化的原因:IJPay 中默认是使用当前线程中的 appId 对应的配置
方法一:使用@PostConstruct注解
@PostConstruct注解原理解析:@PostConstruct注解的方法会在程序启动的时候执行
在启动类上添加@PostConstruct注解的方法:
@SpringBootApplication
public class AlipayApplication {
public static void main(String[] args){
SpringApplication.run(AlipayApplication.class, args);
}
@PostConstruct
public void aliPayInit() {
AlipayProperties aliPayProperties = SpringUtil.getBean(AlipayProperties.class);
AliPayApiConfig aliPayApiConfig = AliPayApiConfig.builder()
.setAppId(aliPayProperties.getAppId())
.setAliPayPublicKey(aliPayProperties.getPublicKey())
.setPrivateKey(aliPayProperties.getPrivateKey())
.setServiceUrl(aliPayProperties.getServiceUrl())
.setCharset("UTF-8")
.setSignType("RSA2")
.build();
AliPayApiConfigKit.putApiConfig(aliPayApiConfig);
}
}
方法二:使用方法拦截器
在OrderController
里面,添加初始化支付宝的方法
@RestController
@RequestMapping(value = "/aliPay")
@Slf4j
public class OrderController {
@Autowired
private AlipayProperties alipayProperties;
public AliPayApiConfig getApiConfig() {
AliPayApiConfig aliPayApiConfig = AliPayApiConfig.builder()
.setAppId(alipayProperties.getAppId())
.setAliPayPublicKey(alipayProperties.getPublicKey())
.setPrivateKey(alipayProperties.getPrivateKey())
.setServiceUrl(alipayProperties.getServiceUrl())
.setCharset("UTF-8")
.setSignType("RSA2")
// 证书模式
// .setAppCertPath(alipayProperties.getAppCertPath())
// .setAliPayCertPath(alipayProperties.getAliPayCertPath())
// .setAliPayRootCertPath(alipayProperties.getAliPayRootCertPath())
// 普通公钥方式
.build();
// 证书模式
// .buildByCert();
return aliPayApiConfig;
}
}
设置OrderController
的拦截器AliPayInterceptor
public class AliPayInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws AlipayApiException {
if (HandlerMethod.class.equals(handler.getClass())) {
HandlerMethod method = (HandlerMethod) handler;
Object methodBean = method.getBean();
AliPayApiConfigKit.setThreadLocalAliPayApiConfig(((OrderController) methodBean).getApiConfig());
return true;
}
return false;
}
}
AlipayConfig
继承WebMvcConfigurationSupport类,并配置拦截器
@Configuration
public class AlipayConfig extends WebMvcConfigurationSupport {
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AliPayInterceptor()).addPathPatterns("/aliPay/**");
super.addInterceptors(registry);
}
}
5. 调用 AliPayApi 中的接口
在OrderController
里面,编写URL请求方法。
此处,以调用 付款码支付 为例子。
扫码支付
这里会返回一个URL,到 二维码制作 中生成二维码,使用支付宝提供的 沙箱版支付宝钱包 ,登录买家账号,发起购买。
特别注意: 回调地址一定是外网可以访问到的域名,可以使用外网端口映射相关的工具来处理。(我买的是花生壳Http,6元),也可以找度娘。
/**
* 扫码支付
*
* @return java.lang.String
* @date 2022/2/9 11:34
*/
@GetMapping(value = "/tradePreCreatePay")
public String tradePreCreatePay() {
String notifyUrl = alipayProperties.getDoMain() + "/aliPay/aliPayNotifyUrl";
AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
model.setSubject("Javen 支付宝扫码支付测试");
model.setTotalAmount("10");
model.setStoreId("123");
model.setTimeoutExpress("5m");
String orderNo = OrderCodeUtils.getRandom();
model.setOutTradeNo(orderNo);
try {
AlipayTradePrecreateResponse response = AliPayApi.tradePrecreatePayToResponse(model, notifyUrl);
String resultStr = response.getBody();
JSONObject jsonObject = JSONObject.parseObject(resultStr);
return jsonObject.getJSONObject("alipay_trade_precreate_response").getString("qr_code");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
支付回调
/**
* 支付回调
*
* @param request 请求体
* @return java.lang.String
* @date 2022/2/9 11:34
*/
@PostMapping(value = "/aliPayNotifyUrl")
public String aliPayNotifyUrl(HttpServletRequest request) {
try {
// 获取支付宝POST过来反馈信息
Map<String, String> params = AliPayApi.toMap(request);
// 遍历打印出反馈信息
// for (Map.Entry<String, String> entry : params.entrySet()) {
// System.out.println(entry.getKey() + " = " + entry.getValue());
// }
boolean verifyResult = AlipaySignature.rsaCheckV1(params, alipayProperties.getPublicKey(), "UTF-8", "RSA2");
if (verifyResult) {
// TODO 请在这里加上商户的业务逻辑程序代码 异步通知可能出现订单重复通知 需要做去重处理
System.out.println("notify_url 验证成功succcess");
return "success";
} else {
System.out.println("notify_url 验证失败");
// TODO
return "failure";
}
} catch (AlipayApiException e) {
e.printStackTrace();
return "failure";
}
}
订单关闭
/**
* 关闭订单
*
* @param outTradeNo 商家内部订单号
* @date 2022/2/9 11:53
* @return java.lang.String
*/
@GetMapping(value = "/tradeClose")
public String tradeClose(@RequestParam("outTradeNo") String outTradeNo){
try {
AlipayTradeCloseModel closeModel = new AlipayTradeCloseModel();
closeModel.setOutTradeNo(outTradeNo);
return AliPayApi.tradeCloseToResponse(closeModel).getBody();
} catch (AlipayApiException e){
e.printStackTrace();
}
return null;
}
支付退款
/**
* 支付退款
*
* @param outTradeNo 商家内部订单号
* @date 2022/2/9 15:38
* @return java.lang.String
*/
@GetMapping(value = "/tradeRefund")
public String tradeRefund(@RequestParam("outTradeNo") String outTradeNo){
try {
AlipayTradeRefundModel refundModel = new AlipayTradeRefundModel();
refundModel.setOutTradeNo(outTradeNo);
refundModel.setRefundAmount("10");
refundModel.setRefundReason("退款测试");
return AliPayApi.tradeRefundToResponse(refundModel).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
订单查询
/**
* 订单查询
*
* @param outTradeNo 商家内部订单号
* @date 2022/2/9 15:37
* @return java.lang.String
*/
@GetMapping(value = "/tradeQuery")
public String tradeQuery(@RequestParam("outTradeNo") String outTradeNo){
AlipayTradeQueryModel queryModel = new AlipayTradeQueryModel();
queryModel.setOutTradeNo(outTradeNo);
try {
AlipayTradeQueryResponse queryResponse = AliPayApi.tradeQueryToResponse(queryModel);
return queryResponse.getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
退款查询
/**
* 退款查询
*
* @param outTradeNo 商户内部交易号
* @date 2022/2/9 15:47
* @return java.lang.String
*/
@GetMapping(value = "/refundQuery")
public String refundQuery(@RequestParam("outTradeNo") String outTradeNo){
AlipayTradeFastpayRefundQueryModel refundQueryModel = new AlipayTradeFastpayRefundQueryModel();
refundQueryModel.setOutTradeNo(outTradeNo);
refundQueryModel.setOutRequestNo(outTradeNo);
try {
return AliPayApi.tradeRefundQueryToResponse(refundQueryModel).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
2.3 测试
### 扫码支付
GET http://localhost:1314/aliPay/tradePreCreatePay
### 关闭订单
GET http://localhost:1314/aliPay/tradeClose?outTradeNo=1491259312927019008
### 支付退款
GET http://localhost:1314/aliPay/tradeRefund?outTradeNo=1491238575935721472
### 订单查询
GET http://localhost:1314/aliPay/tradeQuery?outTradeNo=1491259312927019008
### 退款查询
GET http://localhost:1314/aliPay/refundQuery?outTradeNo=1491238575935721472
三、总结
- 相比较于微信支付,阿里的支付宝开发文档支付实在是太友好了。
- 支付流程的话,与微信支付差不多。