开发环境用沙箱
一、获取支付宝开放平台配置
第一步:登录支付宝开放平台
链接:支付宝开放平台 第二步:点击控制台
第三步:点击左下方沙箱
这里面有三个需要获取的信息,一个是appid,一个是应用私钥,一个是支付宝公钥。这里复制下来下面用到。
二、项目中引入
第一步:引入依赖
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.31.12.ALL</version>
</dependency>
第二步:添加配置文件
一种是在 resources 目录下添加一个 alipay.properties 文件,写入支付宝配置信息。
另一种是在全局配置文件中用key-value的配置方式。
这里介绍第一种。
alipay.properties
# 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
appId: appid
# 商户私钥,您的PKCS8格式RSA2私钥
privateKey: privateKey
# 支付宝公钥,查看地址:https://openhome.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
publicKey: publicKey
# 服务器异步通知页面路径需http://格式的完整路径,不能加?id=123这类自定义参数
notifyUrl: http://外网ip:端口/error.html
# 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数
returnUrl: http://外网ip:端口/sccess.html
# 签名方式
signType: RSA2
# 字符编码格式
charset: utf-8
# 支付宝网关
gatewayUrl: https://openapi.alipaydev.com/gateway.do
# 支付宝网关
logPath: "C:\\"
第三步:增加一个 PropertiesListener 监听器用于在应用启动时加载配置文件属性。
PropertiesListener.java
package com.louis.epay.config;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import com.louis.epay.alipay.AlipayProperties;
/**
* 配置文件监听器,用来加载自定义配置文件
*/
@Component
public class PropertiesListener implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
AlipayProperties.loadProperties();
}
}
上面的监听器加载属性,是通过具体的属性加载器加载的,比如支付宝支付属性加载类如下。
AlipayProperties.java
package com.louis.epay.alipay;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;
/**
* 应用启动加载文件
*/
@Component
public class AlipayProperties {
public static final String APP_ID = "appId";
public static final String PRIVARY_KEY = "privateKey";
public static final String PUBLIC_KEY = "publicKey";
public static final String NOTIFY_URL = "notifyUrl";
public static final String RETURN_URL = "returnUrl";
public static final String SIGN_TYPE = "signType";
public static final String CHARSET = "charset";
public static final String GATEWAY_URL = "gatewayUrl";
public static final String LOG_PATH = "logPath";
/**
* 保存加载配置参数
*/
private static Map<String, String> propertiesMap = new HashMap<String, String>();
/**
* 加载属性
*/
public static void loadProperties() {
// 获得PathMatchingResourcePatternResolver对象
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
// 加载resource文件(也可以加载resources)
Resource resources = resolver.getResource("classpath:alipay.properties");
PropertiesFactoryBean config = new PropertiesFactoryBean();
config.setLocation(resources);
config.afterPropertiesSet();
Properties prop = config.getObject();
// 循环遍历所有得键值对并且存入集合
for (String key : prop.stringPropertyNames()) {
propertiesMap.put(key, (String) prop.get(key));
}
} catch (Exception e) {
new Exception("配置文件加载失败");
}
}
/**
* 获取配置参数值
* @param key
* @return
*/
public static String getKey(String key) {
return propertiesMap.get(key);
}
public static String getAppId() {
return propertiesMap.get(APP_ID);
}
public static String getPrivateKey() {
return propertiesMap.get(PRIVARY_KEY);
}
public static String getPublicKey() {
return propertiesMap.get(PUBLIC_KEY);
}
public static String getNotifyUrl() {
return propertiesMap.get(NOTIFY_URL);
}
public static String getReturnUrl() {
return propertiesMap.get(RETURN_URL);
}
public static String getSignType() {
return propertiesMap.get(SIGN_TYPE);
}
public static String getCharset() {
return propertiesMap.get(CHARSET);
}
public static String getGatewayUrl() {
return propertiesMap.get(GATEWAY_URL);
}
public static String getLogPath() {
return propertiesMap.get(LOG_PATH);
}
}
第四步:支付宝支付接口封装
Alipay 是对支付宝支付功能的封装,它接收一个 AlipayBean 为参数,最终通过调用 AlipayClient 的 pageExecute 方法返回支付页面。
Alipay.java
package com.louis.epay.alipay;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
/**
* 支付宝支付接口
*/
@Component
public class Alipay {
/**
* 支付接口
* @param alipayBean
* @return
* @throws AlipayApiException
*/
public String pay(AlipayBean alipayBean) throws AlipayApiException {
// 1、获得初始化的AlipayClient
String serverUrl = AlipayProperties.getGatewayUrl();
String appId = AlipayProperties.getAppId();
String privateKey = AlipayProperties.getPrivateKey();
String format = "json";
String charset = AlipayProperties.getCharset();
String alipayPublicKey = AlipayProperties.getPublicKey();
String signType = AlipayProperties.getSignType();
String returnUrl = AlipayProperties.getReturnUrl();
String notifyUrl = AlipayProperties.getNotifyUrl();
AlipayClient alipayClient = new DefaultAlipayClient(serverUrl, appId, privateKey, format, charset, alipayPublicKey, signType);
// 2、设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
// 页面跳转同步通知页面路径
alipayRequest.setReturnUrl(returnUrl);
// 服务器异步通知页面路径
alipayRequest.setNotifyUrl(notifyUrl);
// 封装参数
alipayRequest.setBizContent(JSON.toJSONString(alipayBean));
// 3、请求支付宝进行付款,并获取支付结果
String result = alipayClient.pageExecute(alipayRequest).getBody();
// 返回付款信息
return result;
}
}
接口调用参数封装对象如下。
AlipayBean.java
package com.louis.epay.alipay;
/**
* 支付实体对象
* 根据支付宝接口协议,其中的属性名,必须使用下划线,不能修改
*/
public class AlipayBean {
/**
* 商户订单号,必填
*
*/
private String out_trade_no;
/**
* 订单名称,必填
*/
private String subject;
/**
* 付款金额,必填
* 根据支付宝接口协议,必须使用下划线
*/
private String total_amount;
/**
* 商品描述,可空
*/
private String body;
/**
* 超时时间参数
*/
private String timeout_express= "10m";
/**
* 产品编号
*/
private String product_code= "FAST_INSTANT_TRADE_PAY";
public String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getTotal_amount() {
return total_amount;
}
public void setTotal_amount(String total_amount) {
this.total_amount = total_amount;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getTimeout_express() {
return timeout_express;
}
public void setTimeout_express(String timeout_express) {
this.timeout_express = timeout_express;
}
public String getProduct_code() {
return product_code;
}
public void setProduct_code(String product_code) {
this.product_code = product_code;
}
}
第五步:订单业务封装
订单业务提供支付宝支付接口 alipay,内部通过调用 PayService 完成订单支付。
OrderController.java
package com.louis.epay.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alipay.api.AlipayApiException;
import com.louis.epay.alipay.AlipayBean;
import com.louis.epay.service.PayService;
/**
* 订单接口
*
*/
@RestController()
@RequestMapping("order")
public class OrderController {
@Autowired
private PayService payService;
/**
* 阿里支付
* @param tradeNo
* @param subject
* @param amount
* @param body
* @return
* @throws AlipayApiException
*/
@PostMapping(value = "alipay")
public String alipay(String outTradeNo, String subject, String totalAmount, String body) throws AlipayApiException {
AlipayBean alipayBean = new AlipayBean();
alipayBean.setOut_trade_no(outTradeNo);
alipayBean.setSubject(subject);
alipayBean.setTotal_amount(totalAmount);
alipayBean.setBody(body);
return payService.aliPay(alipayBean);
}
}
PayService 封装了 Alipay, 统一对外提供的支付服务接口。
PayService.java
package com.louis.epay.service;
import com.alipay.api.AlipayApiException;
import com.louis.epay.alipay.AlipayBean;
/**
* 支付服务
*/
public interface PayService {
/**
* 支付宝支付接口
* @param alipayBean
* @return
* @throws AlipayApiException
*/
String aliPay(AlipayBean alipayBean) throws AlipayApiException;
}
支付服务的实现类,通过对各种支付代码的调用,统一对外提供支付服务。
PayServiceImpl.java
package com.louis.epay.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alipay.api.AlipayApiException;
import com.louis.epay.alipay.Alipay;
import com.louis.epay.alipay.AlipayBean;
import com.louis.epay.service.PayService;
@Service
public class PayServiceImpl implements PayService {
@Autowired
private Alipay alipay;
@Override
public String aliPay(AlipayBean alipayBean) throws AlipayApiException {
return alipay.pay(alipayBean);
}
}
至此,支付宝支付后端的部分就完成了。
这里讲解一下两个参数:notifyUrl和returnUrl,前者是后端的接口地址,用于支付成功之后的回调;后者是前端页面的地址,用于支付成功后跳转到指定页面,本地测试可以用127.0.0.1这个IP,正式环境时需要该ip是能被外网访问的。
还有,上面的gatewayUrl参数是沙箱环境的网关,正式的网关是:
https://openapi.alipay.com/gateway.do