洛谷 P3374 【模板】樹狀陣列 1
支付寶支付(證書模式)前提:
這三個證書先準備好,獲取的步驟就不用說了;
現在支付寶已經很貼心的幫我們封裝好了各種api,直接在pom檔案裡面引入以下依賴就行了。
com.alipay.sdk
alipay-easysdk
${alipay-easysdk.version}
<alipay-easysdk.version>2.2.0</alipay-easysdk.version>
這些做好了直接呼叫api就行了
一、先初始化客戶端工廠類,全域性初始化一次就夠了:
import com.alipay.easysdk.factory.Factory;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
-
啟動時初始化一下支付寶
*/
@Component
public class AliPayFactoryInit {
@Resource
private AlipayConfig alipayConfig;@PostConstruct
public void AliPayFactoryInit() {
//1.全域性只用設定引數一次
Factory.setOptions(alipayConfig.Config());
}
二、配置檔案
import com.alipay.easysdk.kernel.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AlipayConfig {
@Value("${alipay.gatewayHost}") private String gatewayHost; @Value("${alipay.appId}") private String appId; @Value("${alipay.merchantPrivateKey}") private String merchantPrivateKey; @Value("${alipay.merchantCertPath}") private String merchantCertPath; @Value("${alipay.alipayCertPath}") private String alipayCertPath; @Value("${alipay.alipayRootCertPath}") private String alipayRootCertPath; @Value("${alipay.notifyUrl}") private String notifyUrl; @Value("${alipay.encryptKey}") private String encryptKey; @Bean public Config Config() { Config config = new Config(); config.protocol = "https"; config.gatewayHost = gatewayHost; config.signType = "RSA2"; config.appId = appId; // 為避免私鑰隨原始碼洩露,推薦從檔案中讀取私鑰字串而不是寫入原始碼中 config.merchantPrivateKey = merchantPrivateKey; //注:證書檔案路徑支援設定為檔案系統中的路徑或CLASS_PATH中的路徑,優先從檔案系統中載入,載入失敗後會繼續嘗試從CLASS_PATH中載入 config.merchantCertPath = merchantCertPath; config.alipayCertPath = alipayCertPath; config.alipayRootCertPath = alipayRootCertPath; //注:如果採用非證書模式,則無需賦值上面的三個證書路徑,改為賦值如下的支付寶公鑰字串即可 // config.alipayPublicKey = "<-- 請填寫您的支付寶公鑰,例如:MIIBIjANBg... -->"; //可設定非同步通知接收服務地址(可選) config.notifyUrl = notifyUrl; //可設定AES金鑰,呼叫AES加解密相關介面時需要(可選) config.encryptKey = encryptKey; return config; }
}
三、支付業務類
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.common.models.AlipayTradeCloseResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeCreateResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse;
import com.alipay.easysdk.payment.wap.models.AlipayTradeWapPayResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalTime;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Service
public class DoAliPayReqImpl implements DoAliPayReq {
/**
* 預支付
*
* @param subject 訂單名稱
* @param outTradeNo 商戶訂單號
* @param totalAmount 支付金額
* @return
*/
public ApiResult createPay(String subject, String outTradeNo, String totalAmount, String quitUrl, String returnUrl) {
try {
// 2. 發起API呼叫
log.info("支付金額為:{}", totalAmount);
log.info("支付訂單號為:{}", outTradeNo);
log.info("退出返回為為:{}", quitUrl);
log.info("返回為:{}", returnUrl);
log.info("商品名稱:{}", subject);
AlipayTradeWapPayResponse response =
Factory.Payment.Wap().pay(subject, outTradeNo, totalAmount, quitUrl, returnUrl);
// 3. 處理響應或異常
log.error("返回跳轉連結:{}", response.getBody());
if (ResponseChecker.success(response)) {
return ApiResult.ok(response.getBody());
} else {
log.error("呼叫失敗");
return ApiResult.fail();
}
} catch (Exception e) {
log.error("呼叫遭遇異常,原因:" + e.getMessage());
return ApiResult.fail(e.getMessage());
}
}
/**
* 支付回撥
*
* @param request
* @param response
* @return
*/
public String notify(HttpServletRequest request, HttpServletResponse response) {
try {
//1.從支付寶回撥的request域中取值
Map<String, String[]> requestParams = request.getParameterMap();
Map<String, String> params = new HashMap<>();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
}
//2.簽名驗證
Boolean aBoolean = Factory.Payment.Common().verifyNotify(params);
if (!aBoolean) {
log.error("verifyNotify failed! params={}", params);
return PayConstant.ALI_FAIL;
}
//訂單狀態
String tradeStatus = params.get(PayConstant.ALI_TRADE_STATUS);
//商戶訂單號
String outTradeNo = params.get(PayConstant.ALI_OUT_TRADE_NO);
//流水號
String tradeNo = params.get(PayConstant.ALI_TRADE_NO);
//3 判斷狀態
if (!tradeStatus.equals(PayConstant.TRADE_SUCCESS)) {
log.error("order not pay succ! orderInfo={}", params);
return PayConstant.ALI_SUCCESS;
}
//4 更新訂單
if (!updateMainOrder) {
log.error("updateMainOrderByPayOrderId failed! request={}", params);
return PayConstant.ALI_FAIL;
}
log.info("payinfo process succ! request={}", params);
return PayConstant.ALI_SUCCESS;
} catch (Exception e) {
log.error("回撥介面異常,原因:{}", e.getMessage());
}
return PayConstant.ALI_FAIL;
}
/**
* 關閉訂單
*
* @param outTradeNo 商戶訂單號
* @return
*/
public void closePay(String outTradeNo) {
try {
// 2. 發起API呼叫
log.error("關閉訂單號為:{}", outTradeNo);
AlipayTradeCloseResponse close = Factory.Payment.Common().close(outTradeNo);
// 3. 處理響應或異常
log.error("返回訂單號為:{}", close.getMsg());
} catch (Exception e) {
log.error("呼叫遭遇異常,原因:" + e.getMessage());
}
}
/**
* 退款介面
*
* @return
*/
@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
public String refund(String outTradeNo, String refundAmount) throws Exception {
try {
log.error("refund,時間:" + LocalTime.now());
// 2. 發起API呼叫
log.error("alipay關閉訂單號為:{}", outTradeNo);
AlipayTradeRefundResponse refund = Factory.Payment.Common().refund(outTradeNo, refundAmount);
// 3. 處理響應或異常
log.error("alipay退款返回為:{}", refund.getMsg());
if (ResponseChecker.success(refund)) {
return refund.getCode();
}
return null;
} catch (Exception e) {
log.error("alipay呼叫遭遇異常,原因:{}", e.getMessage());
throw new Exception("alipay呼叫遭遇異常");
}
}
@Recover
public String recover(Exception e) {
System.out.println("alipay重試次數結束後還有異常,回撥方法開始執行");
log.error("alipay重試次數結束後還有異常,回撥方法開始執行");
//可呼叫其餘的方法
return null;
}
/**
- 獲小程式取pid
- @param params
- @param httpRequest
- @return
- @throws Exception
*/
@Override
public ApiResult getOpenId(GetOpenIdReqeust params, HttpServletRequest httpRequest) {
try {
// 2. 配置
log.error(“支付寶小程式code為:{}”, params.getCode());
AlipaySystemOauthTokenResponse token = Factory.Base.OAuth().getToken(params.getCode());
// 3. 處理響應或異常
log.error(“返回支付寶小程式userId為:{}”, token.getUserId());
if (ResponseChecker.success(token)) {
return ApiResult.ok(token.getUserId());
} else {
log.error(“呼叫失敗”);
return ApiResult.fail(token.getSubMsg());
}
} catch (Exception e) {
log.error(“呼叫遭遇異常,原因:” + e.getCause());
return ApiResult.fail(e.getMessage());
}
}
/**
- 獲取手機號
- @param params
- @return
- @throws Exception
*/
public ApiResult getPhone(GetPhoneVo params) {
try {
String response = params.getContent();
//1. 獲取驗籤和解密所需要的引數
Map<String, String> openapiResult = JSON.parseObject(response,
new TypeReference<Map<String, String>>() {
}, Feature.OrderedField);
String signType = “RSA2”;
String charset = “UTF-8”;
String encryptType = “AES”;
String sign = openapiResult.get(“sign”);
String content = openapiResult.get(“response”);
//如果密文的
boolean isDataEncrypted = !content.startsWith("{");
boolean signCheckPass = false;
//2. 驗籤
String signContent = content;
String signVeriKey = aliAppletsConfig.getPublicKey();
String decryptKey = aliAppletsConfig.getMerchantPrivateKey();
//如果是加密的報文則需要在密文的前後新增雙引號
if (isDataEncrypted) {
signContent = “”" + signContent + “”";
}
signCheckPass = AlipaySignature.rsaCheck(signContent, sign, signVeriKey, charset, signType);
if (!signCheckPass) {
//驗籤不通過(異常或者報文被篡改),終止流程(不需要做解密)
return ApiResult.fail(response);
}
//3. 解密
String plainData = null;
if (isDataEncrypted) {
plainData = AlipayEncrypt.decryptContent(content, encryptType, decryptKey, charset);
} else {
plainData = content;
}
//json序列化
JSONObject object = JSONObject.parseObject(plainData);
if (object != null && “10000”.equals(object.getString(“code”))) {
return ApiResult.fail(plainData);
}
String mobile = object.get(“mobile”).toString();
return ApiResult.ok(mobile);
} catch (Exception e) {
log.error(“解密遭遇異常,原因:” + e.getCause());
return ApiResult.fail(“解密遭遇異常”);
}
}
}