支付宝当面付对接

菠萝饭 341 2021-12-13

前言

开发原因及需求见上文:微信native支付对接

支付宝当面付

支付宝配置类 zfbinfo.properties
# 支付宝网关名、partnerId和appId
open_api_domain = https://openapi.alipay.com/gateway.do
mcloud_api_domain = http://mcloudmonitor.com/gateway.do
pid = 
appid = 

# RSA私钥、公钥和支付宝公钥
private_key =
public_key = 
#SHA256withRsa对应支付宝公钥
alipay_public_key = 

# 签名类型: RSA->SHA1withRsa,RSA2->SHA256withRsa
sign_type = RSA2
# 当面付最大查询次数和查询间隔(毫秒)
max_query_retry = 5
query_duration = 5000

# 当面付最大撤销次数和撤销间隔(毫秒)
max_cancel_retry = 3
cancel_duration = 2000

# 交易保障线程第一次调度延迟和调度间隔(秒)
heartbeat_delay = 5
heartbeat_duration = 900
支付宝工具类 PayCommonUtil:
package com.joymusic.servlet.utils.aliPay;

import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.builder.AlipayTradeQueryRequestBuilder;
import com.alipay.demo.trade.model.builder.AlipayTradeRefundRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.model.result.AlipayF2FQueryResult;
import com.alipay.demo.trade.model.result.AlipayF2FRefundResult;
import com.alipay.demo.trade.service.AlipayMonitorService;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayMonitorServiceImpl;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import com.alipay.demo.trade.service.impl.AlipayTradeWithHBServiceImpl;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

//支付宝支付工具类
public class PayCommonUtil {
    private static org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger("mydebug");
    // 支付宝当面付2.0服务
    private static AlipayTradeService tradeService;
    // 支付宝当面付2.0服务(集成了交易保障接口逻辑)
    private static AlipayTradeService tradeWithHBService;
    // 支付宝交易保障接口服务,供测试接口api使用,请先阅读readme.txt
    private static AlipayMonitorService monitorService;

    static {
        /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
         *  Configs会读取classpath下的zfbinfo.properties文件配置信息,如果找不到该文件则确认该文件是否在classpath目录
         */
        Configs.init("zfbinfo.properties");

        /** 使用Configs提供的默认参数
         *  AlipayTradeService可以使用单例或者为静态成员对象,不需要反复new
         */
        tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();
        // 支付宝当面付2.0服务(集成了交易保障接口逻辑)
        tradeWithHBService = new AlipayTradeWithHBServiceImpl.ClientBuilder().build();

        /** 如果需要在程序中覆盖Configs提供的默认参数, 可以使用ClientBuilder类的setXXX方法修改默认参数 否则使用代码中的默认设置 */
        monitorService = new AlipayMonitorServiceImpl.ClientBuilder()
                .setGatewayUrl("http://mcloudmonitor.com/gateway.do").setCharset("GBK")
                .setFormat("json").build();
    }

    //发起当面付2.0生成支付二维码
    public static String aliPay(String body, String total_amount, String uid, String out_trade_no) throws JSONException {
        String code_url = "";
        String subject = body;
        // 支付超时,定义为120分钟
        String timeoutExpress = "100m";
        // 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号)
        // 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID
        String sellerId = "";
        String storeId = "txhy_joymusic";
        // 创建扫码支付请求builder,设置请求参数
        AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
                .setSubject(subject).setTotalAmount(total_amount).setBody(body).setOutTradeNo(out_trade_no)
                .setTimeoutExpress(timeoutExpress).setSellerId(sellerId).setTerminalId(uid).setStoreId(storeId);
        AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);

        switch (result.getTradeStatus()) {
            case SUCCESS:
                AlipayTradePrecreateResponse response = result.getResponse();
                JSONObject responseJson = new JSONObject(response);
                code_url = responseJson.getString("qrCode");
                break;
            case FAILED:
                log.info("支付宝预下单失败!!!");
                break;
            case UNKNOWN:
                log.info("系统异常,预下单状态未知!!!");
                break;
            default:
                log.info("不支持的交易状态,交易返回异常!!!");
                break;
        }
        return code_url;
    }

    /**
     * 查询订单
     *
     * @param outTradeNo 商户订单id
     * @return
     * @throws Exception
     */
    public static Map selectOrder(String outTradeNo) throws Exception {

        Map<String, String> selectMap = new HashMap<>();
        // 创建查询请求builder,设置请求参数
        AlipayTradeQueryRequestBuilder builder = new AlipayTradeQueryRequestBuilder().setOutTradeNo(outTradeNo);
        AlipayF2FQueryResult result = tradeService.queryTradeResult(builder);
        AlipayTradeQueryResponse response = result.getResponse();
        JSONObject jsonObject = new JSONObject(response.getBody());
        JSONObject query_response = jsonObject.getJSONObject("alipay_trade_query_response");
        String resultCode = query_response.getString("code");
        if ("10000".equals(resultCode)){
            String buyer_user_id = query_response.getString("buyer_user_id");//支付宝用户id
            String trade_no = query_response.getString("trade_no");//支付宝订单id
            String out_trade_no = query_response.getString("out_trade_no");//商户订单id
            String trade_status = query_response.getString("trade_status");//交易状态
            String amount = query_response.getString("receipt_amount");//实际支付金额
            String send_pay_date = query_response.getString("send_pay_date");//付款时间
            selectMap.put("returnCode","1");
            selectMap.put("trade_status",trade_status);
            selectMap.put("buyer_user_id",buyer_user_id);
            selectMap.put("trade_no",trade_no);
            selectMap.put("out_trade_no",out_trade_no);
            selectMap.put("amount",amount);
            selectMap.put("send_pay_date",send_pay_date);
        }else {
            selectMap.put("returnCode","0");
            log.info("查询错误原因: "+query_response.getString("sub_msg"));
        }
        return selectMap;
    }

    //分转换为元
    public static String cent2yuan(int orderPrice){
        Double num1 = Double.valueOf(orderPrice);
        Double ratio = num1 / 100;
        return String.format("%.2f", ratio);
    }

    // 测试当面付2.0退款
    public static HashMap<String, String> test_trade_refund(String outTradeNo, String refundAmount, String refundReason) throws JSONException {
        HashMap<String, String> refundMap = new HashMap<>();
        // (必填) 退款金额,该金额必须小于等于订单的支付金额,单位为元
        refundAmount = "0.01";
        // (必填) 退款原因,可以说明用户退款原因,方便为商家后台提供统计
        refundReason = "正常退款,用户买多了";
        // (必填) 商户门店编号,退款情况下可以为商家后台提供退款权限判定和统计等作用,详询支付宝技术支持
        String storeId = "txhy_joymusic";
        // 创建退款请求builder,设置请求参数
        AlipayTradeRefundRequestBuilder builder = new AlipayTradeRefundRequestBuilder()
                .setOutTradeNo(outTradeNo).setRefundAmount(refundAmount).setRefundReason(refundReason).setStoreId(storeId).setStoreId(storeId);

        AlipayF2FRefundResult result = tradeService.tradeRefund(builder);
        AlipayTradeRefundResponse response = result.getResponse();
        JSONObject jsonObject = new JSONObject(response.getBody());
        JSONObject query_response = jsonObject.getJSONObject("alipay_trade_query_response");
        String resultCode = query_response.getString("code");
        if ("10000".equals(resultCode)){
            String buyer_user_id = query_response.getString("buyer_user_id");//支付宝用户id
            String trade_no = query_response.getString("trade_no");//支付宝订单id
            String out_trade_no = query_response.getString("out_trade_no");//商户订单id
            String trade_status = query_response.getString("trade_status");//交易状态
            String amount = query_response.getString("receipt_amount");//实际支付金额
            String send_pay_date = query_response.getString("send_pay_date");//付款时间
            refundMap.put("returnCode","1");
            refundMap.put("trade_status",trade_status);
            refundMap.put("buyer_user_id",buyer_user_id);
            refundMap.put("trade_no",trade_no);
            refundMap.put("out_trade_no",out_trade_no);
            refundMap.put("amount",amount);
            refundMap.put("send_pay_date",send_pay_date);
        }else {
            refundMap.put("returnCode","0");
            log.info("查询错误原因: "+query_response.getString("sub_msg"));
        }
        return refundMap;
    }
}
调用及实现:
//支付
String ip = "192.168.0.1";//发起支付ip
String body = "XX订购";//订单标题
String orderPrice = "1";//支付金额(分)
String userId = "test010101";//设备id 可当做用户id
String out_trade_no = userId.substring(0,5)+"_"+ PayCommonUtil.getCurrTime() + PayCommonUtil.buildRandom(4);//商户订单id
//数据库记录发起订购记录(自定义)
setInitPay(ip, userId,orderPrice,body,"86",songId,platform,out_trade_no,payType);
String total_amount = cent2yuan(orderPrice);
String aliQRcode = aliPay.PayCommonUtil.aliPay(body, total_amount, userId, out_trade_no);

//查询
//订单状态 :0: 用户支付中 1: 支付成功 3:未支付 4:已关闭
Map orderSelectMap = aliPay.PayCommonUtil.selectOrder(out_trade_no);
String aliReturnCode = orderSelectMap.get("returnCode").toString();
String trade_state = orderSelectMap.get("trade_status").toString();
if("1".equals(aliReturnCode)){
    String myOrderNumber = orderSelectMap.get("out_trade_no").toString();
    if ("TRADE_SUCCESS".equals(trade_state)){//记录数据库
        //更新数据库(自定义)        
        setPayResult(ip, userId, "86", songId, platform, orderPrice+"", validTime, expireTime, "0", aliOderNumber, payType, myOrderNumber, openid, 0);
        orderResult = "0";
    }else if("WAIT_BUYER_PAY".equals(trade_state)){//正在支付中时
        if ("1".equals(isLast)) {
            updateInfoPay(userId,myOrderNumber,"3");
        }else {
            isKeep = "1";
        }
    }else if("TRADE_CLOSED".equals(trade_state)){//订单关闭
        updateInfoPay(userId,myOrderNumber,"3");
    }else if("TRADE_FINISHED".equals(trade_state)){
        updateInfoPay(userId,myOrderNumber,"4");
    }
}

# 实际问题