文章目录
- 前言
- 官方文档以及说明
- 1、申请沙箱
- 2、进入沙箱获取对应的关键信息
- 3、拿到系统生成的公钥和密钥
- 注意事项
- 创建springboot项目
- 1、引入依赖
- 2、配置连接参数
- 3、创建配置类,用于接收这些参数
- 4、中间类的定义(订单类)
- 5、编写测试接口
- 场景一、pc端请求后端后,生成支付宝的特制页面(AlipayTradePagePayRequest)
- 场景二、前端请求后端,只返回对应的二维码地址(AlipayTradePrecreateRequest)
前言
最近项目中需要对接支付模块,需要考虑到微信支付与支付宝支付的实现。
由于微信支付的还在审核中,先预研demo做一个支付宝支付码获取的实现。
官方文档以及说明
本次开发环境中编写demo实现,采用的是支付宝的沙箱
方式,后续上线会重新申请正式的appid等信息。
支付宝开发平台链接:https://open.alipay.com/
1、申请沙箱
进入支付宝的开发平台,用支付宝登录后,在控制台面板中找到沙箱
,并创建第一个沙箱。
https://open.alipay.com/develop/manage
2、进入沙箱获取对应的关键信息
对于像授权回调地址
、应用网关地址
这些暂时不设置。
3、拿到系统生成的公钥和密钥
这里会有应用公钥
、支付宝公钥
和应用私钥
。但这里通过个人实践,只需要支付宝公钥
和应用私钥
。
应用公钥
在某些特定的场景中并不会生效还会出现各种奇怪的报错。
注意事项
沙箱
并不是所有的操作都能够在其中进行开发操作,详情参考官方文档说明。
https://opendocs.alipay.com/common/097jyi?pathHash=9fcbe0d0&highlight_field=%E6%B2%99%E7%AE%B1%E7%8E%AF%E5%A2%83
创建springboot项目
1、引入依赖
选用的是springboot 2.x
的版本,并且引用的依赖在官方文档中有版本说明。
<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.34.47.ALL</version>
</dependency><dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-easysdk</artifactId><version>2.0.0</version>
</dependency>
参考官方文档依赖版本规定:
https://opendocs.alipay.com/common/02n6z6?pathHash=f5e2a056
其中,针对通用版
的版本要求,官方文档中有做说明:
https://opendocs.alipay.com/common/02kkv2?pathHash=358ff034
2、配置连接参数
在src/main/resources
中新建一个application.yml
文件,如果是nacos项目,可以在对应的配置中心中新增配置项。
# 支付宝支付
alipay:# 应用ID,标识你的应用appId: # 应用私钥,用于签名请求appPrivateKey:# 应用公钥,用于验证支付宝的响应#alipayPublicKey: 沙箱页面中的应用公钥# 支付宝公钥(推荐使用这个)alipayPublicKey: 支付宝公钥# 支付通知的回调地址,支付宝会在支付完成后通知这个地址notifyUrl: 支付成功后的回调地址,必须要求公网能够访问# 页面跳转地址,支付完成后跳转到此URLreturnUrl: 场景一中登录成功后的重定向页面# 签名类型,通常为RSA2signType: RSA2# 字符编码,通常为utf-8charset: utf-8# 支付宝网关地址,用于发送请求gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do
3、创建配置类,用于接收这些参数
package cn.alipay.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** 支付宝 支付参数配置类*/
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AlipayProperties {/*** APPID*/private String appId;/*** 应用私钥,就是工具生成的应用私钥*/public String appPrivateKey;/*** 支付宝公钥,对应APPID下的支付宝公钥*/public String alipayPublicKey;/*** 支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息*/public String notifyUrl;/*** 同步通知,支付成功,一般跳转到成功页*/public String returnUrl;/*** 签名方式*/private String signType;/*** 字符编码格式*/private String charset;/*** 支付宝网关;https://openapi-sandbox.dl.alipaydev.com/gateway.do*/public String gatewayUrl;/*** 订单超时时间*/private String timeout = "5m";
}
新建配置类,获取对应的配置参数,并构建连接对象
package cn.alipay.config;import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradePayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.BusinessParams;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.domain.GoodsDetail;
import com.alipay.api.domain.SettleDetailInfo;
import com.alipay.api.domain.SettleInfo;
import com.alipay.api.internal.util.WebUtils;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradePayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;/*** 支付宝支付 模板*/
@Slf4j
@Data
@Component
public class AliPayTemplate {@Autowiredprivate AlipayProperties alipayProperties;private AlipayClient alipayClient;@PostConstructpublic void init() {log.info("APPID:" + alipayProperties.getAppId());log.info("应用私钥:" + alipayProperties.getAppPrivateKey());log.info("支付宝公钥:" + alipayProperties.getAlipayPublicKey());log.info("支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息:" + alipayProperties.getNotifyUrl());log.info("同步通知,支付成功,一般跳转到成功页:" + alipayProperties.getReturnUrl());log.info("签名方式:" + alipayProperties.getSignType());log.info("字符编码格式:" + alipayProperties.getCharset());log.info("订单超时时间:" + alipayProperties.getTimeout());log.info("支付宝网关:" + alipayProperties.getGatewayUrl());// 1. 根据支付宝的配置生成一个支付客户端alipayClient = new DefaultAlipayClient(alipayProperties.getGatewayUrl(),alipayProperties.getAppId(),alipayProperties.getAppPrivateKey(),"json",alipayProperties.getCharset(),alipayProperties.getAlipayPublicKey(),alipayProperties.getSignType());}
}
4、中间类的定义(订单类)
创建一个订单类,主要用于一些基本信息的传参处理。
package cn.alipay.config;import lombok.Data;import java.io.Serializable;
import java.util.Date;/*** 订单表*/
@Data
public class Order implements Serializable {/*** 订单Id*/private Long id;/*** 用户Id*/private Long userId;/*** 接口Id*/private Long interfaceInfoId;/*** 支付金额*/private Double money;/*** 支付方式*/private String paymentMethod;/*** 0 - 未支付 1 - 已支付*/private Integer status;/*** 创建时间*/private Date createTime;/*** 更新时间*/private Date updateTime;/*** 是否删除*/private Integer isDelete;private static final long serialVersionUID = 1L;
}
5、编写测试接口
场景一、pc端请求后端后,生成支付宝的特制页面(AlipayTradePagePayRequest)
在支付宝的PC端案例文档
中,有一个注意事项。
https://opendocs.alipay.com/open/00dn7o?pathHash=c1e36251
像这种传递订单信息至后台,后台调用支付宝的对应接口后,返回前端页面样式或者地址,前端再进行渲染实现。可以参照以下的方式。
定义接口
package cn.alipay.controller;import cn.alipay.config.AliPayTemplate;
import cn.alipay.config.Order;
import com.alipay.api.AlipayApiException;
import com.alipay.easysdk.factory.Factory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;/*** 阿里支付宝支付与回调接口*/
@Slf4j
@RestController
@RequestMapping("/alipay")
public class AliPayController {@Autowiredprivate AliPayTemplate aliPayTemplate;/*** 获取支付宝* post 请求 生成 frame 页面* get 请求生成 页面url* @param id* @return* @throws AlipayApiException*/@GetMapping(value = "/pay", produces = MimeTypeUtils.TEXT_HTML_VALUE)@ResponseBodypublic String pay(@RequestParam long id) throws AlipayApiException {// 创建订单对象并设置属性Order order = createOrder(id);// 调用支付宝支付模板进行支付return aliPayTemplate.pay(order);}/*** 伪造订单数据* @param id* @return*/private Order createOrder(long id) {Order order = new Order();order.setId(id); order.setUserId(1111111L); order.setInterfaceInfoId(294389472934L); order.setMoney(1000.0); order.setPaymentMethod("支付宝"); return order;}
}
定义请求逻辑代码
package cn.alipay.config;import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradePayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.BusinessParams;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.domain.GoodsDetail;
import com.alipay.api.domain.SettleDetailInfo;
import com.alipay.api.domain.SettleInfo;
import com.alipay.api.internal.util.WebUtils;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradePayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;/*** 支付宝支付 模板*/
@Slf4j
@Data
@Component
public class AliPayTemplate {@Autowiredprivate AlipayProperties alipayProperties;private AlipayClient alipayClient;@PostConstructpublic void init() {log.info("APPID:" + alipayProperties.getAppId());log.info("应用私钥:" + alipayProperties.getAppPrivateKey());log.info("支付宝公钥:" + alipayProperties.getAlipayPublicKey());log.info("支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息:" + alipayProperties.getNotifyUrl());log.info("同步通知,支付成功,一般跳转到成功页:" + alipayProperties.getReturnUrl());log.info("签名方式:" + alipayProperties.getSignType());log.info("字符编码格式:" + alipayProperties.getCharset());log.info("订单超时时间:" + alipayProperties.getTimeout());log.info("支付宝网关:" + alipayProperties.getGatewayUrl());// 1. 根据支付宝的配置生成一个支付客户端alipayClient = new DefaultAlipayClient(alipayProperties.getGatewayUrl(),alipayProperties.getAppId(),alipayProperties.getAppPrivateKey(),"json",alipayProperties.getCharset(),alipayProperties.getAlipayPublicKey(),alipayProperties.getSignType());}/*** 调用支付接口* @param order* @return* @throws AlipayApiException*/public String pay(Order order) throws AlipayApiException {//2、创建一个支付请求,并设置请求参数AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();alipayRequest.setReturnUrl(alipayProperties.getReturnUrl());alipayRequest.setNotifyUrl(alipayProperties.getNotifyUrl());Long id = order.getId();Long interfaceInfoId = order.getInterfaceInfoId();Double money = order.getMoney();String paymentMethod = order.getPaymentMethod();// 设置业务内容,包含必要的支付参数AlipayTradePagePayModel pagePayModel = new AlipayTradePagePayModel();pagePayModel.setOutTradeNo(String.valueOf(id));pagePayModel.setTotalAmount(String.valueOf(money));pagePayModel.setSubject(String.valueOf(interfaceInfoId));pagePayModel.setBody(paymentMethod);pagePayModel.setTimeoutExpress(alipayProperties.getTimeout());// 电脑支付场景下仅支持FAST_INSTANT_TRADE_PAYpagePayModel.setProductCode("FAST_INSTANT_TRADE_PAY");alipayRequest.setBizModel(pagePayModel);// post 请求返回 frame 前端样式AlipayTradePagePayResponse response = alipayClient.pageExecute(alipayRequest, "POST");// get 请求返回一个页面地址urlAlipayTradePagePayResponse response2 = alipayClient.pageExecute(alipayRequest, "GET");String result = response.getBody();//返回支付宝响应的结果return result;}
}
启动服务,请求后的效果如下:
localhost:8080/alipay/pay?id=123456
post 请求生成的样式如下所示:
<form name="punchout_form" method="post" action="会有对应的信息"><input type="hidden" name="biz_content" value="{"body":"支付宝","out_trade_no":"125477","product_code":"FAST_INSTANT_TRADE_PAY","subject":"294389472934","timeout_express":"5m","total_amount":"1000.0"}"><input type="submit" value="立即支付" style="display:none" ></form><script>document.forms[0].submit();</script>
如果是GET
请求,则只会是上面action
的地址。
场景二、前端请求后端,只返回对应的二维码地址(AlipayTradePrecreateRequest)
参照官方文档中的案例实现
https://opendocs.alipay.com/open/8ad49e4a_alipay.trade.precreate?scene=2ae8516856f24a5592194d237f3f235d&pathHash=d18bff53
编写对应的接口和实现类
@GetMapping(value = "/pay3")
@ResponseBody
public String pay3(@RequestParam long id) throws AlipayApiException {// 创建订单对象并设置属性Order order = createOrder(id);// 调用支付宝支付模板进行支付return aliPayTemplate.pay3(order);
}
package cn.alipay.config;import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradePayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.BusinessParams;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.domain.GoodsDetail;
import com.alipay.api.domain.SettleDetailInfo;
import com.alipay.api.domain.SettleInfo;
import com.alipay.api.internal.util.WebUtils;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradePayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;/*** 支付宝支付 模板*/
@Slf4j
@Data
@Component
public class AliPayTemplate {@Autowiredprivate AlipayProperties alipayProperties;private AlipayClient alipayClient;@PostConstructpublic void init() {log.info("APPID:" + alipayProperties.getAppId());log.info("应用私钥:" + alipayProperties.getAppPrivateKey());log.info("支付宝公钥:" + alipayProperties.getAlipayPublicKey());log.info("支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息:" + alipayProperties.getNotifyUrl());log.info("同步通知,支付成功,一般跳转到成功页:" + alipayProperties.getReturnUrl());log.info("签名方式:" + alipayProperties.getSignType());log.info("字符编码格式:" + alipayProperties.getCharset());log.info("订单超时时间:" + alipayProperties.getTimeout());log.info("支付宝网关:" + alipayProperties.getGatewayUrl());// 1. 根据支付宝的配置生成一个支付客户端alipayClient = new DefaultAlipayClient(alipayProperties.getGatewayUrl(),alipayProperties.getAppId(),alipayProperties.getAppPrivateKey(),"json",alipayProperties.getCharset(),alipayProperties.getAlipayPublicKey(),alipayProperties.getSignType());}public String pay3(Order order) throws AlipayApiException {AlipayTradePrecreateRequest alipayRequest = new AlipayTradePrecreateRequest();// 强制关闭 ssl 证书校验WebUtils.setNeedCheckServerTrusted(false);alipayRequest.setNotifyUrl(alipayProperties.getNotifyUrl());JSONObject jsonObject = new JSONObject();jsonObject.put("out_trade_no",order.getId());// 商户订单号jsonObject.put("total_amount",order.getMoney());// 商品价格jsonObject.put("subject","这只是个商品标题");// 商品标题jsonObject.put("store_id","香蕉集团");//组织或公司名
// jsonObject.put("timeout_express","5m");// 订单有效时间alipayRequest.setBizContent(jsonObject.toString());AlipayTradePrecreateResponse response = alipayClient.execute(alipayRequest);System.out.println("创建订单结果:"+response.getBody());System.out.println("订单编号是"+response.getOutTradeNo());String qrCode = response.getQrCode();
// AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();return qrCode;}
}
请求后会得到一个支付的地址,使用ZXing
框架,将其转换为二维码。