支付网关系统
# 支付网关系统
在跨境电商的世界里,支付就像是连接买家和卖家的桥梁。想象一下,当一位美国的消费者想要购买来自中国的商品时,他们需要用美元支付,而商家希望收到人民币。这个看似简单的过程背后,隐藏着复杂的技术挑战:多币种转换、汇率计算、风险控制、合规检查等。今天,我们就来揭开支付网关系统的神秘面纱,看看它是如何让全球贸易变得如此便捷。
# 📋 系统概述
# 核心功能
支付网关系统是跨境电商的金融中枢,主要负责:
- 多渠道支付接入:支持信用卡、PayPal、支付宝、微信支付等
- 多币种处理:实时汇率转换和多币种结算
- 风险控制:反欺诈检测和风险评估
- 合规管理:满足各国金融监管要求
- 资金清算:自动化的资金分账和清算
- 支付路由:智能选择最优支付通道
# 🏗️ 系统架构设计
graph TB
subgraph "客户端层"
A[Web前端] --> B[移动端]
B --> C[第三方应用]
end
subgraph "网关层"
D[API网关] --> E[负载均衡器]
E --> F[支付网关服务]
end
subgraph "核心服务层"
F --> G[支付路由服务]
F --> H[风控服务]
F --> I[汇率服务]
F --> J[合规服务]
G --> K[渠道管理服务]
H --> L[反欺诈引擎]
I --> M[汇率计算引擎]
J --> N[KYC/AML服务]
end
subgraph "支付渠道层"
K --> O[信用卡通道]
K --> P[PayPal]
K --> Q[支付宝]
K --> R[微信支付]
K --> S[银行直连]
end
subgraph "数据层"
T[支付数据库] --> U[风控数据库]
U --> V[汇率数据库]
V --> W[合规数据库]
W --> X[Redis缓存]
end
subgraph "外部服务"
Y[银行系统] --> Z[监管机构]
Z --> AA[汇率提供商]
AA --> BB[风控服务商]
end
# 💻 核心代码实现
# 1. 支付网关核心服务
/**
* 支付网关核心服务
* 负责统一的支付处理流程
*/
@Service
@Transactional
public class PaymentGatewayService {
private final PaymentRouterService paymentRouterService;
private final RiskControlService riskControlService;
private final ExchangeRateService exchangeRateService;
private final ComplianceService complianceService;
private final PaymentRepository paymentRepository;
private final PaymentEventPublisher paymentEventPublisher;
/**
* 创建支付订单
*/
public PaymentCreationResult createPayment(PaymentCreationRequest request) {
log.info("开始创建支付订单: {}", request);
try {
// 1. 参数验证
validatePaymentRequest(request);
// 2. 风险评估
RiskAssessmentResult riskResult = riskControlService.assessRisk(request);
if (riskResult.getRiskLevel() == RiskLevel.HIGH) {
return PaymentCreationResult.rejected("高风险交易被拒绝", riskResult);
}
// 3. 合规检查
ComplianceCheckResult complianceResult = complianceService.checkCompliance(request);
if (!complianceResult.isPassed()) {
return PaymentCreationResult.rejected("合规检查未通过", complianceResult);
}
// 4. 汇率计算
ExchangeRateCalculationResult rateResult = exchangeRateService
.calculateExchangeRate(request.getSourceCurrency(), request.getTargetCurrency(),
request.getAmount());
// 5. 支付路由选择
PaymentRouteResult routeResult = paymentRouterService.selectOptimalRoute(request, riskResult);
// 6. 创建支付记录
Payment payment = createPaymentRecord(request, riskResult, complianceResult,
rateResult, routeResult);
// 7. 发布支付创建事件
paymentEventPublisher.publishPaymentCreated(payment);
log.info("支付订单创建成功: {}", payment.getPaymentId());
return PaymentCreationResult.success(payment, routeResult);
} catch (Exception e) {
log.error("创建支付订单失败: {}", request, e);
return PaymentCreationResult.failure(e.getMessage());
}
}
/**
* 执行支付
*/
public PaymentExecutionResult executePayment(String paymentId, PaymentExecutionRequest request) {
log.info("开始执行支付: {}", paymentId);
try {
// 1. 获取支付记录
Payment payment = paymentRepository.findByPaymentId(paymentId)
.orElseThrow(() -> new PaymentNotFoundException("支付记录不存在: " + paymentId));
// 2. 验证支付状态
if (payment.getStatus() != PaymentStatus.CREATED) {
throw new InvalidPaymentStatusException(
"支付状态无效: " + payment.getStatus());
}
// 3. 更新支付状态为处理中
payment.setStatus(PaymentStatus.PROCESSING);
payment.setProcessingStartTime(Instant.now());
paymentRepository.save(payment);
// 4. 获取支付渠道处理器
PaymentChannelProcessor processor = getPaymentChannelProcessor(payment.getChannelCode());
// 5. 执行支付
PaymentChannelResult channelResult = processor.processPayment(payment, request);
// 6. 更新支付结果
updatePaymentResult(payment, channelResult);
// 7. 发布支付结果事件
if (channelResult.isSuccess()) {
paymentEventPublisher.publishPaymentSuccess(payment);
} else {
paymentEventPublisher.publishPaymentFailure(payment, channelResult.getErrorMessage());
}
log.info("支付执行完成: {}, 结果: {}", paymentId, channelResult.isSuccess());
return PaymentExecutionResult.from(payment, channelResult);
} catch (Exception e) {
log.error("执行支付失败: {}", paymentId, e);
// 更新支付状态为失败
updatePaymentStatusToFailed(paymentId, e.getMessage());
return PaymentExecutionResult.failure(e.getMessage());
}
}
/**
* 查询支付状态
*/
@Transactional(readOnly = true)
public PaymentStatusResult queryPaymentStatus(String paymentId) {
Payment payment = paymentRepository.findByPaymentId(paymentId)
.orElseThrow(() -> new PaymentNotFoundException("支付记录不存在: " + paymentId));
// 如果支付状态为处理中,尝试从渠道查询最新状态
if (payment.getStatus() == PaymentStatus.PROCESSING) {
try {
PaymentChannelProcessor processor = getPaymentChannelProcessor(payment.getChannelCode());
PaymentChannelStatusResult channelStatus = processor.queryPaymentStatus(payment);
if (channelStatus.isStatusChanged()) {
updatePaymentStatusFromChannel(payment, channelStatus);
}
} catch (Exception e) {
log.warn("查询渠道支付状态失败: {}", paymentId, e);
}
}
return PaymentStatusResult.from(payment);
}
/**
* 支付退款
*/
public RefundResult refundPayment(String paymentId, RefundRequest request) {
log.info("开始处理退款: {}, 退款金额: {}", paymentId, request.getRefundAmount());
try {
// 1. 获取原支付记录
Payment originalPayment = paymentRepository.findByPaymentId(paymentId)
.orElseThrow(() -> new PaymentNotFoundException("支付记录不存在: " + paymentId));
// 2. 验证退款条件
validateRefundRequest(originalPayment, request);
// 3. 创建退款记录
Refund refund = createRefundRecord(originalPayment, request);
// 4. 执行渠道退款
PaymentChannelProcessor processor = getPaymentChannelProcessor(originalPayment.getChannelCode());
RefundChannelResult channelResult = processor.processRefund(originalPayment, refund);
// 5. 更新退款结果
updateRefundResult(refund, channelResult);
// 6. 发布退款事件
if (channelResult.isSuccess()) {
paymentEventPublisher.publishRefundSuccess(refund);
} else {
paymentEventPublisher.publishRefundFailure(refund, channelResult.getErrorMessage());
}
log.info("退款处理完成: {}, 结果: {}", refund.getRefundId(), channelResult.isSuccess());
return RefundResult.from(refund, channelResult);
} catch (Exception e) {
log.error("处理退款失败: {}", paymentId, e);
return RefundResult.failure(e.getMessage());
}
}
/**
* 创建支付记录
*/
private Payment createPaymentRecord(PaymentCreationRequest request,
RiskAssessmentResult riskResult,
ComplianceCheckResult complianceResult,
ExchangeRateCalculationResult rateResult,
PaymentRouteResult routeResult) {
Payment payment = new Payment();
payment.setPaymentId(generatePaymentId());
payment.setOrderId(request.getOrderId());
payment.setUserId(request.getUserId());
payment.setMerchantId(request.getMerchantId());
// 金额信息
payment.setSourceAmount(request.getAmount());
payment.setSourceCurrency(request.getSourceCurrency());
payment.setTargetAmount(rateResult.getTargetAmount());
payment.setTargetCurrency(rateResult.getTargetCurrency());
payment.setExchangeRate(rateResult.getExchangeRate());
payment.setExchangeRateProvider(rateResult.getProvider());
// 路由信息
payment.setChannelCode(routeResult.getChannelCode());
payment.setChannelName(routeResult.getChannelName());
payment.setPaymentMethod(routeResult.getPaymentMethod());
// 风控信息
payment.setRiskLevel(riskResult.getRiskLevel());
payment.setRiskScore(riskResult.getRiskScore());
payment.setRiskFactors(riskResult.getRiskFactors());
// 合规信息
payment.setComplianceStatus(complianceResult.getStatus());
payment.setComplianceChecks(complianceResult.getChecks());
// 状态信息
payment.setStatus(PaymentStatus.CREATED);
payment.setCreatedAt(Instant.now());
payment.setExpiresAt(Instant.now().plus(Duration.ofMinutes(30))); // 30分钟后过期
return paymentRepository.save(payment);
}
/**
* 生成支付ID
*/
private String generatePaymentId() {
return "PAY_" + System.currentTimeMillis() + "_" +
ThreadLocalRandom.current().nextInt(1000, 9999);
}
/**
* 获取支付渠道处理器
*/
private PaymentChannelProcessor getPaymentChannelProcessor(String channelCode) {
return paymentChannelProcessorFactory.getProcessor(channelCode);
}
/**
* 验证支付请求
*/
private void validatePaymentRequest(PaymentCreationRequest request) {
if (request.getAmount() == null || request.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
throw new InvalidPaymentRequestException("支付金额必须大于0");
}
if (StringUtils.isBlank(request.getSourceCurrency())) {
throw new InvalidPaymentRequestException("源币种不能为空");
}
if (StringUtils.isBlank(request.getTargetCurrency())) {
throw new InvalidPaymentRequestException("目标币种不能为空");
}
if (request.getUserId() == null) {
throw new InvalidPaymentRequestException("用户ID不能为空");
}
if (StringUtils.isBlank(request.getOrderId())) {
throw new InvalidPaymentRequestException("订单ID不能为空");
}
}
/**
* 更新支付结果
*/
private void updatePaymentResult(Payment payment, PaymentChannelResult channelResult) {
if (channelResult.isSuccess()) {
payment.setStatus(PaymentStatus.SUCCESS);
payment.setChannelTransactionId(channelResult.getTransactionId());
payment.setChannelResponseCode(channelResult.getResponseCode());
payment.setChannelResponseMessage(channelResult.getResponseMessage());
payment.setCompletedAt(Instant.now());
} else {
payment.setStatus(PaymentStatus.FAILED);
payment.setChannelErrorCode(channelResult.getErrorCode());
payment.setChannelErrorMessage(channelResult.getErrorMessage());
payment.setFailedAt(Instant.now());
}
payment.setProcessingEndTime(Instant.now());
payment.setProcessingDuration(
Duration.between(payment.getProcessingStartTime(), payment.getProcessingEndTime()));
paymentRepository.save(payment);
}
/**
* 更新支付状态为失败
*/
private void updatePaymentStatusToFailed(String paymentId, String errorMessage) {
try {
Payment payment = paymentRepository.findByPaymentId(paymentId).orElse(null);
if (payment != null) {
payment.setStatus(PaymentStatus.FAILED);
payment.setChannelErrorMessage(errorMessage);
payment.setFailedAt(Instant.now());
paymentRepository.save(payment);
}
} catch (Exception e) {
log.error("更新支付状态失败: {}", paymentId, e);
}
}
}
# 2. 支付路由服务
/**
* 支付路由服务
* 根据多种因素选择最优的支付渠道
*/
@Service
public class PaymentRouterService {
private final PaymentChannelRepository channelRepository;
private final PaymentChannelConfigService channelConfigService;
private final PaymentStatisticsService statisticsService;
private final RedisTemplate<String, Object> redisTemplate;
/**
* 选择最优支付路由
*/
public PaymentRouteResult selectOptimalRoute(PaymentCreationRequest request,
RiskAssessmentResult riskResult) {
log.info("开始选择支付路由: {}", request);
try {
// 1. 获取可用的支付渠道
List<PaymentChannel> availableChannels = getAvailableChannels(request, riskResult);
if (availableChannels.isEmpty()) {
throw new NoAvailableChannelException("没有可用的支付渠道");
}
// 2. 计算每个渠道的评分
List<ChannelScore> channelScores = calculateChannelScores(availableChannels, request);
// 3. 选择评分最高的渠道
ChannelScore bestChannel = channelScores.stream()
.max(Comparator.comparing(ChannelScore::getScore))
.orElseThrow(() -> new RouteSelectionException("无法选择最优渠道"));
// 4. 构建路由结果
PaymentRouteResult result = PaymentRouteResult.builder()
.channelCode(bestChannel.getChannel().getChannelCode())
.channelName(bestChannel.getChannel().getChannelName())
.paymentMethod(bestChannel.getChannel().getPaymentMethod())
.routingReason(bestChannel.getReason())
.alternativeChannels(getAlternativeChannels(channelScores, bestChannel))
.build();
log.info("支付路由选择完成: {}, 选中渠道: {}",
request.getOrderId(), result.getChannelCode());
return result;
} catch (Exception e) {
log.error("选择支付路由失败: {}", request, e);
throw new RouteSelectionException("支付路由选择失败: " + e.getMessage(), e);
}
}
/**
* 获取可用的支付渠道
*/
private List<PaymentChannel> getAvailableChannels(PaymentCreationRequest request,
RiskAssessmentResult riskResult) {
// 1. 基础过滤条件
List<PaymentChannel> channels = channelRepository.findByStatusAndCurrency(
ChannelStatus.ACTIVE, request.getSourceCurrency());
// 2. 金额范围过滤
channels = channels.stream()
.filter(channel -> isAmountInRange(channel, request.getAmount()))
.collect(Collectors.toList());
// 3. 地区限制过滤
channels = channels.stream()
.filter(channel -> isRegionSupported(channel, request.getUserRegion()))
.collect(Collectors.toList());
// 4. 风险等级过滤
channels = channels.stream()
.filter(channel -> isRiskLevelAcceptable(channel, riskResult.getRiskLevel()))
.collect(Collectors.toList());
// 5. 渠道可用性检查
channels = channels.stream()
.filter(this::isChannelHealthy)
.collect(Collectors.toList());
return channels;
}
/**
* 计算渠道评分
*/
private List<ChannelScore> calculateChannelScores(List<PaymentChannel> channels,
PaymentCreationRequest request) {
return channels.stream()
.map(channel -> calculateSingleChannelScore(channel, request))
.collect(Collectors.toList());
}
/**
* 计算单个渠道评分
*/
private ChannelScore calculateSingleChannelScore(PaymentChannel channel,
PaymentCreationRequest request) {
double score = 0.0;
List<String> reasons = new ArrayList<>();
// 1. 成功率权重 (40%)
double successRate = getChannelSuccessRate(channel.getChannelCode());
double successScore = successRate * 0.4;
score += successScore;
reasons.add(String.format("成功率: %.2f%% (权重40%%)", successRate * 100));
// 2. 费率权重 (30%)
BigDecimal feeRate = channel.getFeeRate();
double feeScore = (1.0 - feeRate.doubleValue()) * 0.3; // 费率越低分数越高
score += feeScore;
reasons.add(String.format("费率: %.2f%% (权重30%%)", feeRate.multiply(new BigDecimal("100"))));
// 3. 处理速度权重 (20%)
Duration avgProcessingTime = getChannelAvgProcessingTime(channel.getChannelCode());
double speedScore = calculateSpeedScore(avgProcessingTime) * 0.2;
score += speedScore;
reasons.add(String.format("处理速度: %d秒 (权重20%%)", avgProcessingTime.getSeconds()));
// 4. 用户偏好权重 (10%)
double preferenceScore = getUserChannelPreference(request.getUserId(), channel.getChannelCode()) * 0.1;
score += preferenceScore;
reasons.add(String.format("用户偏好: %.2f (权重10%%)", preferenceScore));
return ChannelScore.builder()
.channel(channel)
.score(score)
.reason(String.join(", ", reasons))
.build();
}
/**
* 获取渠道成功率
*/
private double getChannelSuccessRate(String channelCode) {
String cacheKey = "channel_success_rate:" + channelCode;
Double cachedRate = (Double) redisTemplate.opsForValue().get(cacheKey);
if (cachedRate != null) {
return cachedRate;
}
// 计算最近24小时的成功率
Instant startTime = Instant.now().minus(Duration.ofHours(24));
PaymentStatistics stats = statisticsService.getChannelStatistics(channelCode, startTime, Instant.now());
double successRate = stats.getTotalCount() > 0 ?
(double) stats.getSuccessCount() / stats.getTotalCount() : 0.8; // 默认80%
// 缓存5分钟
redisTemplate.opsForValue().set(cacheKey, successRate, Duration.ofMinutes(5));
return successRate;
}
/**
* 获取渠道平均处理时间
*/
private Duration getChannelAvgProcessingTime(String channelCode) {
String cacheKey = "channel_avg_time:" + channelCode;
Long cachedSeconds = (Long) redisTemplate.opsForValue().get(cacheKey);
if (cachedSeconds != null) {
return Duration.ofSeconds(cachedSeconds);
}
// 计算最近24小时的平均处理时间
Instant startTime = Instant.now().minus(Duration.ofHours(24));
Duration avgTime = statisticsService.getChannelAvgProcessingTime(channelCode, startTime, Instant.now());
if (avgTime == null) {
avgTime = Duration.ofSeconds(30); // 默认30秒
}
// 缓存5分钟
redisTemplate.opsForValue().set(cacheKey, avgTime.getSeconds(), Duration.ofMinutes(5));
return avgTime;
}
/**
* 计算速度评分
*/
private double calculateSpeedScore(Duration processingTime) {
long seconds = processingTime.getSeconds();
if (seconds <= 10) {
return 1.0; // 10秒以内满分
} else if (seconds <= 30) {
return 0.8; // 30秒以内80分
} else if (seconds <= 60) {
return 0.6; // 60秒以内60分
} else if (seconds <= 120) {
return 0.4; // 120秒以内40分
} else {
return 0.2; // 超过120秒20分
}
}
/**
* 获取用户渠道偏好
*/
private double getUserChannelPreference(Long userId, String channelCode) {
// 查询用户历史支付记录,计算对该渠道的偏好度
PaymentStatistics userStats = statisticsService.getUserChannelStatistics(userId, channelCode);
if (userStats.getTotalCount() == 0) {
return 0.5; // 无历史记录,中等偏好
}
// 根据使用频率和成功率计算偏好度
double usageFrequency = Math.min(userStats.getTotalCount() / 10.0, 1.0); // 最多10次达到满分
double userSuccessRate = (double) userStats.getSuccessCount() / userStats.getTotalCount();
return (usageFrequency * 0.3 + userSuccessRate * 0.7);
}
/**
* 检查金额是否在范围内
*/
private boolean isAmountInRange(PaymentChannel channel, BigDecimal amount) {
BigDecimal minAmount = channel.getMinAmount();
BigDecimal maxAmount = channel.getMaxAmount();
return (minAmount == null || amount.compareTo(minAmount) >= 0) &&
(maxAmount == null || amount.compareTo(maxAmount) <= 0);
}
/**
* 检查地区是否支持
*/
private boolean isRegionSupported(PaymentChannel channel, String userRegion) {
if (StringUtils.isBlank(userRegion)) {
return true; // 无地区信息,默认支持
}
List<String> supportedRegions = channel.getSupportedRegions();
return supportedRegions == null || supportedRegions.isEmpty() ||
supportedRegions.contains(userRegion);
}
/**
* 检查风险等级是否可接受
*/
private boolean isRiskLevelAcceptable(PaymentChannel channel, RiskLevel riskLevel) {
RiskLevel maxAcceptableRisk = channel.getMaxAcceptableRiskLevel();
return maxAcceptableRisk == null || riskLevel.ordinal() <= maxAcceptableRisk.ordinal();
}
/**
* 检查渠道健康状态
*/
private boolean isChannelHealthy(PaymentChannel channel) {
String healthKey = "channel_health:" + channel.getChannelCode();
Boolean isHealthy = (Boolean) redisTemplate.opsForValue().get(healthKey);
if (isHealthy != null) {
return isHealthy;
}
// 检查渠道健康状态(成功率、响应时间等)
boolean healthy = checkChannelHealth(channel);
// 缓存1分钟
redisTemplate.opsForValue().set(healthKey, healthy, Duration.ofMinutes(1));
return healthy;
}
/**
* 检查渠道健康状态
*/
private boolean checkChannelHealth(PaymentChannel channel) {
// 检查最近5分钟的成功率
Instant startTime = Instant.now().minus(Duration.ofMinutes(5));
PaymentStatistics recentStats = statisticsService.getChannelStatistics(
channel.getChannelCode(), startTime, Instant.now());
if (recentStats.getTotalCount() == 0) {
return true; // 无交易记录,认为健康
}
double recentSuccessRate = (double) recentStats.getSuccessCount() / recentStats.getTotalCount();
// 成功率低于50%认为不健康
return recentSuccessRate >= 0.5;
}
/**
* 获取备选渠道
*/
private List<String> getAlternativeChannels(List<ChannelScore> channelScores, ChannelScore selectedChannel) {
return channelScores.stream()
.filter(score -> !score.getChannel().getChannelCode().equals(selectedChannel.getChannel().getChannelCode()))
.sorted(Comparator.comparing(ChannelScore::getScore).reversed())
.limit(3) // 最多3个备选渠道
.map(score -> score.getChannel().getChannelCode())
.collect(Collectors.toList());
}
}
# 3. 风险控制服务
/**
* 风险控制服务
* 实现多维度的风险评估和反欺诈检测
*/
@Service
public class RiskControlService {
private final RiskRuleEngine riskRuleEngine;
private final FraudDetectionService fraudDetectionService;
private final BlacklistService blacklistService;
private final DeviceFingerprintService deviceFingerprintService;
private final GeoLocationService geoLocationService;
private final RiskModelService riskModelService;
/**
* 风险评估
*/
public RiskAssessmentResult assessRisk(PaymentCreationRequest request) {
log.info("开始风险评估: {}", request.getOrderId());
try {
// 1. 基础风险检查
List<RiskFactor> riskFactors = new ArrayList<>();
// 2. 黑名单检查
BlacklistCheckResult blacklistResult = blacklistService.checkBlacklist(request);
if (blacklistResult.isBlacklisted()) {
riskFactors.add(RiskFactor.builder()
.type(RiskFactorType.BLACKLIST)
.severity(RiskSeverity.HIGH)
.description("用户在黑名单中: " + blacklistResult.getReason())
.score(100)
.build());
}
// 3. 设备指纹检查
DeviceFingerprintResult deviceResult = deviceFingerprintService.analyzeDevice(request);
if (deviceResult.isSuspicious()) {
riskFactors.add(RiskFactor.builder()
.type(RiskFactorType.DEVICE_FINGERPRINT)
.severity(deviceResult.getSeverity())
.description("可疑设备: " + deviceResult.getReason())
.score(deviceResult.getRiskScore())
.build());
}
// 4. 地理位置检查
GeoLocationResult geoResult = geoLocationService.analyzeLocation(request);
if (geoResult.isAnomalous()) {
riskFactors.add(RiskFactor.builder()
.type(RiskFactorType.GEO_LOCATION)
.severity(geoResult.getSeverity())
.description("异常地理位置: " + geoResult.getReason())
.score(geoResult.getRiskScore())
.build());
}
// 5. 交易行为分析
TransactionBehaviorResult behaviorResult = analyzeTransactionBehavior(request);
if (behaviorResult.isAnomalous()) {
riskFactors.add(RiskFactor.builder()
.type(RiskFactorType.TRANSACTION_BEHAVIOR)
.severity(behaviorResult.getSeverity())
.description("异常交易行为: " + behaviorResult.getReason())
.score(behaviorResult.getRiskScore())
.build());
}
// 6. 机器学习模型评分
MLModelResult mlResult = riskModelService.predict(request);
if (mlResult.getRiskScore() > 0.7) {
riskFactors.add(RiskFactor.builder()
.type(RiskFactorType.ML_MODEL)
.severity(RiskSeverity.MEDIUM)
.description("机器学习模型识别为高风险")
.score((int) (mlResult.getRiskScore() * 100))
.build());
}
// 7. 规则引擎评估
RuleEngineResult ruleResult = riskRuleEngine.evaluate(request, riskFactors);
riskFactors.addAll(ruleResult.getAdditionalRiskFactors());
// 8. 计算综合风险评分
int totalRiskScore = calculateTotalRiskScore(riskFactors);
RiskLevel riskLevel = determineRiskLevel(totalRiskScore);
// 9. 生成风险评估结果
RiskAssessmentResult result = RiskAssessmentResult.builder()
.riskLevel(riskLevel)
.riskScore(totalRiskScore)
.riskFactors(riskFactors)
.recommendation(generateRiskRecommendation(riskLevel, riskFactors))
.assessmentTime(Instant.now())
.build();
log.info("风险评估完成: {}, 风险等级: {}, 评分: {}",
request.getOrderId(), riskLevel, totalRiskScore);
return result;
} catch (Exception e) {
log.error("风险评估失败: {}", request.getOrderId(), e);
// 发生异常时返回高风险
return RiskAssessmentResult.builder()
.riskLevel(RiskLevel.HIGH)
.riskScore(100)
.riskFactors(Arrays.asList(
RiskFactor.builder()
.type(RiskFactorType.SYSTEM_ERROR)
.severity(RiskSeverity.HIGH)
.description("风险评估系统异常: " + e.getMessage())
.score(100)
.build()
))
.recommendation(RiskRecommendation.REJECT)
.assessmentTime(Instant.now())
.build();
}
}
/**
* 交易行为分析
*/
private TransactionBehaviorResult analyzeTransactionBehavior(PaymentCreationRequest request) {
List<String> anomalies = new ArrayList<>();
int riskScore = 0;
// 1. 检查交易金额异常
BigDecimal avgAmount = getUserAverageTransactionAmount(request.getUserId());
if (avgAmount != null && request.getAmount().compareTo(avgAmount.multiply(new BigDecimal("5"))) > 0) {
anomalies.add("交易金额异常偏高");
riskScore += 30;
}
// 2. 检查交易频率异常
int recentTransactionCount = getUserRecentTransactionCount(request.getUserId(), Duration.ofHours(1));
if (recentTransactionCount > 10) {
anomalies.add("交易频率异常偏高");
riskScore += 40;
}
// 3. 检查交易时间异常
LocalTime transactionTime = LocalTime.now();
if (transactionTime.isBefore(LocalTime.of(6, 0)) || transactionTime.isAfter(LocalTime.of(23, 0))) {
anomalies.add("非正常交易时间");
riskScore += 20;
}
// 4. 检查新用户大额交易
if (isNewUser(request.getUserId()) && request.getAmount().compareTo(new BigDecimal("1000")) > 0) {
anomalies.add("新用户大额交易");
riskScore += 50;
}
RiskSeverity severity = riskScore > 70 ? RiskSeverity.HIGH :
riskScore > 40 ? RiskSeverity.MEDIUM : RiskSeverity.LOW;
return TransactionBehaviorResult.builder()
.isAnomalous(!anomalies.isEmpty())
.reason(String.join(", ", anomalies))
.riskScore(riskScore)
.severity(severity)
.build();
}
/**
* 计算总风险评分
*/
private int calculateTotalRiskScore(List<RiskFactor> riskFactors) {
if (riskFactors.isEmpty()) {
return 0;
}
// 使用加权平均算法,高严重性的风险因子权重更大
double totalWeightedScore = 0.0;
double totalWeight = 0.0;
for (RiskFactor factor : riskFactors) {
double weight = getFactorWeight(factor.getSeverity());
totalWeightedScore += factor.getScore() * weight;
totalWeight += weight;
}
return totalWeight > 0 ? (int) (totalWeightedScore / totalWeight) : 0;
}
/**
* 获取风险因子权重
*/
private double getFactorWeight(RiskSeverity severity) {
switch (severity) {
case HIGH:
return 3.0;
case MEDIUM:
return 2.0;
case LOW:
return 1.0;
default:
return 1.0;
}
}
/**
* 确定风险等级
*/
private RiskLevel determineRiskLevel(int riskScore) {
if (riskScore >= 80) {
return RiskLevel.HIGH;
} else if (riskScore >= 50) {
return RiskLevel.MEDIUM;
} else {
return RiskLevel.LOW;
}
}
/**
* 生成风险建议
*/
private RiskRecommendation generateRiskRecommendation(RiskLevel riskLevel, List<RiskFactor> riskFactors) {
switch (riskLevel) {
case HIGH:
return RiskRecommendation.REJECT;
case MEDIUM:
// 检查是否有高严重性的风险因子
boolean hasHighSeverityFactor = riskFactors.stream()
.anyMatch(factor -> factor.getSeverity() == RiskSeverity.HIGH);
return hasHighSeverityFactor ? RiskRecommendation.MANUAL_REVIEW : RiskRecommendation.ADDITIONAL_VERIFICATION;
case LOW:
return RiskRecommendation.APPROVE;
default:
return RiskRecommendation.MANUAL_REVIEW;
}
}
/**
* 获取用户平均交易金额
*/
private BigDecimal getUserAverageTransactionAmount(Long userId) {
// 查询用户最近30天的平均交易金额
// 这里简化实现
return new BigDecimal("500");
}
/**
* 获取用户最近交易次数
*/
private int getUserRecentTransactionCount(Long userId, Duration duration) {
// 查询用户在指定时间内的交易次数
// 这里简化实现
return 3;
}
/**
* 检查是否为新用户
*/
private boolean isNewUser(Long userId) {
// 检查用户注册时间是否在7天内
// 这里简化实现
return false;
}
}