支付宝小程序对接流程和工具类

支付宝小程序流程简介图

在这里插入图片描述

开发步骤

  1. 创建小程序: 登入支付宝开发平台,创建支付宝小程序;
  2. 配置公钥密钥: 下载支付宝提供的支付宝开发平台开发助手生成“商户应用公钥”和“商户应用私钥”,然后将“商户应用公钥”去支付宝开发平台换取“支付宝公钥”;
  3. . 功能列表添加相关功能: 登入支付宝开发平台,进入小程序,在开发管理的功能列表中添加相关功能;
  4. 开始开发小程序: 根据小程序的需求开发小程序接口;

小程序授权

  1. 第一步:URL拼接与scope详解:
url拼接规则:https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=APPID&scope=SCOPE&redirect_uri=ENCODED_URL
  1. 第二步:获取auth_code:
http或https打头的授权回调地址? app_id=2016032301002387 &scope=auth_user&auth_code=10e20498fe5d42f18427d893fc06WX59
  1. 第三步:auth_code换取access_token与user_id:
package com.xzb.base.util.AliPay;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayOpenAppQrcodeCreateRequest;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.response.AlipayOpenAppQrcodeCreateResponse;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 支付宝认证接口
 */
public class AliAuthUtil {

    private static String serverUrl = "https://openapi.alipay.com/gateway.do";

    private static final Logger logger = LoggerFactory.getLogger(AliAuthUtil.class);


    public static AlipayClient getAlipayClient(String appId, String privateKey, String publicKey) {
        return new DefaultAlipayClient(serverUrl, appId, privateKey, "json", "utf-8", publicKey, "RSA2");
    }


    // 服务端获取access_token、user_id
    public static String getAccessToken(String authCode, String appId, String privateKey,
                                                                String publicKey){

        try {
            AlipayClient alipayClient = getAlipayClient(appId, privateKey, publicKey);
            AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
            request.setGrantType("authorization_code");
            request.setCode(authCode);
            logger.warn("服务端获取access_token、user_id请求参数:{}",JSONObject.toJSONString(request));
            AlipaySystemOauthTokenResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                logger.warn("服务端获取access_token、user_id调用成功,返回参数:{}",response.getBody());
                return response.getBody();
            } else {
                logger.error("服务端获取access_token、user_id调用失败,appid:{}",appId);
            }
        } catch (AlipayApiException e) {
            logger.error("服务端获取access_token、user_id调用异常,appid:{}",appId);
            e.printStackTrace();
        }
        return null;
    }
}

  • 至此,用户信息授权流程已结束,如果只想拿到user_id(支付宝用户唯一标识符),则无需看下一步。

说明

  1. 用户授权auth_code: auth_code一次有效,auth_code有效期为3分钟到24小时(开放平台规则会根据具体的业务场景动态调整auth_code的有效期,但是不会低于3分钟,同时也不会超过24小时),超过有效期的auth_code即使未使用也将无法使用 ,用户的每次授权动作都会生成一个新的auth_code。

小程序二维码

  /**
     * 小程序二维码
     * @param appId
     * @param privateKey 私钥
     * @param publicKey  公钥
     * @param urlParam  小程序中能访问到的页面路径。
     * @param queryParam 小程序的启动参数,打开小程序的query,在小程序onLaunch的方法中获取。
     * @param describe 对应的二维码描述。
     */
    public static String create(String appId, String privateKey, String publicKey,String urlParam,String queryParam,String describe) {
        try {
            AlipayClient alipayClient = AliAuthUtil.getAlipayClient(appId, privateKey, publicKey);
            AlipayOpenAppQrcodeCreateRequest request = new AlipayOpenAppQrcodeCreateRequest();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("url_param",urlParam);
            jsonObject.put("query_param",queryParam);
            jsonObject.put("describe",describe);
            request.setBizContent(jsonObject.toJSONString());
            logger.warn("获取小程序二维码请求参数:{}",JSONObject.toJSONString(request));
            AlipayOpenAppQrcodeCreateResponse response = alipayClient.execute(request);
            if(response.isSuccess()){
                logger.warn("调用支付宝小程序二维码成功,返回参数{}",response.getBody());
                return response.getBody();
            } else {
                logger.error("调用支付宝小程序二维码失败,启动参数:{}",queryParam);
            }
        } catch (AlipayApiException e) {
            logger.error("调用支付宝小程序二维码异常,启动参数:{}",queryParam);
            e.printStackTrace();
        }
        return null;
    }

资金冻结

/**
     * 线上资金授权冻结
     *
     * @param appId        appid
     * @param privateKey   秘钥
     * @param publicKey    公钥
     * @param orderNo      订单号
     * @param totalAmount  冻结金额
     * @param outStoreCode 商户的门店编号
     * @param orderName    订单名称
     * @param notify_url   异步回调通知地址
     * @param category   租赁行业的类型(如:充电宝,手机....)
     * @param serviceId  信用场景下必传,具体值需要联系芝麻客服
     * @return
     * @throws AlipayApiException
     */
    public static String frozen(String appId, String privateKey, String publicKey, String orderNo,
                                String totalAmount, String outStoreCode, String orderName, String notify_url,
                                String payeeUserId, String payeeLogonId,String outRequestNo,String category,String serviceId) throws AlipayApiException {

        try {
            AlipayClient alipayClient = AliAuthUtil.getAlipayClient(appId, privateKey, publicKey);
            AlipayFundAuthOrderAppFreezeRequest request = new AlipayFundAuthOrderAppFreezeRequest();

            AlipayFundAuthOrderAppFreezeModel model = new AlipayFundAuthOrderAppFreezeModel();
            model.setOrderTitle("租赁商城-商品租赁押金冻结");
            model.setOutOrderNo(orderNo);//实际订单号
            model.setPayTimeout("31m");//订单过期时间
            model.setOutRequestNo(outRequestNo);//替换为实际请求单号,保证每次请求都是唯一的
            //payee_user_id(商户PID),payee_logon_id(商户登录ID)不能同时为空;
            model.setPayeeUserId(payeeUserId);
            model.setPayeeLogonId(payeeLogonId);
            model.setProductCode("PRE_AUTH_ONLINE");//PRE_AUTH_ONLINE为固定值,不要替换
            model.setAmount(totalAmount);
            //如果是信用授权 则下面注释的必须传
            Map<String, String> extraParam = new HashMap<>();
            //category为业务分类  地址:https://docs.open.alipay.com/10719
            extraParam.put("category", category);
             extraParam.put("serviceId", serviceId);
            extraParam.put("outStoreCode", outStoreCode);
            extraParam.put("outStoreAlias", orderName);
            model.setExtraParam(JSON.toJSONString(extraParam));
            request.setBizModel(model);
            request.setNotifyUrl(notify_url);//异步通知地址,必填,该接口只通过该参数进行异步通知
            logger.info("线上资金冻结请求参数:{}",JSONObject.toJSONString(request));
            AlipayFundAuthOrderAppFreezeResponse response = alipayClient.sdkExecute(request);//注意这里是sdkExecute,可以获取签名参数
            if (response.isSuccess()) {
                logger.info("线上资金授权冻结调用成功,返回参数: {}" + response.getBody());//签名后的参数,直接入参到
                return response.getBody();
            }else {
                logger.info("线上资金授权冻结调用失败,orderNo:{}",orderNo);
            }
        } catch (AlipayApiException e) {
            logger.info("线上资金授权冻结调用异常,orderNo:{}",orderNo);
            e.printStackTrace();
        }
        return null;
    }

资金解冻

/**
     * 资金授权解冻
     *
     * @param appId        appid
     * @param privateKey   私钥
     * @param publicKey    公钥
     * @param notify_url   回调地址
     * @param authNo       支付宝授权成功订单号
     * @param outRequestNo 商户资金操作流水号
     * @param totalAmount  解冻金额
     * @return
     * @throws Exception
     */
    public static boolean fundAuthOrderUnFreeze(String appId, String privateKey, String publicKey, String notify_url, String authNo, String outRequestNo, String totalAmount) {
        try {
            AlipayClient alipayClient = AliAuthUtil.getAlipayClient(appId, privateKey, publicKey);
            AlipayFundAuthOrderUnfreezeRequest request = new AlipayFundAuthOrderUnfreezeRequest();

            AlipayFundAuthOrderUnfreezeModel model = new AlipayFundAuthOrderUnfreezeModel();
            model.setAuthNo(authNo); // 支付宝资金授权订单号,在授权冻结成功时返回需要入库保存
            model.setOutRequestNo(outRequestNo);//同一商户每次不同的资金操作请求,商户请求流水号不能重复,且与冻结流水号不同
            model.setAmount(totalAmount); // 本次操作解冻的金额,单位为:元(人民币),精确到小数点后两位
            model.setRemark("租赁商城-商品租赁押金解冻"); // 商户对本次解冻操作的附言描述,长度不超过100个字母或50个汉字

            //选填字段,信用授权订单,针对信用全免订单,传入该值完结信用订单,形成芝麻履约记录
            model.setExtraParam("{\"unfreezeBizInfo\":\"{\\\"bizComplete\\\":\\\"true\\\"}\"}");

            request.setBizModel(model);
            request.setNotifyUrl(notify_url);//异步通知地址,必填,该接口只通过该参数进行异步通知

            logger.warn("资金授权解冻请求参数: {}" + JSONObject.toJSONString(request));
            AlipayFundAuthOrderUnfreezeResponse response = alipayClient.execute(request);
            logger.warn("资金授权解冻返回参数: {}" + response.getBody());
            return response.isSuccess();
        } catch (AlipayApiException e) {
            logger.error("资金授权解冻调用异常,authNo:{}",authNo);
            e.printStackTrace();
        }
        return false;
    }

资金授权操作查询

/**
     * 资金授权操作查询
     * 功能:通过该接口可以查询单笔明细的详细信息,细分到每一次操作,如冻结、解冻。
     *
     * @param appId        appid
     * @param privateKey
     * @param publicKey
     * @param authNo
     * @param outOrderNo
     * @param operationId
     * @param outRequestNo
     * @return
     */
    public static String fundAuthQuery(String appId, String privateKey, String publicKey, String authNo, String outOrderNo, String operationId, String outRequestNo) {
        try {
            AlipayClient alipayClient = AliAuthUtil.getAlipayClient(appId, privateKey, publicKey);
            AlipayFundAuthOperationDetailQueryRequest request = new AlipayFundAuthOperationDetailQueryRequest();

            AlipayFundAuthOperationDetailQueryModel model = new AlipayFundAuthOperationDetailQueryModel();
            model.setAuthNo(authNo); // 支付宝资金授权订单号,在授权冻结成功时返回参数中获得
            model.setOutOrderNo(outOrderNo); //商户的授权资金订单号,与支付宝的授权资金订单号不能同时为空
            model.setOperationId(operationId); //支付宝的授权资金操作流水号,冻结成功同步返回
            model.setOutRequestNo(outRequestNo);//商户的授权资金操作流水号,与支付宝的授权资金操作流水号不能同时为空,该值为冻结或解冻是的outRequestNo
            request.setBizModel(model);
            logger.warn("资金授权操作查询请求参数:{}",JSONObject.toJSONString(request));
            AlipayFundAuthOperationDetailQueryResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                logger.warn("资金授权操作查询调用成功,返回参数:{}",response.getBody());
                return response.getBody();
            }else {
                logger.error("资金授权操作查询失败,outOrderNo:{}",outOrderNo);
            }
        } catch (AlipayApiException e) {
            logger.error("资金授权操作查询异常,outOrderNo:{}",outOrderNo);
            e.printStackTrace();
        }
        return null;
    }

授权转支付

 /**
     * 授权转支付
     *
     * @param appId
     * @param privateKey
     * @param publicKey
     * @param outTradeNo  商户订单号
     * @param authNo      支付宝授权成功订单号
     * @param sellerId    卖家支付宝账户pid
     * @param payUserId   预授权用户uid,通过预授权冻结接口返回的payer_user_id字段获取
     * @param storeId     与预授权的outStoreCode保持一致即可
     * @param totalAmount 结束支付金额
     * @param notifyUrl   回调地址
     * @return
     * @throws AlipayApiException
     */
    public static boolean tradePay(String appId, String privateKey, String publicKey, String outTradeNo,
                                   String authNo, String sellerId, String payUserId, String storeId, String totalAmount, String notifyUrl) {

        try {
            AlipayClient alipayClient = AliAuthUtil.getAlipayClient(appId, privateKey, publicKey);
            AlipayTradePayRequest request = new AlipayTradePayRequest();

            AlipayTradePayModel model = new AlipayTradePayModel();
            model.setOutTradeNo(outTradeNo); // 预授权转支付商户订单号,为新的商户交易流水号
            model.setProductCode("PRE_AUTH_ONLINE"); // 固定值PRE_AUTH_ONLINE
            model.setAuthNo(authNo); // 填写预授权冻结交易号
            model.setSubject("租赁支付"); // 解冻转支付标题,用于展示在支付宝账单中
            model.setTotalAmount(totalAmount); // 结算支付金额
            model.setSellerId(sellerId); // 填写卖家支付宝账户pid
            model.setBuyerId(payUserId); // 填写预授权用户uid,通过预授权冻结接口返回的payer_user_id字段获取
            model.setStoreId(storeId); // 填写实际交易发生的终端编号,与预授权的outStoreCode保持一致即可
            model.setBody("租赁支付"); // 可填写备注信息
            model.setAuthConfirmMode("COMPLETE");//传入COMPLETE时,用户剩余金额会自动解冻
            request.setBizModel(model);
            request.setNotifyUrl(notifyUrl);//异步通知地址,必填,该接口只通过该参数进行异步通知
            logger.warn("授权转支付请求参数:{}",JSONObject.toJSONString(request));
            AlipayTradePayResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                logger.warn("授权转支付调用成功,返回参数: {}" + response.getBody());
                return true;
            } else {
                logger.error("授权转支付调用失败, authNo:{}" + authNo);
            }
        } catch (AlipayApiException e) {
            logger.error("授权转支付调用异常, authNo:{}" + authNo);
            e.printStackTrace();
        }
        return false;
    }

统一收单交易创建接口(支付)

 /**
     * 中文名:(统一收单交易创建接口)
     * 接口英文名:alipay.trade.create
     * @param appId
     * @param privateKey
     * @param publicKey
     * @param outTradeNo 商户订单号
     * @param totalAmount 支付金额
     * @param subject  订单标题
     * @param buyer_id  是支付宝小程序授权登录成功后获取到的支付宝 user_id
     * @param notify_url 回调地址
     * @return
     */
    public static String create(String appId, String privateKey, String publicKey,String outTradeNo,String totalAmount,String subject,String buyer_id, String notify_url) {

        AlipayClient alipayClient = AliAuthUtil.getAlipayClient(appId, privateKey, publicKey);
        AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("out_trade_no",outTradeNo);
        jsonObject.put("total_amount",totalAmount);
        jsonObject.put("subject",subject);
        jsonObject.put("buyer_id",buyer_id);
        jsonObject.put("timeout_express","31m");
        request.setBizContent(jsonObject.toJSONString());
        request.setNotifyUrl(notify_url);//异步通知地址,必填,该接口只通过该参数进行异步通知
        logger.warn("统一收单交易创建接口请求参数:{}",JSONObject.toJSONString(request));
        try {
            //使用的是execute
            AlipayTradeCreateResponse response = alipayClient.execute(request);
            String tradeNo = response.getTradeNo();//获取返回的tradeNO。
            return tradeNo;
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }

自定义工具方法

	/**
     * 验证
     *
     * @param params
     * @param publicKey
     * @return
     */
    public static boolean rsaCheckV1(Map<String, String> params, String publicKey, String signType) {

        boolean b = false;
        try {
            b = AlipaySignature.rsaCheckV1(params, publicKey, "utf-8", signType);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return b;

    }
    
	/**
     * 生成随机流水号
     *
     * @return
     */
    public static String genOrderNo() {
        long num = System.currentTimeMillis() + (long) (Math.random() * 10000000L);
        return String.valueOf(num);
    }

接收回调

/**
     * 支付宝支付回调
     *
     * @return
     */
    @RequestMapping("/alipayCallback")
    public void aliCallback(HttpServletRequest request, HttpServletResponse response) {
	
        Map<String, String[]> notifyParams = request.getParameterMap();
        String notifyParamStr = JSONObject.toJSONString(notifyParams);
        logger.warn("回调通知参数:{}", notifyParamStr);
        
        //验证入参
        Map<String, String> params = new HashMap<String, String>();
        for (Iterator<String> iter = notifyParams.keySet().iterator(); iter.hasNext(); ) {
            String name = iter.next();
            String[] values = notifyParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        // getAliPublicKey() 自定义方法获取支付宝公钥
        boolean b = AliPayUtil.rsaCheckV1(params, getAliPublicKey(), "RSA2");
        if (!b) {
            logger.error("验证失败,验签参数:{}", JSON.toJSONString(params));
            return;
        }
		
		JSONObject jsonObject = JSONObject.parseObject(notifyParamStr);
		//业务处理
		.....
        //向芝麻反馈处理是否成功
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
            writer.write("success"); //一定要打印success
            writer.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值