开发前准备
easy支付官方文档:
通用版文档:
有基础的可以直接看文档自己搭建,官方文档写的很详细。
支付宝沙箱配置
1、注册支付宝开发者账户,进入开发者控制台
(有支付宝账户的直接支付宝扫码登入即可)
https://auth.alipay.com/login(这个直接登入到控制台)
沙箱快捷入口
2、进入沙箱
沙箱界面
3、下载支付宝开放平台开发助手,生成应用公钥和应用私钥(重点)
开发助手下载地址: 生成密钥 | 开放平台
载后直接安装,打开后直接生成秘钥,生成秘钥后电脑会有两个文件,分别保存有应用公钥和应用私钥
注:安装路径不要有中文,不要有空格
双击安装下载好的开发助手
点击生成秘钥,选择PKCS8(JAVA适用)
4、配置支付宝沙箱公钥
将应用公钥复制下来,然后到沙箱应用中配置生成支付宝公钥
5、沙箱账号说明
-
商家
用于收款的一方
-
买家
付款的一方,建议沙箱客户端登入该账号
沙箱环境支付,只能使用这两个账号实现支付功能。
6、沙箱工具
客户端用于手机端支付唤醒支付宝进行支付,以及网页端二维码支付时手机扫码支付
SpringBoot中配置
1、导入依赖
alipay-sdk 完整版 (支持中文的subject)
<dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>4.22.110.ALL</version> </dependency>
遇到的坑:
alipay-easysdk版不支持中文的subject
2、AliPayConfig配置类
public class AliPayConfig { // 应用ID,APPID,收款账号既是APPID对应支付宝账号 public static String app_id = "2021000120617096"; // 商户私钥,PKCS8格式RSA2私钥 刚刚生成的私钥直接复制填写 public static String merchant_private_key =""; // 支付宝公钥,对应APPID下的支付宝公钥,别填成商户公钥 public static String alipay_public_key =""; // 服务器异步通知页面路径 需http://格式的完整路径,其实就是支付完成后返回的页面URL // public static String notify_url = neturl+"/alipay/notify_url"; public static String notify_url =""; // 页面跳转同步通知页面路径 需http://格式的完整路径,其实就是你的一个支付完成后返回的页面URL // public static String return_url = neturl+"/alipay/return_url"; public static String return_url =""; // 签名方式 public static String sign_type = "RSA2"; // 字符编码格式 public static String charset = "utf-8"; // 支付宝网关 public static String gatewayUrl = "https://openapi.alipaydev.com/gateway.do"; }
3、AliPayBean
@Data public class AlipayBean implements Serializable { /** * 商户订单号 */ private String out_trade_no; /** * 订单名称 */ private String subject; /** * 付款金额 */ private String total_amount; /** * 商品描述 */ private String body; /** * 产品编号,支付方式不同,传的数据不同 */ //如果是PC网页支付,这个是必传参数 private String product_code = "FAST_INSTANT_TRADE_PAY"; //如果是扫码支付,这个是选传参数 //private String product_code = "FACE_TO_FACE_PAYMENT"; }
4、AliPayController
@Controller @Slf4j @RequestMapping("/payment") public class AlipayController extends BaseController{ @Autowired private OrdersService ordersService; @SneakyThrows @RequestMapping("/pay") @ResponseBody
手机版的支付宝支付跳转(会跳转到app)
public void aliPay() { AlipayClient alipayClient = new DefaultAlipayClient(AliPayConfig.gatewayUrl, AliPayConfig.app_id, AliPayConfig.merchant_private_key, "json", AliPayConfig.charset, AliPayConfig.alipay_public_key, AliPayConfig.sign_type); AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest(); request.setNotifyUrl(AliPayConfig.notify_url); request.setReturnUrl(AliPayConfig.return_url); JSONObject bizContent = new JSONObject(); bizContent.put("out_trade_no","111111"); bizContent.put("total_amount", "0,01"); bizContent.put("subject", "a"); bizContent.put("product_code", "QUICK_WAP_WAY"); bizContent.put("time_expire", LocalDateTime.now().plusMinutes(30)); // request.setBizContent(bizContent.toString()); // AlipayTradeWapPayResponse response = alipayClient.pageExecute(request); String result = null; try { result = alipayClient.pageExecute(request).getBody(); } catch (AlipayApiException e) { e.printStackTrace(); } log.info("返回结果={}",result); } }
Web版的支付宝扫码支付
@SneakyThrows
@RequestMapping("/pay")
@ResponseBody
public void aliPay() {
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(AliPayConfig.gatewayUrl, AliPayConfig.app_id, AliPayConfig.merchant_private_key, "json", AliPayConfig.charset, AliPayConfig.alipay_public_key, AliPayConfig.sign_type);
//设置请求参数
AlipayTradePagePayRequest aliPayRequest = new AlipayTradePagePayRequest();
//商户订单号,,必填
String order_number = new String("1111123");
//付款金额,从前台获取,必填
String total_amount = new String("201314");
//订单名称,必填
String subject = new String("NewBoy");
aliPayRequest.setBizContent("{\"out_trade_no\":\"" + order_number + "\","
+ "\"total_amount\":\"" + total_amount + "\","
+ "\"subject\":\"" + subject + "\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//请求
String result = null;
try {
result = alipayClient.pageExecute(aliPayRequest).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
//输出
log.info("返回结果={}",result);
}
5、WebMvcConfig放行payment
@Override protected void addInterceptors(InterceptorRegistry registry) { log.info("加载了用户权限拦截器"); //不拦截的地址 List<String> urls = Arrays.asList(new String[]{ "/employee/login", "/employee/logout", "/backend/**", "/front/**", "/common/**", "/user/sendMsg", "/user/login", "/swagger-ui.html/**", "/payment/**" }); registry.addInterceptor(new CheckLoginInterceptor()).addPathPatterns("/**").excludePathPatterns(urls); }
6.支付阶段测试
postman请求支付接口
控制台打印以下内容代表成功
点击链接跳转到该页面(有些直接跳转会出现验签错误)
7、支付成功回调方法(AliPayController)
@Controller @Slf4j @RequestMapping("/payment") public class AlipayController extends BaseController{ @SneakyThrows @RequestMapping(value = "/notify",method = {RequestMethod.GET,RequestMethod.HEAD,RequestMethod.POST}) // 注意这里必须是POST接口 @ResponseBody public void payNotify() { if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) { System.out.println("=========支付宝异步回调========"); Map<String, String> params = new HashMap<>(); Map<String, String[]> requestParams = request.getParameterMap(); for (String name : requestParams.keySet()) { params.put(name, request.getParameter(name)); // System.out.println(name + " = " + request.getParameter(name)); } String tradeNo = params.get("out_trade_no"); String gmtPayment = params.get("gmt_payment"); String alipayTradeNo = params.get("trade_no"); System.out.println("交易名称: " + params.get("subject")); System.out.println("交易状态: " + params.get("trade_status")); System.out.println("支付宝交易凭证号: " + params.get("trade_no")); System.out.println("商户订单号: " + params.get("out_trade_no")); System.out.println("交易金额: " + params.get("total_amount")); System.out.println("买家在支付宝唯一id: " + params.get("buyer_id")); System.out.println("买家付款时间: " + params.get("gmt_payment")); System.out.println("买家付款金额: " + params.get("buyer_pay_amount")); // 更新订单为已支付(4) } } }
8、沙箱配置回调网关
内网穿透
简单来说内网穿透:让外网能访问你本地的应用,例如在外网打开你本地http://127.0.0.1的指向Web站点。
内网穿透工具:花生壳(收费)、Natapp(免费)
Natapp注册
在这里我们使用一个免费的内网穿透工具:Natapp:NATAPP官网
在这里有详细教程:一分钟的natapp快速新手教程,在文档中已经提供
-
首先注册一个用户,要提供手机号
-
购买隧道,如果是免费隧道,需要进行实名认证和支付宝认证。
-
购买一个免费隧道
-
后期还可以在"我的隧道"中修改
natapp的使用
-
在这里复制authtoken,在natapp中配置的时候需要用到
-
找到natapp目录下的config.ini文件,把其中的authtoken改成上面的值
-
运行natapp,生成外网随机访问的地址。注:免费的生成地址不稳定,半小时可能会变了。
注:支付成功回调地址就是上面的外网域名加上你的接口方法地址
例如:http://fzkvax.natappfree.cc/payment/notify