项目开发之支付宝支付

本文介绍使用Spring Boot开发支付宝测试环境下的扫码支付接口。先在支付宝开发平台注册账号、配置沙箱环境,生成密钥。开发接口时,注意价格等敏感数据从后台获取。支付完成后,通过异步通知判断支付结果。同时,还提到了支付幂等性问题及解决办法。

开发支付宝支付接口

使用springboot做一个简单的支付宝扫码支付功能,用的是测试环境下的沙箱环境
首先需要登录支付宝开发平台注册一个自己的账号,并打开沙箱环境配置一些数据
在这里插入图片描述

在这里插入图片描述
这里进行配置的时候需要进行登录,登录成功后才能继续配置

配置密钥
这里需要下载一个支付宝的插件RSA签名验签工具
生成密钥
不需要改其他的配置,直接点击生成就行,然后复制公钥到开发平台上添加上去
在这里插入图片描述

在这里插入图片描述配置这些数据方便以后拿取
准备工作结束,之后就可以开始做项目并开发接口了

这是支付接口

/**
 *@Author XXX
 *@Description //TODO Administrator
 *@Date 17:05 2019/5/28
 *@Param []
 *@return java.lang.String
 **/
@RequestMapping("dopay")
    public void dapay(HttpServletRequest httpRequest, HttpServletResponse httpResponse,String goodsId,int countNum) {

        //根据商品id获取到商品的详细信息

        //根据商品的价格和订购的总数算出总价

        //在订单表中插入一条数据,状态为未支付
        String oid = UUID.randomUUID().toString();


        AlipayClient alipayClient = new DefaultAlipayClient(alipayUrl,
                alipayUtils.APP_ID, alipayUtils.APP_PRIVATE_KEY, "json", "UTF-8", alipayUtils.ALIPAY_PUBLIC_KEY, "RSA2"); //获得初始化的AlipayClient
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();//创建API对应的request
        //支付完成后,浏览器跳转的地址
        alipayRequest.setReturnUrl("http://www.xuyuanzeng.cn/demo_vuetest/alipay/return.html");
        //支付完成后,通知后台是否完成本次支付
        alipayRequest.setNotifyUrl("http://www.xuyuanzeng.cn/demo_vuetest/alipay/alipaynotifyUrl");//在公共参数中设置回跳和通知地址

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("out_trade_no",oid);
        jsonObject.put("product_code","FAST_INSTANT_TRADE_PAY");
        jsonObject.put("total_amount",0.1);
        jsonObject.put("subject","我是商品名称");
//        alipayRequest.setBizContent("{" +
//                "    \"out_trade_no\":\"20150320010101001\"," +//商户订单id
//                "    \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," +//销售产品码。
//                "    \"total_amount\":88.88," +//订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
//                "    \"subject\":\"Iphone6 16G\"," +//订单标题
//                "    \"body\":\"Iphone6 16G\"," +//商品描述
//                "    \"passback_params\":\"merchantBizType%3d3C%26merchantBizNo%3d2016010101111\"," +
//                "    \"extend_params\":{" +
//                "    \"sys_service_provider_id\":\"2088511833207846\"" +
//                "    }"+
//                "  }");//填充业务参数
        alipayRequest.setBizContent(jsonObject.toString());
        String form="";
        try {
            form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        try {
            httpResponse.setContentType("text/html;charset=UTF-8");
            httpResponse.getWriter().write(form);//直接将完整的表单html输出到页面
            httpResponse.getWriter().flush();
            httpResponse.getWriter().close();
        }catch (Exception e){
            //写进日志记录

            e.printStackTrace();
        }

    }

这是支付宝开发文档中代码,我只是把它拿到业务场景中来细致化了一点,还有一些更加细腻的判断,日后根据需求自己添加,这里要说的,这段代码中,首先接受的参数有:1.商品ID 2.购买的数量,需要注意的是,不能够将商品的价格也当做参数传递过来,这是为了防止某些黑客抓取到具体的价格参数后,进行修改,来达到一些不法的目的,以后做的所有的支付方面的东西,价格一类敏感的数据都只能去后台获取,而不能从前台传递

这里简单说下需要给支付宝传递的参数:

参数设置完成后,当用户点击支付的时候,后台调用这个dopay方法去请求支付宝的服务端并将一些具体的商品信息携带上,并生成html信息发送给前台,让用户确认输入支付密码,支付密码确认以后,返回后台系统,这时候支付宝就会通过我们之前提到的alipaynotifyUrl设置好的地址返回给我们支付消息。
下面是接受通知的代码

/**
 *@Author XXX
 *@Description //TODO Administrator
 *@Date 21:36 2019/5/28
 *@Param [request]
 *@return java.lang.String
 * 支付宝回调时返回的参数,需要将其转化成json数据
 **/
@RequestMapping("alipaynotifyUrl")
public String alipaynotifyUrl(HttpServletRequest request){
    try {
        InputStream inStream = request.getInputStream();
        //把消息流转换成文本类型
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        outSteam.close();
        String result = new String(outSteam.toByteArray(), "UTF-8");
        System.out.println("result==="+result);

        JSONObject jsonObject = JSONObject.fromObject(result);
        JSONObject alipayResponse = (JSONObject) jsonObject.get("alipay_trade_page_pay_response");
        String trade_no = (String) alipayResponse.get("trade_no");//订单ID
        String total_amount = (String) alipayResponse.get("total_amount");//价格
        String msg = (String) alipayResponse.get("msg");//返回的状态

        //判断返回状态是否成功

        //拿着订单号往数据库查询,查询回来订单表数据后,比较价格是否一致,如果一致,说明支付没有问题

        //更新订单表的状态,更改为已支付,更改物流表状态,往物流表插入数据,开始发货
    }catch (Exception e){

    }
    return "";
}

判断返回来的msg是否==success,如果相同证明支付成功,则进行下面的判断,判断支付金额与数据库中的数据是否相同,相同的话,更新订单表状态,并开始发货,并且返回给前台提示操作是否完成。到这里支付基本完成,不过在验证这里还需要注意的一点是,要考虑到支付的一些并发情况,如支付的幂等性。

什么是支付的幂等性?

1)用户多次请求造成出现多个订单
2)支付完成后,被拦截或网络不好,造成收不到回调通知或是收到了回调通知,但是这个回调通知的金额和支付信息不匹配,说明数据有问题

如何保证支付的幂等性呢,有很多的办法,这里采用一种很简单的方法:

(1)提交时的幂等性,做个token拦截,防止用户重复提交
①cookie和redis中放一个都放一个token
②提交到后台后,获取cookie中的token,比较redis当中的token,把token删除掉,防止用户重复提交
(2)支付宝通知时防止的幂等性
①根据支付宝自己提供的校验,把返回来的参数进行校验
具体实施步骤:采用异步通知的办法

Map<String, String> paramsMap = ... //将异步通知中收到的所有参数都存放到map中
boolean signVerified = AlipaySignature.rsaCheckV1(paramsMap, ALIPAY_PUBLIC_KEY, CHARSET, SIGN_TYPE) //调用SDK验证签名
if(signVerfied){
    // TODO 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure
}else{
    // TODO 验签失败则记录异常日志,并在response中返回failure.


异步验证的流程(开发文档上介绍的很详细,具体还看自己的需求)

商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),4、验证app_id是否为该商户本身。上述1、2、3、4有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。注意:状态TRADE_SUCCESS的通知触发条件是商户签约的产品支持退款功能的前提下,买家付款成功;交易状态TRADE_FINISHED的通知触发条件是商户签约的产品不支持退款功能的前提下,买家付款成功;或者,商户签约的产品支持退款功能的前提下,交易已经成功并且已经超过可退款期限。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值