feat:钱包接口对接
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
package com.cool.store.http;
|
||||
|
||||
import com.cool.store.enums.ErrorCodeEnum;
|
||||
import com.cool.store.exception.ServiceException;
|
||||
import com.cool.store.utils.RsaSignUtil;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.*;
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author suzhuhong
|
||||
* @Date 2025/11/13 10:00
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class WalletHttpClientRest {
|
||||
|
||||
@Autowired
|
||||
private OkHttpClient okHttpClient;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Value("${cool.api.rsa.private.key}")
|
||||
private String coolPrivateKey;
|
||||
@Value("${wallet.api.rsa.public.key}")
|
||||
private String walletPublicKey;
|
||||
|
||||
|
||||
/**
|
||||
* 发送带签名的POST请求
|
||||
*/
|
||||
public <T> T postWithSign(String url, Object request, Class<T> responseType) {
|
||||
try {
|
||||
// 1. 准备请求参数
|
||||
Map<String, Object> requestParams = convertToMap(request);
|
||||
requestParams.put("timestamp", System.currentTimeMillis());
|
||||
requestParams.put("key", "360155690205317");
|
||||
// 2. 生成签名
|
||||
String signature = RsaSignUtil.generateSign(requestParams,coolPrivateKey);
|
||||
requestParams.put("sign", signature);
|
||||
|
||||
// 3. 发送请求
|
||||
String responseJson = executePost(url, requestParams);
|
||||
|
||||
// 4. 解析响应
|
||||
return parseResponse(responseJson, responseType);
|
||||
|
||||
} catch (ServiceException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// 其他异常统一包装为RuntimeException
|
||||
log.error("发送带签名POST请求失败: {}", url, e);
|
||||
throw new RuntimeException("接口调用异常: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送带签名和验签的POST请求
|
||||
*/
|
||||
public <T> T postWithSignAndVerify(String url, Object request, Class<T> responseType) {
|
||||
try {
|
||||
// 1. 准备请求参数
|
||||
Map<String, Object> requestParams = convertToMap(request);
|
||||
requestParams.put("timestamp", System.currentTimeMillis());
|
||||
|
||||
// 2. 生成签名
|
||||
String signature = RsaSignUtil.generateSign(requestParams,coolPrivateKey);
|
||||
requestParams.put("sign", signature);
|
||||
|
||||
// 3. 发送请求
|
||||
String responseJson = executePost(url, requestParams);
|
||||
|
||||
// 4. 解析响应并验证签名
|
||||
return parseAndVerifyResponse(responseJson, responseType);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("发送带签名和验签POST请求失败: {}", url, e);
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送普通POST请求(无签名)
|
||||
*/
|
||||
public <T> T post(String url, Object request, Class<T> responseType) {
|
||||
try {
|
||||
String responseJson = executePost(url, request);
|
||||
return parseResponse(responseJson, responseType);
|
||||
} catch (Exception e) {
|
||||
log.error("发送POST请求失败: {}", url, e);
|
||||
throw new RuntimeException("调用外部接口失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行POST请求
|
||||
*/
|
||||
private String executePost(String url, Object body) throws IOException {
|
||||
String jsonBody = objectMapper.writeValueAsString(body);
|
||||
RequestBody requestBody = RequestBody.create( MediaType.parse("application/json; charset=utf-8"),jsonBody);
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.post(requestBody)
|
||||
.addHeader("Content-Type", "application/json")
|
||||
.build();
|
||||
|
||||
log.info("发送POST请求: {}, 数据: {}", url, jsonBody);
|
||||
|
||||
try (Response response = okHttpClient.newCall(request).execute()) {
|
||||
if (!response.isSuccessful()) {
|
||||
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,response.code() + " " + response.message());
|
||||
}
|
||||
|
||||
|
||||
String responseBody = response.body().string();
|
||||
log.info("收到响应: {}", responseBody);
|
||||
|
||||
checkBusinessResponseCode(responseBody);
|
||||
|
||||
return responseBody;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkBusinessResponseCode(String responseJson) throws IOException {
|
||||
try {
|
||||
Map<String, Object> responseMap = objectMapper.readValue(responseJson,
|
||||
new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
|
||||
Object codeObj = responseMap.get("code");
|
||||
if (codeObj != null) {
|
||||
int code = 0;
|
||||
if (codeObj instanceof Number) {
|
||||
code = ((Number) codeObj).intValue();
|
||||
} else {
|
||||
code = Integer.parseInt(codeObj.toString());
|
||||
}
|
||||
|
||||
if (code != 200) {
|
||||
String msg = (String) responseMap.get("msg");
|
||||
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
|
||||
"code: " + code + ", msg: " + msg);
|
||||
}
|
||||
}
|
||||
} catch (ServiceException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// 如果解析失败,说明可能不是标准格式,继续处理
|
||||
log.debug("无法解析响应码格式: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析响应
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T parseResponse(String responseJson, Class<T> responseType) throws Exception {
|
||||
if (responseType == String.class) {
|
||||
return (T) responseJson;
|
||||
}
|
||||
|
||||
// 解析为通用响应格式
|
||||
Map<String, Object> responseMap = objectMapper.readValue(responseJson,
|
||||
new TypeReference<Map<String, Object>>() {});
|
||||
|
||||
|
||||
|
||||
// 如果返回类型是Map,直接返回
|
||||
if (responseType == Map.class) {
|
||||
return (T) responseMap;
|
||||
}
|
||||
|
||||
// 提取data字段
|
||||
Object data = responseMap.get("data");
|
||||
if (data != null && responseType != Object.class) {
|
||||
return objectMapper.convertValue(data, responseType);
|
||||
}
|
||||
|
||||
return objectMapper.convertValue(responseMap, responseType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析响应并验证签名
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T parseAndVerifyResponse(String responseJson, Class<T> responseType) throws Exception {
|
||||
// 解析为Map来验证签名
|
||||
Map<String, Object> responseMap = objectMapper.readValue(responseJson,
|
||||
new TypeReference<Map<String, Object>>() {});
|
||||
|
||||
// 验证响应签名
|
||||
String responseSign = (String) responseMap.get("sign");
|
||||
if (responseSign != null) {
|
||||
// 移除sign字段后进行验签
|
||||
Map<String, Object> verifyParams = new HashMap<>(responseMap);
|
||||
|
||||
boolean isValid = RsaSignUtil.verifySign(verifyParams, walletPublicKey);
|
||||
if (!isValid) {
|
||||
throw new SecurityException("响应签名验证失败");
|
||||
}
|
||||
log.debug("响应签名验证成功");
|
||||
}
|
||||
|
||||
// 返回指定类型的数据
|
||||
return parseResponse(responseJson, responseType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Map
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> convertToMap(Object obj) {
|
||||
if (obj instanceof Map) {
|
||||
return (Map<String, Object>) obj;
|
||||
}
|
||||
return objectMapper.convertValue(obj, new TypeReference<Map<String, Object>>() {});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.cool.store.service.wallet;
|
||||
|
||||
import com.cool.store.dto.wallet.*;
|
||||
import com.cool.store.http.WalletHttpClientRest;
|
||||
import com.cool.store.request.wallet.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @Author suzhuhong
|
||||
* @Date 2025/11/13 10:51
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Service
|
||||
public class WalletApiService {
|
||||
|
||||
@Resource
|
||||
WalletHttpClientRest walletHttpClientRest;
|
||||
|
||||
/**
|
||||
* 在平安扫呗系统中,创建签约人账户
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public StoreAccountDTO createStoreAndAccount(CreateStoreAndAccountRequest request){
|
||||
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/createStoreAndAccount", request, StoreAccountDTO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开通失败 开通
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public StoreAccountDTO updateStoreAccount(UpdateStoreAccountRequest request){
|
||||
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/updateStoreAccount", request, StoreAccountDTO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建门店接口
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public AccountNoDTO createStore(CreateStoreRequest request){
|
||||
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/v1/createStoreAndAccount", request, AccountNoDTO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 银行发送短信接口
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public AccountAuthenticationDTO authentication(OutStoreIdRequest request){
|
||||
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/authentication", request, AccountAuthenticationDTO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 门店开通平安银行接口
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public AccountVerifyDTO openAccount(AccountVerifyRequest request){
|
||||
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/openAccount", request, AccountVerifyDTO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 签约人账户打标升级
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public AddTagDTO addTag(AccountAddTagRequest request){
|
||||
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/addTag", request, AddTagDTO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取账户信息
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public AccountInfoDTO getAccountInfo(OutStoreIdRequest request){
|
||||
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/getAccountInfo", request, AccountInfoDTO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 大额预支付接口
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public LargePaymentDTO largePayment(LargePaymentRequest request){
|
||||
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/payment/v1/largePayment", request, LargePaymentDTO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 大额预支付查询接口
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public PaymentDTO largePaymentQuery(PaymentDetailRequest request){
|
||||
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/trans/v1/largePaymentQuery", request, PaymentDTO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支行信息
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public BankListDTO getBankList(GetBankRequest request) {
|
||||
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/base/v1/findPageBank", request, BankListDTO.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user