SpringBoot 接入支付宝 SDK(支付宝支付你会吗?)

26 篇文章 1 订阅

SpringBoot 接入支付宝SDK

最近有好奇网页/手机扫码付款支付宝如何实现的?然后去学习了一下, 发现还是很简单的~,记录一下吧(下次就直接拿来用了)

前言

我在学习的时候,发现与支付宝SDK对接,最麻烦的却是接入前的一些准备工作,但是好在官网其实很详细了

大家可以去 网页 & 移动接入 详细的进行接入前的准备工作(电脑网站支付 手机网站支付 网页支付)

具体就是几个步骤:(详细的配置这里就不说明了,都很清晰)

  • 创建应用

    创建应用 中创建应用并提交审核,审核通过后会生成应用 唯一标识 APPID,并且可以申请开通开放产品使用权限,通过 APPID 应用才能调用开放产品的接口能力

  • 配置应用(根据自己的需求进行配置)

    • 添加功能。在应用详情页面中 能力列表 中点击 添加能力 来添加 电脑网站支付 功能 添加应用功能
    • 开发设置。主要是配置一些 接口加签方式、IP白名单、应用网关、接口内容加密方式 (这里的接口内容加密方式比较重要,下面会介绍)
    • 上线应用与签约。详细步骤可参考 上线应用 应用上线后,还需要完成应用签约才能在线上环境(生产环境)使用功能。

总结:

上述的准备工作,在下面的集成中,我们需要的东西为:

  • APPID(创建应用得到的标识ID)
  • 加密方式,根据加密方式的不同,所需内容有所不同
    • 普通公钥模式加签:APP_PRIVATE_KEY(应用私钥) ALIPAY_PUBLIC_KEY (支付宝公钥)
    • 公钥证书模式加签:APP_PRIVATE_KEY(应用私钥)app_cert_path(应用公钥证书文件本地路径)alipay_cert_path(支付宝公钥证书文件本地路径)alipay_root_cert_path(支付宝根证书文件本地路径)

APPID 创建应用就有了,其他的字段看下面的介绍。有上述的东西,我们就可以进行下面的集成了

接口内容加密方式介绍

以下内容参考 接口加签方式 进行介绍。常用的接口加签方式有两种:

  • 公钥证书模式:企业开发者若涉及 alipay.fund.trans.uni.transfer 接口(即 现金红包转账功能)接入,必须使用 公钥证书 方式。
  • 公钥模式:个人开发者不涉及到 alipay.fund.trans.uni.transfer 接口,使用 公钥模式 进行加签。

首先通过 获取公钥 获取应用公私钥/公钥证书,待获取完成之后,在申请的具体应用详情页 > 设置 > 开发设置 > 接口加签方式,点击 设置,上传获取到的 CSR 文件,以此来获取 应用公钥证书支付宝根证书支付宝公钥证书 等信息(这里可以获取到应用私钥 即 APP_PRIVATE_KEY(应用私钥) )

请添加图片描述

  • 公钥证书模式:下载上述图中的三个证书到本地,然后就知晓 app_cert_path(应用公钥证书文件本地路径)alipay_cert_path(支付宝公钥证书文件本地路径)alipay_root_cert_path(支付宝根证书文件本地路径)
  • 公钥模式:上述图中的支付宝公钥即对应 ALIPAY_PUBLIC_KEY (支付宝公钥)

集成SDK

1、导包

集成首先导包:

  • Maven 项目依赖

    <properties>
        <alipay.version>4.9.153.ALL</alipay.version>
    </properties> 
    <!--支付宝依赖-->
    <dependency>
         <groupId>com.alipay.sdk</groupId>
          <artifactId>alipay-sdk-java</artifactId>
          <version>${alipay.version}</version>
    </dependency>
    
  • GitHub 项目主页

2、确定加签方式与签名算法类型

在上述接口内容加密方式介绍的加密方式,根据加密方式的不同,所需内容有所不同

  • 普通公钥模式加签:APP_PRIVATE_KEY(应用私钥) ALIPAY_PUBLIC_KEY (支付宝公钥)
  • 公钥证书模式加签:APP_PRIVATE_KEY(应用私钥)app_cert_path(应用公钥证书文件本地路径)alipay_cert_path(支付宝公钥证书文件本地路径)alipay_root_cert_path(支付宝根证书文件本地路径)

根据所需的内容与加签的方式,了解所需的参数

普通公钥模式关键参数说明
配置参数示例值解释获取方式/示例值
URL支付宝网关(固定)https://openapi.alipay.com/gateway.do
APPIDAPPID 即创建应用后生成获取到的 APPID
APP_PRIVATE_KEY开发者私钥,由开发者自己生成获取到的 APP_PRIVATE_KEY
FORMAT参数返回格式,只支持 JSON 格式json
CHARSET编码集,支持 GBK/UTF-8开发者根据实际工程编码配置
ALIPAY_PUBLIC_KEY支付宝公钥,由支付宝生成获取到的 ALIPAY_PUBLIC_KEY
SIGN_TYPE商户生成签名字符串所使用的签名算法类型,目前支持 RSA2 和 RSA,推荐使用 RSA2根据加密所选的算法来决定

可根据上述字段相应的实体类:

这里用到了 lombokswagger,不了解的可详细看:Swagger 介绍(Swagger 与 SpringBoot 集成)lombok 的使用

package com.study.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
 * 支付宝配置类
 */
@Data
public class AlipayConfig implements Serializable {

    @ApiModelProperty(value = "支付宝开放安全地址", hidden = true)
    private String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";
    
    @NotBlank
    @ApiModelProperty(value = "应用ID")
    private String appId;

    @NotBlank
    @ApiModelProperty(value = "商户私钥")
    private String privateKey;
    
    @ApiModelProperty(value = "编码", hidden = true)
    private String charset= "utf-8";
    
    @ApiModelProperty(value = "类型")
    private String format="JSON";

    @NotBlank
    @ApiModelProperty(value = "支付宝公钥")
    private String publicKey;

    @ApiModelProperty(value = "签名方式")
    private String signType="RSA2";
}
公钥证书模式关键参数说明
配置参数示例值解释获取方式/示例值
URL支付宝网关(固定)https://openapi.alipay.com/gateway.do
APPIDAPPID 即创建应用后生成获取到的 APPID
APP_PRIVATE_KEY开发者私钥,由开发者自己生成获取到的 APP_PRIVATE_KEY
FORMAT参数返回格式,只支持 JSON(固定)json
CHARSET编码集,支持 GBK/UTF-8开发者根据实际工程编码配置
SIGN_TYPE商户生成签名字符串所使用的签名算法类型,目前支持 RSA2 和 RSA,推荐使用 RSA2根据加密所选的算法来决定
app_cert_path应用公钥证书文件本地路径上面相应文件下载后的路径
alipay_cert_path支付宝公钥证书文件本地路径上面相应文件下载后的路径
alipay_root_cert_path支付宝根证书文件本地路径上面相应文件下载后的路径

根据配置同样可写相应的配置类:

package com.study.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
 * 支付宝配置类
 */
@Data
public class AlipayConfig implements Serializable {

    @ApiModelProperty(value = "支付宝开放安全地址", hidden = true)
    private String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";
    
    @NotBlank
    @ApiModelProperty(value = "应用ID")
    private String appId;

    @NotBlank
    @ApiModelProperty(value = "商户私钥")
    private String privateKey;
    
    @ApiModelProperty(value = "编码", hidden = true)
    private String charset= "utf-8";
    
    @ApiModelProperty(value = "类型")
    private String format="JSON";

    @NotBlank
    @ApiModelProperty(value = "应用公钥证书文件本地路径")
    private String appCertPath;
 
   	@NotBlank
    @ApiModelProperty(value = "支付宝公钥证书文件本地路径")
    private String alipayCertPath;
	
    @NotBlank
    @ApiModelProperty(value = "支付宝根证书文件本地路径")
    private String alipayRootCertPath;
    
    @ApiModelProperty(value = "签名方式")
    private String signType="RSA2";
}

上述的参数主要用于构造我们SDK集成所需的Client

3、请求参数与响应参数说明

不同的接口的请求参数与响应参数不完全一致,可查看具体调用的接口的参数说明 API列表

下面以 PC场景下单并支付 (接口名称为 alipay.trade.page.pay )的接口为例进行说明:

请求参数
参数类型是否必填最大长度描述示例值
app_idString32支付宝分配给开发者的应用ID2014072300007148
methodString128接口名称alipay.trade.page.pay
formatString40仅支持JSONJSON
return_urlString256HTTP/HTTPS开头字符串https://m.alipay.com/Gk8NF23
charsetString10请求使用的编码格式,如utf-8,gbk,gb2312等utf-8
sign_typeString10商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2RSA2
signString344商户请求参数的签名串,详见签名详见示例
timestampString19发送请求的时间,格式"yyyy-MM-dd HH:mm:ss"2014-07-24 03:07:50
versionString3调用的接口版本,固定为:1.01.0
notify_urlString256支付宝服务器主动通知商户服务器里指定的页面http/https路径。http://api.test.alipay.net/atinterface/receive_notify.htm
app_auth_tokenString40详见应用授权概述
biz_contentString请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递

其中 biz_content 的字段说明:

参数类型是否必填最大长度描述示例值
out_trade_noString必选64商户订单号。 由商家自定义,64个字符以内,仅支持字母、数字、下划线且需保证在商户端不重复20150320010101001
total_amountPrice必选11订单总金额,单位为元,精确到小数点后两位,取值范围为 [0.01,100000000],不能为0。88.88
subjectString必选256订单标题。 注意:不可使用特殊字符,如 /,=,& 等。Iphone6 16G
product_codeString必选64销售产品码,与支付宝签约的产品码名称。注:目前电脑支付场景下仅支持 FAST_INSTANT_TRADE_PAYFAST_INSTANT_TRADE_PAY
qr_pay_modeString可选2PC扫码支付的方式。 支持前置模式和跳转模式。
前置模式是将二维码前置到商户的订单确认页的模式。需要商户在自己的页面中以 iframe 方式请求支付宝页面

跳转模式是用户的扫码界面是由支付宝生成的,不在商户的域名下
具体支持的枚举值有以下几种:
0:订单码-简约前置模式,对应 iframe 宽度不能小于600px,高度不能小于300px;
1:订单码-前置模式,对应iframe 宽度不能小于 300px,高度不能小于600px;

2:订单码-跳转模式
3:订单码-迷你前置模式,对应 iframe 宽度不能小于 75px,高度不能小于75px;
4:订单码-可定义宽度的嵌入式二维码,商户可根据需要设定二维码的大小。
1
qrcode_widthNumber可选4商户自定义二维码宽度。 注:qr_pay_mode=4时该参数有效100
goods_detailGoodsDetail[]可选订单包含的商品列表信息,json格式。
time_expireString可选32订单绝对超时时间。 格式为yyyy-MM-dd HH:mm:ss。 注:time_expire和timeout_express两者只需传入一个或者都不传,两者均传入时,优先使用time_expire。2016-12-31 10:05:01
sub_merchantSubMerchant可选二级商户信息。 直付通模式和机构间连模式下必传,其它场景下不需要传入。
extend_paramsExtendParams可选业务扩展参数
business_paramsString可选512商户传入业务信息,具体值要和支付宝约定,应用于安全,营销等参数直传场景,格式为json格式{“data”:“123”}
promo_paramsString可选512优惠参数。为 JSON 格式。注:仅与支付宝协商后可用{“storeIdType”:“1”}
integration_typeString可选16请求后页面的集成方式。 枚举值: ALIAPP:支付宝钱包内 PCWEB:PC端访问 默认值为PCWEB。PCWEB
request_from_urlString可选256请求来源地址。如果使用ALIAPP的集成方式,用户中途取消支付会返回该地址。https://
store_idString可选32商户门店编号。 指商户创建门店时输入的门店编号。NJ_001
merchant_order_noString可选32商户原始订单号,最大长度限制 32 位20161008001
invoice_infoInvoiceInfo可选开票信息
响应参数

状态相关参数:

参数类型是否必填描述示例值
codeString网关返回码,详见文档40004
msgString网关返回码描述,详见文档Business Failed
sub_codeString业务返回码,参见具体的API接口文档ACQ.TRADE_HAS_SUCCESS
sub_msgString业务返回码描述,参见具体的API接口文档交易已被支付
signString签名,详见文档DZXh8eeTuAHoYE3w1J+POiPhfDxOYBfU
Nn1lkeT/V7P4zJdyojWEa6IZs6Hz0yDW5Cp/vi
ufUb5I0/V5WENS3OYR8zRedqo6D+fUTdLHdc+EFyCkiQhBxI
zgngPdPdfp1PIS7BdhhzrsZHbRqb7o4k3Dxc+AAnFauu4V6Zdwczo=

数据相关参数:

参数类型是否必填最大长度描述示例值
trade_noString必选64支付宝交易号2013112011001004330000121536
out_trade_noString必选64商户订单号6823789339978248
seller_idString必选28收款支付宝账号对应的支付宝唯一用户号。 以2088开头的纯16位数字2088111111116894
total_amountPrice必选11交易金额128.00
merchant_order_noString必选32商户原始订单号,最大长度限制32位20161008001

异常例子:

{	
    // 这个key 对应 请求参数的 method
    "alipay_trade_query_response": {
        "code": "20000",
        "msg": "Service Currently Unavailable",
        "sub_code": "isp.unknow-error",
        "sub_msg": "系统繁忙"
    },
    "sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"
}

4、请求示例

一般直接使用 DefaultAlipayClient 就可完成我们的需求,三个步骤:

  • 创建 Client 。 一般就创建 DefaultAlipayClient 即可
  • 创建Reqeust 。根据不同的端/不同的加签方式会有所不同,常用的:
    • 普通 公钥证书 模式加签 CertAlipayRequest
    • 电脑网页端 AlipayTradePagePayRequest
    • 手机网页版 AlipayTradeWapPayRequest
    • 批量请求 BatchAlipayRequest
  • 调用请求方法,发送请求

example:

@Override
public String toPayAsPc(AlipayConfig alipay, TradeVo trade) throws Exception {
    String returnUrl = "https://m.alipay.com/Gk8NF23"; // 返回页面,也可放入 AlipayConfig 中
    String notifyUrl = "http://api.test.alipay.net/atinterface/receive_notify.htm"; // 异步通知地址,也可放入 AlipayConfig 中
    // 1、构建Client
    AlipayClient alipayClient = new DefaultAlipayClient(alipay.getGatewayUrl(), alipay.getAppId(), alipay.getPrivateKey(), alipay.getFormat(), alipay.getCharset(), alipay.getPublicKey(), alipay.getSignType());

    // 2、创建API对应的request(电脑网页版) 
    AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
    // 创建API对应的request(手机网页版)
    // AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();

    // 订单完成后返回的页面和异步通知地址
    request.setReturnUrl(returnUrl);
    request.setNotifyUrl(notifyUrl);
    // 填充业务参数
    request.setBizContent("{" +
            "    \"out_trade_no\":\""+trade.getOutTradeNo()+"\"," +
            "    \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," +
            "    \"total_amount\":"+trade.getTotalAmount()+"," +
            "    \"subject\":\""+trade.getSubject()+"\"," +
            "    \"body\":\""+trade.getBody()+"\"," +
            "    \"extend_params\":{" +
            "    \"sys_service_provider_id\":\""+alipay.getSysServiceProviderId()+"\"" +
            "    }"+
            "  }");
    // 3、调用SDK生成表单, 通过GET方式
    return alipayClient.pageExecute(request, "GET").getBody();
}

说明:

第一步 创建 Client ,其提供了很多的重载构造方法供其构造,设置一些所有请求都包含的公共参数字段

  • com.alipay.api.DefaultAlipayClient
package com.alipay.api;
import java.security.cert.X509Certificate;
import java.util.concurrent.ConcurrentHashMap;
public class DefaultAlipayClient extends AbstractAlipayClient {
    private String                                     privateKey; 
    private String                                     encryptKey;
    private String                                     alipayPublicKey;
    private Signer                                     signer;
    private SignChecker                                signChecker;
    private Encryptor                                  encryptor; 
    private Decryptor                                  decryptor;
    private X509Certificate                            cert;
    private ConcurrentHashMap<String, X509Certificate> alipayPublicCertMap;
	// 1
    public DefaultAlipayClient(String serverUrl, String appId, String privateKey) {
        ....
    }
	// 2
    public DefaultAlipayClient(String serverUrl, String appId, String privateKey, String format) {
       .....
    }
	// 3
    public DefaultAlipayClient(String serverUrl, String appId, String privateKey, String format,
                               String charset) {
        .....
    }
	// 4
    public DefaultAlipayClient(String serverUrl, String appId, String privateKey, String format,
                               String charset, String alipayPublicKey) {
        ....
    }
	//5  常用 
    public DefaultAlipayClient(String serverUrl, String appId, String privateKey, String format,
                               String charset, String alipayPublicKey, String signType) {
        .....
    }
	// 6
    public DefaultAlipayClient(String serverUrl, String appId, String privateKey, String format,
                               String charset, String alipayPublicKey, String signType,
                               String proxyHost, int proxyPort) {
        .....
    }
	// 7
    public DefaultAlipayClient(String serverUrl, String appId, String privateKey, String format,
                               String charset, String alipayPublicKey, String signType,
                               String encryptKey, String encryptType) {
        .....
    }
	// 8
    public DefaultAlipayClient(CertAlipayRequest certAlipayRequest) throws AlipayApiException {
        ....
    }
}

第二步 创建 Request ,其实就是设置一些不同的端请求的一些私有参数的配置

  • com.alipay.api.request.AlipayTradeWapPayRequest
public class AlipayTradeWapPayRequest implements AlipayRequest<AlipayTradeWapPayResponse> {
   private AlipayHashMap udfParams; // add user-defined text parameters
   private String apiVersion="1.0";
   /** 
   * 手机网站支付接口2.0
    */
   private String bizContent;
   private String terminalType;
   private String terminalInfo;   
   private String prodCode;
   private String notifyUrl;
   private String returnUrl;
   private boolean needEncrypt=false;
   private AlipayObject bizModel=null;
   ......
}

第三步 创建 请求调用执行 ,通过调用 DefaultAlipayClient 的父类 AlipayClient 的相应请求方法来执行请求,不同的request执行不同的方法

  • com.alipay.api.AlipayClient
    • 底层还是调用 java.net 包相应的HttpURLConnection构造连接,底层通过 socket通信 完成请求
public interface AlipayClient {

    /**
     * @param request 请求request
     */
    <T extends AlipayResponse> T execute(AlipayRequest<T> request) throws AlipayApiException;

    /**
     * @param request 请求request
     */
    <T extends AlipayResponse> T execute(AlipayRequest<T> request,
                                         String authToken) throws AlipayApiException;

    /**
     * @param request
     * @param accessToken
     * @param appAuthToken
     */
    <T extends AlipayResponse> T execute(AlipayRequest<T> request, String accessToken,
                                         String appAuthToken) throws AlipayApiException;

    <T extends AlipayResponse> T execute(AlipayRequest<T> request, String accessToken,
                                         String appAuthToken, String targetAppId) throws AlipayApiException;

    /**
     * @param request
     */
    <T extends AlipayResponse> T pageExecute(AlipayRequest<T> request) throws AlipayApiException;

    /**
     * SDK客户端调用生成sdk字符串
     *
     * @param <T>
     * @param request
     * @return
     * @throws AlipayApiException
     */
    <T extends AlipayResponse> T sdkExecute(AlipayRequest<T> request) throws AlipayApiException;

    /**
     * @param request
     */
    <T extends AlipayResponse> T pageExecute(AlipayRequest<T> request,
                                             String method) throws AlipayApiException;

    /**
     * 移动客户端同步结果返回解析的参考工具方法
     * @param result       移动客户端SDK同步返回的结果map,一般包含resultStatus,result和memo三个key
     * @param requsetClazz 接口请求request类,如App支付传入 AlipayTradeAppPayRequest.class
     */
    <TR extends AlipayResponse, T extends AlipayRequest<TR>> TR parseAppSyncResult(Map<String, String> result,
                                                                                   Class<T> requsetClazz) throws AlipayApiException;

    /**
     * 批量调用
     *
     * @param request
     */
    BatchAlipayResponse execute(BatchAlipayRequest request) throws AlipayApiException;

    /**
     * 证书类型调用
     * @param request
     */
    <T extends AlipayResponse> T certificateExecute(AlipayRequest<T> request) throws AlipayApiException;

    /**
     * @param request
     */
    <T extends AlipayResponse> T certificateExecute(AlipayRequest<T> request,
                                                    String authToken) throws AlipayApiException;

    /**
     * @param request
     * @param accessToken
     * @param appAuthToken
     */
    <T extends AlipayResponse> T certificateExecute(AlipayRequest<T> request, String accessToken,
                                                    String appAuthToken) throws AlipayApiException;

    <T extends AlipayResponse> T certificateExecute(AlipayRequest<T> request, String accessToken,
                                                    String appAuthToken, String targetAppId) throws AlipayApiException;
}

总结

在学习的过程中,总的来说,官网说明的很详细了,也有社区来提问

在Java中集成支付宝支付其实很简单,涉及的代码就三步:(前期配置太多,但是配置好了就ok了)

  • 创建 Client 。 一般就创建 DefaultAlipayClient 即可
  • 创建Reqeust 。根据不同的端/不同的加签方式会有所不同,常用的:
    • 普通 公钥证书 模式加签 CertAlipayRequest
    • 电脑网页端 AlipayTradePagePayRequest
    • 手机网页版 AlipayTradeWapPayRequest
    • 批量请求 BatchAlipayRequest
  • 调用请求方法,发送请求

在实际开发中,基本上会编写一个 AlipayConfig,用数据库的表 / properties 的方式来动态修改该Config,不同的端/请求方式,编写一个统一的Util就完事了

在学习时,也去看了一下底层实现,发现具体其底层还是 Socket通信,也不稀奇,只是其帮忙封装好了,我们直接傻瓜式调用即可

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值