前言
这段时间帮助一个电商平台做了手机支付宝支付的模块,过程中遇到了一些坑,也收获了一些经验,在此做一下记录,也希望能帮助到后来的人。
需求
我们的需求比较常规,就是下单的时候选择支付宝支付,支付给卖家即可。接入支付宝支付模块后应尽量让卖家操作简单,毕竟卖家不一定有开发能力,也不一定很懂电脑。为此,我们选择服务商授权第三方应用模式,卖家只需在蚂蚁金服务开放平台注册手机网站支付应用,然后在平台一键授权即可,非常简单。
支付宝手机支付
准备工作
首先,我们先看支付宝官方的文档以及官方demo,可以说基本所有问题都可以从文档里找到答案,实在找不到答案可以去问蚂蚁金服的人工客服。支付宝手机支付官方文档地址:https://docs.open.alipay.com/203/105288/ ,在文档里可以找到官方demo。我们先按照支付宝手机支付的官方文档完成支付宝支付功能。
可以使用沙箱账号,也可以直接使用真实账号,我们这里就不介绍沙箱账号配置方法,使用真实账号。需要提醒的是,沙箱账号有个坑:配置沙箱卖家账号之后,支付也只能使用沙箱买家账号,对于手机端,要下载沙箱版的支付宝app,登陆沙箱账号,而沙箱账号在我们用的支付宝app上是无法登陆的!
在蚂蚁金服开放平台使用支付宝账号密码登录,第一次登陆的时候要选择身份,可以选择系统服务商(ISV),也可以选择自主开发者,在后期可以扩展身份,这里选择系统服务商好了,对于注册应用似乎没什么影响。然后就需要注册应用,可以参考文档:https://docs.open.alipay.com/203/107084/ 即可,这里有一个授权回调地址,这是后来授权给第三方应用需要配置的项,现在可以不填或者随便填一个地址,支付宝网关是图里固定的一个url(对于沙箱是另一个url),支付宝公钥和应用公钥、应用私钥都可查看文档在本地生成,这些在代码里也要用到。
应用注册好,通过审核、上线之后,需要添加手机网站支付的功能,点击应用详情,进入应用详情页,点击添加功能,输入一系列必要的资料,等审核通过即可(对于个人账号貌似需要公司营业执照,公司支付宝账号似乎不需要,当时做的太快忘记了。。)。
正式写代码
准备工作做好之后,就要开始写代码。首先,因为在实现过程中需要调用支付宝的很多接口,我们需要导入alipay的jar包,在pom文件里添加依赖:
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.1.0</version>
</dependency>
然后,在application.yml文件里添加相关基本配置:
pay:
alipay:
gatewayUrl: https://openapi.alipay.com/gateway.do
appid: 申请的应用id
appPrivateKey: 生成的应用私钥
alipayPublicKey: 支付宝公钥
returnUrl: https://xxxxxx/alipay/returnurl
notifyUrl: https://xxxxxx/alipay/notifyurl
charset: UTF-8
format: json
signtype: RSA2
returnUrl和notifyUrl是两个接口地址,都需要是线上可访问的,因为是支付宝来调用这两个接口。
接下来新建AlipayController.java文件,在这个controller里写有关支付宝支付的所有接口,必要的接口包括创建支付宝订单接口、异步回调接口、同步回调接口和退款接口,其他一些辅助接口(比如交易查询接口、下载对账单接口等)可根据自己项目需要再加上。
创建支付宝订单接口
创建支付宝订单接口包括两部分,一部分是和自己业务相关的,根据自己的订单获取支付金额、支付信息等,另一部分是调用alipay-sdk中的相关接口,由支付宝来处理支付信息,跳到支付宝支付界面进行支付。代码如下:
/**
* 生成支付宝支付订单接口,传入参数为多个订单orderNo的数组,可多个订单一起支付
* @param orderNoDTO
* @return
* @throws ServletException
* @throws IOException
*/
@PostMapping(value = "/createAlipayOrder")
public Object createAlipayOrder(@RequestBody OrderNoDTO orderNoDTO) throws ServletException, IOException{
Map<String, Object> map = new HashMap<>();
if(orderNoDTO.getOrderNo().size()<=0){
return ResponseJsonUtil.returnJson(map, BusinessConstants.GET_ORDER_LIST_ERROR, PsiInfo.ERROR.code);
}//判断orderNoDTO里是否有订单,没有订单报错
String firstOrderNo=orderNoDTO.getOrderNo().get(0);
Long sellerId=orderService.selectSellerIdByOrderNo(firstOrderNo);//所有订单卖家相同,因此根据第一个订单编号即可获取卖家id
double money=0.0;//支付金额初始值
String subject="";//支付描述信息
AlipayOrder alipayOrder=new AlipayOrder();//创建支付订单
alipayOrder.setOut_trade_no(CreateOrderNo.createOrderNo("Alipay"));//创建由Alipay打头的支付订单号,多个订单号对应一个支付订单号
for(String orderNo:orderNoDTO.getOrderNo()){
try{
Order order=orderService.getSingleOrderByOrderNo(orderNo);
order.setAlipay_out_trade_no(alipayOrder.getOut_trade_no());
orderService.updateOrderByExample(order);//获取原销售订单,将支付订单号传入并更新
List<OrderEx> orderExlist=orderService.getOrderDetailByOrderNo(orderNo);//获取原支付订单包含的物品信息
for(OrderEx orderEx:orderExlist){
subject+=orderEx.getGoodsName();//支付订单描述由所有物品信息组成
logger.info("subject:{}",subject);
}
money+=order.getMoney().doubleValue();//支付订单金额等于原订单金额之和
logger.info("money:{}",money);
}catch (Exception e){
}
}
//以上是与自己业务相关的代码,可根据自己业务来,最重要的是要生成支付订单号,获取支付金额和支付描述信息
alipayOrder.setStatus((byte)0);//0代表创建订单等待付款
alipayOrder.setTotal_amount(new BigDecimal(Double.toString(money)));//支付订单金额
alipayOrder.setReceipt_amount(new BigDecimal(Double.toString(0.00)));//实收金额
alipayOrder.setInvoice_amount(new BigDecimal(Double.toString(0.00)));//开票金额
alipayOrder.setBuyerpay_amount(new BigDecimal(Double.toString(0.00)));//买家付款金额
alipayOrder.setRefund_fee(new BigDecimal(Double.toString(0.00)));//退款金额
if(orderService.createAlipayOrder(alipayOrder)<=0) {
return ResponseJsonUtil.returnJson(map, BusinessConstants.AliPay_ORDER_CREATE_FAIL, PsiInfo.ERROR.code);
}//创建支付订单,插入数据库
try{
//String alipayToken=storeService.getAlipayTokenByMemberId(sellerId);
//if(alipayToken==null){
//return ResponseJsonUtil.returnJson(map, BusinessConstants.AliPay_TOKEN_NULL, PsiInfo.ERROR.code);
// }
//以上注释是和授权有关代码,以后再提,目前对于支付并无影响
AlipayClient alipayClient=new DefaultAlipayClient(aliPayConfig.getGatewayUrl(),aliPayConfig.getAppid(),aliPayConfig.getAppPrivateKey(),"json",aliPayConfig.getCharset(),aliPayConfig.getAlipayPublicKey(),aliPayConfig.getSigntype());//初始化AlipayClient
AlipayTradeWapPayRequest alipayRequest=new AlipayTradeWapPayRequest();//初始化AlipayTradeWapPayRequest,注意是手机网站支付
AlipayTradeWapPayModel model=new AlipayTradeWapPayModel();
model.setOutTradeNo(alipayOrder.getOut_trade_no());
model.setSubject<