java支付寶支付後臺服務方法

java支付寶支付後臺服務方法

前言

記錄一下支付功能的一些方法, 僅供學習參考,不涉及商業內容,一些基本環境先說一下,後面就不再說了
jdk1.8 springBoot2.0 maven

支付寶支付對接流程

使用支付寶沙箱做演示
首先要登錄支付寶開放平臺-開發者中心-研發服務(沙箱)

  1. 設置RSA2(SHA256)密鑰(推薦), 這裏有公鑰證書和公鑰兩種方式,選擇不同的方式對調用alipay-sdk-java第三方sdk的方法也會不同,後面會區分標識.
  2. 下載支付寶沙箱app到手機,可以使用給你的沙箱賬號登錄支付寶沙箱app, 賬號有商家和買家的兩個賬號,錢都可以自己設置
  3. 引入支付寶第三方jar包, 公鑰證書文件放到項目目錄下
    在這裏插入圖片描述
<dependency>
	<groupId>com.alipay.sdk</groupId>
	<artifactId>alipay-sdk-java</artifactId>
	<version>4.8.73.ALL</version>
</dependency>

<dependency>
	<groupId>commons-logging</groupId>
	<artifactId>commons-logging</artifactId>
	<version>1.1.1</version>
</dependency>

<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId>bcprov-jdk15on</artifactId>
	<version>1.62</version>
</dependency>
  1. 編寫一個配置支付寶參數的類
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.IOException;

public class AlipayConfig {

    // 應用ID,您的APPID,收款賬號既是您的APPID對應支付寶賬號
    public static final String APP_ID = "";

    // 商戶私鑰,您的PKCS8格式RSA2私鑰
    public static final String MERCHANT_PRIVATE_KEY = "";

    // 簽名方式
    public static final String SIGN_TYPE = "RSA2";

    // 字符編碼格式
    public static final String CHARSET = "UTF-8";

    // json
    public static final String FORMAT = "json";

    // 支付寶網關(開發環境)
    public static final String GATEWAY_URL = "https://openapi.alipaydev.com/gateway.do";

    public static final String APP_CERT_PATH = "/static/CRT/appCertPublicKey_2016102300744804.crt";

    public static final String ALIPAY_CERT_PATH = "/static/CRT/alipayCertPublicKey_RSA2.crt";

    public static final String ALIPAY_ROOT_CERT_PATH = "/static/CRT/alipayRootCert.crt";

    private volatile static AlipayClient alipayClient = null;

	// 使用"公鑰證書"創建的阿里客戶端對象實例
    public static AlipayClient getInstance() throws AlipayApiException, IOException {
        if (alipayClient == null) {
            synchronized (AlipayClient.class) {
                if (alipayClient == null) {
                    CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
                    File file = new File(ResourceUtils.getURL("classpath:").getPath());
                    certAlipayRequest.setCertPath(file.getAbsolutePath() + APP_CERT_PATH);
                    certAlipayRequest.setAlipayPublicCertPath(file.getAbsolutePath() + ALIPAY_CERT_PATH);
                    certAlipayRequest.setRootCertPath(file.getAbsolutePath() + ALIPAY_ROOT_CERT_PATH);
                    certAlipayRequest.setServerUrl(AlipayConfig.GATEWAY_URL);
                    certAlipayRequest.setAppId(AlipayConfig.APP_ID);
                    certAlipayRequest.setPrivateKey(AlipayConfig.MERCHANT_PRIVATE_KEY);
                    certAlipayRequest.setFormat(FORMAT);
                    certAlipayRequest.setCharset(AlipayConfig.CHARSET);
                    certAlipayRequest.setSignType(AlipayConfig.SIGN_TYPE);
                    alipayClient = new DefaultAlipayClient(certAlipayRequest);
                }
            }
        }
        return alipayClient;
    }

    private AlipayConfig() {
    }
}
  1. 阿里支付的方法
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AlipayVo {
    private String out_trade_no;
    private String total_amount;
    private String subject;
    private String product_code;
    private String passback_params;
}

/**
 * 阿里支付接口
 *
 * @param outTradeNo     商號
 * @param totalAmount    金額
 * @param notifyUrl      回調地址
 * @param passbackParams 附加數據
 * @return               返回的字符串是生成的訂單,如果是app返回給前端喚起支付寶沙箱支付, 如果是網頁直接跳轉支付寶網頁支付頁面
 */
public static String alipay(String outTradeNo, String totalAmount, String notifyUrl, String passbackParams) {
    try {
        AlipayClient alipayClient = AlipayConfig.getInstance();
        // 注意這裏是AlipayTradeAppPayRequest對象, 如果是網頁支付的話創建AlipayTradePagePayRequest對象
        AlipayTradeAppPayRequest aliRequest = new AlipayTradeAppPayRequest();
        aliRequest.setNotifyUrl(notifyUrl);
        aliRequest.setBizContent(JSONObject.toJSONString(
                AlipayVo.builder()
                        .out_trade_no(outTradeNo)
                        .subject("充值")
                        .product_code("FAST_INSTANT_TRADE_PAY")
                        .total_amount(totalAmount)
                        .passback_params(URLEncoder.encode(passbackParams, AlipayConfig.CHARSET))
                        .build()
        ));
        try {
            // 注意這裏是sdkExecute方法, 如果是網頁支付的話調用pageExecute方法
            return alipayClient.sdkExecute(aliRequest).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new RuntimeException("支付異常");
        }
    } catch (AlipayApiException | IOException e) {
        e.printStackTrace();
        throw new RuntimeException("創建支付實例異常");
    }
}
  1. 支付完成之後,會被阿里調用回調的方法,注意這個方法必須是外網能夠訪問的, 可以在阿里雲linux服務器上面,運行一個後端服務, 接受回調的方法
@PostMapping(value = "/recharge")
@ApiOperation(value = "支付寶回調-充值")
public String callback(HttpServletRequest request) {
    return PayUtils.notifyUrl(() -> {
        //...業務邏輯
        return null;
    }, request);
}

/**
 * 阿里支付完成回調方法
 *
 * @param supplier 業務邏輯
 * @param request  請求
 */
public static String notifyUrl(Supplier<Void> supplier, HttpServletRequest request) {
    Map<String, String> params = new HashMap<>();

    // 1.從支付寶回調的request域中取值
    Map<String, String[]> requestParams = request.getParameterMap();
    for (String name : requestParams.keySet()) {
        String[] values = requestParams.get(name);
        String valueStr = "";
        for (int i = 0; i < values.length; i++) {
            valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
        }
        // 亂碼解決,這段代碼在出現亂碼時使用。如果mysign和sign不相等也可以使用這段代碼轉化
        // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
        params.put(name, valueStr);
    }

    // 2.封裝必須參數
    String out_trade_no = request.getParameter("out_trade_no");// 商戶訂單號
    String subject = request.getParameter("subject");// 訂單內容
    String tradeStatus = request.getParameter("trade_status");//交易狀態

    log.debug("____________________支付寶返回參數start_______________________");
    log.debug(JSON.toJSONString(params));
    log.debug("out_trade_no: " + out_trade_no);
    log.debug("subject: " + subject);
    log.debug("tradeStatus: " + tradeStatus);
    log.debug("____________________支付寶返回參數end_______________________");


    // 3.簽名驗證(對支付寶返回的數據驗證,確定是支付寶返回的)
    boolean signVerified = false;
    try {
        //3.1調用SDK驗證簽名
        File file = new File(ResourceUtils.getURL("classpath:").getPath());
        String alipayPublicCertPath = file.getAbsolutePath() + AlipayConfig.ALIPAY_CERT_PATH;
        // 公鑰證書驗證方法rsaCertCheckV1
        signVerified = AlipaySignature.rsaCertCheckV1(params, alipayPublicCertPath, AlipayConfig.CHARSET, AlipayConfig.SIGN_TYPE);
    } catch (AlipayApiException | FileNotFoundException e) {
        e.printStackTrace();
        log.error("驗籤異常");
    }

    // 4.對驗籤進行處理
    if (signVerified) {    //驗籤通過
        if (tradeStatus != null && tradeStatus.equals("TRADE_SUCCESS")) {    //只處理支付成功的訂單: 修改交易表狀態,支付成功
            // 業務代碼
            supplier.get();
            log.debug("異步回調業務處理完畢.");
            return "success";
        } else {
            log.error("驗籤通過, 但是狀態 tradeStatus is null or tradeStatus != TRADE_SUCCESS, params: " + params);
            return "fail";
        }
    } else {  //驗籤不通過
        log.error("驗籤失敗");
        return "fail";
    }
}
  1. 回調方法執行完成之後,再次查詢支付寶訂單是否生成方法
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("支付寶訂單查詢vo")
public class AlipayQueryOrderVo {
    private String out_trade_no;
    private String trade_no;
    private String org_pid;
    private String[] query_options;
}

/**
 * 支付寶支付訂單的查詢
 */
public static Boolean existsOrder(AlipayQueryOrderVo alipayQueryOrderVo) {
    try {
        AlipayClient alipayClient = AlipayConfig.getInstance();
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        request.setBizContent(JSONObject.toJSONString(alipayQueryOrderVo));
        AlipayTradeQueryResponse response = alipayClient.certificateExecute(request);
        if (response.isSuccess()) {
            if (!"10000".equals(response.getCode()))
                throw new RRException(response.getSubMsg());
            return true;
        }
        throw new RuntimeException(response.getSubMsg());
    } catch (AlipayApiException | IOException e) {
        e.printStackTrace();
        throw new RuntimeException("查詢支付訂單異常");
    }
}
  1. 這樣支付寶支付流程就完成了
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章