本文只介绍当面付(扫码支付)和APP支付
一. 接入准备
#这里分两种情况,正式环境和沙箱环境,本文使用沙箱环境
1.进入支付宝开放平台,创建应用
登录 支付宝开放平台,创建应用并提交审核,审核通过后会生成应用唯一标识 APPID,并且可以申请开通开放产品使用权限。通过 APPID 应用才能调用开放产品的接口能力。详情请参考 创建应用。
2.配置应用
应用创建完成后,系统会自动跳转到应用详情页面。您可以在 能力列表 中点击 添加能力 来添加 当面付 功能。详情请参见 添加应用功能。 添加需要的能力
3.开发设置
进入开发设置中完成接口加签方式、IP白名单、应用网关、接口内容加密方式开发信息设置。详情请参见 配置应用环境
- 接口加签方式:必填。用于保障商户应用和支付宝交互的安全性,配置详情参见 接口加签方式配置说明。
-
IP白名单:选填。用于保障用户资金安全,说明详情参见 IP 白名单接入指南。
-
应用网关:选填。用于接收支付宝异步通知消息,说明详情参见 应用网关。
-
接口内容加密方式:选填。用于加/解密 OpenAPI bizContent 报文内容及加/解密部分用户隐私信息,说明详情参见 接口内容加密方式。
-
授权回调地址:选填。第三方应用授权 或 用户信息授权 后回调地址。授权链接中配置的 redirect_uri 的值必须与此值保持一致 (如:https://www.alipay.com) ,用户成功授权后将在该 url 后携带授权码等信息并跳转至该页。当填入该地址时,系统会自动进行安全检测,详情请参考 安全检测。
4.设置接口加签方式
支付宝开放平台的应用管理体系,使用了公私钥的机制,商户可通过设置接口加签方式为自身应用配置 公私钥/公私钥证书 来保障商户应用和支付宝交互的安全性。密钥的获取方式请参见 生成密钥。
公钥证书与公钥的区别请参见 普通公钥与公钥证书区别。
简单说一下公钥私钥
使用支付宝支付加密方式有两种:1. 公钥私钥 2. 证书
1. 可使用支付宝提供的开发助手生成证书,生成后,支付宝会提供给你三个证书,分别为:私钥证书、公钥证书、支付宝公钥证书,
将生成的公钥证书配置到支付宝平台中,剩下的私钥证书和支付宝公钥留在本地使用
2. 同上使用支付宝开发助手生成密钥,将生成的公钥配置到支付宝,将支付宝公钥复制到本地。
密钥的作用:私钥签名,公钥验签;公钥加密,私钥解密;私钥是不能公开的。
为什么有两套密钥:开发者生成的私钥公钥、支付宝公钥-支付宝私钥;开发者需要签名,支付宝平台也需要签名。
其他步骤参照支付宝开放平台接入流程。
二. 编码阶段
1. 下载支付宝sdk
java使用maven引入即可
2.编码
封装配置类
1 @Data 2 @Configuration 3 @ConfigurationProperties(prefix = "alipay") 4 public class AliPayConfig implements Serializable { 5 6 private static final long serialVersionUID = -4736760736935998953L; 7 8 public AliPayConfig(){} 9 10 public AlipayClient build(){ 11 if(this.alipayClient == null){ 12 return new DefaultAlipayClient(this.getGatewayUrl(), 13 this.getAppId(), 14 this.getPrivateKey(), 15 this.getFormat(), 16 this.getCharset(), 17 this.getAliPublicKey(), 18 this.getSignType()); 19 } 20 return this.alipayClient; 21 } 22 23 /** 24 * 支付宝网关 25 */ 26 private String gatewayUrl; 27 28 /** 29 * 新版本 30 */ 31 private String newGatewayUrl; 32 33 /** 34 * AppId 35 */ 36 private String appId; 37 38 /** 39 * 应用私钥 40 */ 41 private String privateKey; 42 43 /** 44 * 请求使用的编码格式,如utf-8,gbk,gb2312等 45 */ 46 private String charset; 47 48 /** 49 * 仅支持JSON 50 */ 51 private String format; 52 53 /** 54 * 支付宝公钥 55 */ 56 private String aliPublicKey; 57 58 /** 59 * 加密方式 目前支持RSA2和RSA,推荐使用RSA2 60 */ 61 private String signType; 62 63 /** 64 * 回调地址 65 */ 66 private String notifyUrl; 67 68 /** 69 * ali 客户端 70 */ 71 private AlipayClient alipayClient; 72 73 /** 74 * 获取Config配置类 75 * @return Config 76 */ 77 public Config getConfig(){ 78 Config config = new Config(); 79 config.protocol = "https"; 80 config.gatewayHost = this.getNewGatewayUrl(); 81 config.signType = this.getSignType(); 82 config.appId = this.getAppId(); 83 config.merchantPrivateKey = this.getPrivateKey(); 84 config.alipayPublicKey = this.getAliPublicKey(); 85 config.notifyUrl = this.getNotifyUrl(); 86 return config; 87 } 88 }
老版支付宝sdk
1 @Slf4j 2 public class AliPayApi { 3 4 /** 5 * 统一收单线下交易预创建 (老版本sdk) 6 * 扫码支付 7 * @param model 8 * @param aliPayConfig 9 * @return 10 */ 11 public static AlipayTradePrecreateResponse tradePayToScanCode(AlipayTradePrecreateModel model, AliPayConfig aliPayConfig){ 12 log.info("扫码支付:"+model.getOutTradeNo()); 13 // 1.实例化API对应的request类 14 AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest(); 15 request.setBizModel(model); 16 // 2.发起请求 17 AlipayTradePrecreateResponse response = null; 18 try { 19 response = aliPayConfig.getAlipayClient().execute(request); 20 // 3.是否调用成功 21 if(response.isSuccess()){ 22 log.info("扫码支付调用成功:" + response.getBody()); 23 return response; 24 } 25 } catch (AlipayApiException e) { 26 log.info("扫码支付调用失败:" + e.getErrMsg()); 27 throw new RuntimeException(e); 28 } 29 log.debug("扫码支付调用失败:" + response.getMsg()); 30 return null; 31 } 32 }
新版支付宝sdk
1 /** 2 * 支付宝支付 新版sdk 3 * Create by Echo<php637.com> on 2021/1/22 0022 4 */ 5 @Slf4j 6 public class AliPayNewApi { 7 8 /** 9 * 统一收单线下交易预创建 10 * 扫码支付 11 * @param model 12 * @param aliPayProperties 13 * @return 14 */ 15 public static AlipayTradePrecreateResponse tradePayToScanCode(AlipayTradePrecreateModel model, AliPayConfig aliPayProperties){ 16 log.info("扫码支付:" + model.getOutTradeNo()); 17 // 1. 设置参数 18 Factory.setOptions(aliPayProperties.getConfig()); 19 AlipayTradePrecreateResponse response = null; 20 try{ 21 // 2. 发起Api调用 22 response = Factory.Payment.FaceToFace().preCreate(model.getSubject(), model.getOutTradeNo(), model.getTotalAmount()); 23 dumpResponse(response); 24 // 3. 处理响应 25 if(ResponseChecker.success(response)){ 26 log.info("扫码支付调用成功:" + response.getHttpBody()); 27 return response; 28 } 29 } catch (Exception e) { 30 log.debug("扫码支付调用异常:" + e.getMessage()); 31 throw new RuntimeException(e); 32 } 33 log.debug("扫码支付调用失败:" + response.getMsg()); 34 return null; 35 } 36 37 /** 38 * App支付 39 * @param model 40 * @param aliPayConfig 41 * @return 42 */ 43 public static AlipayTradeAppPayResponse tradePayToApp(AlipayTradeAppPayModel model, AliPayConfig aliPayConfig){ 44 log.info("支付宝app支付:" + model.getOutTradeNo()); 45 // 1. 设置参数 46 Factory.setOptions(aliPayConfig.getConfig()); 47 AlipayTradeAppPayResponse response = null; 48 try{ 49 // 2. 发起Api调用 50 response = Factory.Payment.App().pay(model.getSubject(), model.getOutTradeNo(), model.getTotalAmount()); 51 // 3. 处理响应 52 if (ResponseChecker.success(response)){ 53 return response; 54 } 55 } catch (Exception e) { 56 log.debug("支付宝app支付调用异常:" + e.getMessage()); 57 throw new RuntimeException(e); 58 } 59 log.debug("支付宝app支付调用失败:" + response.getBody()); 60 return null; 61 } 62 63 // 简单打印应答 64 private static void dumpResponse(AlipayTradePrecreateResponse response) { 65 if (response != null) { 66 log.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg())); 67 if (StringUtils.isNotEmpty(response.getSubCode())) { 68 log.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(), 69 response.getSubMsg())); 70 } 71 log.info("body:" + response.getHttpBody()); 72 } 73 } 74 }
测试和回调
1 @Autowired 2 private AliPayConfig aliPayProperties; 3 4 @Autowired 5 private SmsUtils smsUtils; 6 7 /** 8 * 扫码支付测试 老版本 9 * @return 10 */ 11 @RequestMapping("/test1") 12 public Object test1(){ 13 AlipayTradePrecreateModel model = new AlipayTradePrecreateModel(); 14 model.setOutTradeNo("123456789"); 15 model.setSubject("测试商品"); 16 model.setTotalAmount("20"); 17 System.out.println(AliPayApi.tradePayToScanCode(model, aliPayProperties)); 18 return new Return().success(); 19 } 20 21 /** 22 * 扫码支付测试 新版本 23 * @return 24 */ 25 @RequestMapping("/test2") 26 public Object test2(){ 27 AlipayTradePrecreateModel model = new AlipayTradePrecreateModel(); 28 model.setOutTradeNo("12341234"); 29 model.setSubject("新版支付"); 30 model.setTotalAmount("10"); 31 System.out.println(AliPayNewApi.tradePayToScanCode(model, aliPayProperties)); 32 return new Return().success(); 33 } 34 35 /** 36 * app支付测试 新版本 37 * @return 38 */ 39 @RequestMapping("/test3") 40 public Object test3(){ 41 AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); 42 model.setOutTradeNo("123412314"); 43 model.setSubject("新版app支付"); 44 model.setTotalAmount("10"); 45 return new Return().success(AliPayNewApi.tradePayToApp(model, aliPayProperties)); 46 } 47 48 /** 49 * 回调 50 * @param request 51 * @return 52 */ 53 @RequestMapping("/notify") 54 public Object alinNotify(HttpServletRequest request){ 55 // 1.获取回调参数 56 Map<String, String> params = new HashMap<>(); 57 Map requestParams = request.getParameterMap(); 58 for (Iterator iterable = requestParams.keySet().iterator(); iterable.hasNext();){ 59 String name = (String) iterable.next(); 60 String[] values = (String[]) requestParams.get(name); 61 StringBuffer valueStr = new StringBuffer(); 62 for (int i = 0; i < values.length; i++){ 63 if(i == values.length - 1){ 64 valueStr.append(values[i]); 65 }else{ 66 valueStr.append(values[i]); 67 valueStr.append(","); 68 } 69 params.put(name, valueStr.toString()); 70 } 71 } 72 log.info("支付宝回调,sign:{},trade_status:{},参数:{}",params.get("sign"),params.get("trade_status"),params.toString()); 73 // 2.验签 74 params.remove("sign"); 75 params.remove("sign_type"); 76 try { 77 boolean checkRes = AlipaySignature.rsaCheckV1(params, aliPayProperties.getAliPublicKey(), aliPayProperties.getCharset(), aliPayProperties.getSignType()); 78 if (!checkRes){ 79 return new Return().failed("非法请求,验证失败"); 80 } 81 } catch (AlipayApiException e) { 82 log.debug("支付宝验签异常:{}", e.getErrMsg()); 83 } 84 // 3.服务端订单参数验证及其他逻辑 85 // TODO 86 return "SUCCESS"; 87 }