Merge remote-tracking branch 'origin/dev/dev' into dev/dev

This commit is contained in:
shahaibo
2024-04-02 10:15:49 +08:00
16 changed files with 155 additions and 239 deletions

View File

@@ -11,12 +11,12 @@ public class MQConfig {
// public static final String GENERATE_QUEUE = "generate-queue-prod"; // public static final String GENERATE_QUEUE = "generate-queue-prod";
// public static final String GENERATE_QUEUE = "generate-queue-test"; // public static final String GENERATE_QUEUE = "generate-queue-test";
public static final String GENERATE_QUEUE = "generate-queue-dev"; public static final String GENERATE_QUEUE = "generate-queue-dev";
// public static final String GENERATE_QUEUE = "generate-queue"; // public static final String GENERATE_QUEUE = "generate-queue-local";
public static final String SR_QUEUE = "SR-queue-dev"; public static final String SR_QUEUE = "SR-queue-dev";
// public static final String SR_QUEUE = "SR-queue-local"; // public static final String SR_QUEUE = "SR-queue-local";
// public static final String SR_RESULT_QUEUE = "SuperResolution-local"; // public static final String SR_RESULT_QUEUE = "SuperResolution-local";
public static final String SR_RESULT_QUEUE = "SuperResolution-dev"; public static final String SR_RESULT_QUEUE = "SuperResolution-dev";
public MQConfig() { public MQConfig() {

View File

@@ -0,0 +1,10 @@
package com.ai.da.common.constant;
public class CommonConstant {
// 单位 秒 一天过期
public static final Long TASK_EXPIRE_TIME = 24 * 60 * 60L;
// 单位 秒 两天过期
public static final Long CREDITS_EXPIRE_TIME = 2 * 24 * 60 * 60L;
// 单位 分钟
public static final Integer MINIO_IMAGE_EXPIRE_TIME = 24 * 60;
}

View File

@@ -2,9 +2,6 @@ package com.ai.da.common.constant;
public class PayPalCheckoutConstant { public class PayPalCheckoutConstant {
// public static String MODE = "sandbox";
public static String MODE = "live";
public static final String CAPTURE = "CAPTURE"; public static final String CAPTURE = "CAPTURE";
/** /**
* 该标签将覆盖PayPal网站上PayPal帐户中的公司名称 * 该标签将覆盖PayPal网站上PayPal帐户中的公司名称
@@ -168,12 +165,6 @@ public class PayPalCheckoutConstant {
public final static String CMD_NOTIFY_VALIDATE = "_notify-validate"; public final static String CMD_NOTIFY_VALIDATE = "_notify-validate";
// public final static String WEBHOOK_ID = "31797347YC028794L";
// kim-sandbox
// public final static String WEBHOOK_ID = "1WH327112B602422N";
// kim-live
public final static String WEBHOOK_ID = "41L14847MC833625B";
public final static String PAYPAL_TOKEN_KEY = "PayPalAccessToken"; public final static String PAYPAL_TOKEN_KEY = "PayPalAccessToken";

View File

@@ -9,7 +9,7 @@ public enum CreditsEventsEnum {
PRICE("price","1"), PRICE("price","1"),
// 6USD -> 1000 points ==> 10HKD -> 215 points ==> 2HKD -> 43points // 6USD -> 1000 points ==> 10HKD -> 215 points ==> 2HKD -> 43points
BUY_CREDITS("Buy Credits","43"), BUY_CREDITS("Buy Credits","50"),
INIT("init", "1000"), INIT("init", "1000"),

View File

@@ -136,6 +136,10 @@ public class RedisUtil {
} }
//- - - - - - - - - - - - - - - - - - - - - String类型 - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - String类型 - - - - - - - - - - - - - - - - - - - -
public void addToString(String key, String value){
redisTemplate.opsForValue().set(key,value);
}
public void addToString(String key, String value, Long expiresIn){ public void addToString(String key, String value, Long expiresIn){
redisTemplate.opsForValue().set(key,value,expiresIn, TimeUnit.SECONDS); redisTemplate.opsForValue().set(key,value,expiresIn, TimeUnit.SECONDS);
} }
@@ -156,4 +160,8 @@ public class RedisUtil {
return redisTemplate.getExpire(key); return redisTemplate.getExpire(key);
} }
public void removeFromString(String key){
redisTemplate.delete(key);
}
} }

View File

@@ -1,7 +1,6 @@
package com.ai.da.controller; package com.ai.da.controller;
import com.ai.da.common.response.Response; import com.ai.da.common.response.Response;
import com.ai.da.service.CallBackService;
import com.ai.da.service.PayPalCheckoutService; import com.ai.da.service.PayPalCheckoutService;
import com.paypal.http.HttpResponse; import com.paypal.http.HttpResponse;
import com.paypal.http.exceptions.SerializeException; import com.paypal.http.exceptions.SerializeException;
@@ -61,7 +60,6 @@ public class PayPalCheckoutController {
}else { }else {
return Response.fail("Request for refund failed."); return Response.fail("Request for refund failed.");
} }
} }
@ApiOperation("执行扣款") @ApiOperation("执行扣款")
@@ -70,8 +68,5 @@ public class PayPalCheckoutController {
Order response = payPalCheckoutService.captureOrder(orderNo); Order response = payPalCheckoutService.captureOrder(orderNo);
return Response.success(response); return Response.success(response);
} }
} }

View File

@@ -10,4 +10,6 @@ public class Product extends BaseEntity{
private String title; //商品名称 private String title; //商品名称
private Integer price; //价格(分) private Integer price; //价格(分)
private Integer credits; // 积分
} }

View File

@@ -1,12 +0,0 @@
package com.ai.da.service;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public interface CallBackService {
Boolean doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException;
}

View File

@@ -26,4 +26,8 @@ public interface CreditsService extends IService<CreditsDetail> {
PageBaseResponse<CreditsDetail> queryCreditsDetailsPage(QueryIncomeOrExpenditureDTO queryPageByTimeDTO); PageBaseResponse<CreditsDetail> queryCreditsDetailsPage(QueryIncomeOrExpenditureDTO queryPageByTimeDTO);
Boolean checkCredits(Long accountId, CreditsEventsEnum event, Integer num); Boolean checkCredits(Long accountId, CreditsEventsEnum event, Integer num);
Boolean creditsPreDeduction(CreditsEventsEnum event, Integer num);
void taskCreditsDeduction(Long accountId, String taskId);
} }

View File

@@ -1,159 +0,0 @@
package com.ai.da.service.impl;
import com.ai.da.common.config.PayPalClient;
import com.ai.da.common.constant.PayPalCheckoutConstant;
import com.ai.da.common.utils.paypalRequest.WebhookVerifyRequest;
import com.ai.da.service.CallBackService;
import com.ai.da.service.PayPalCheckoutService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.paypal.api.payments.Event;
import com.paypal.base.Constants;
import com.paypal.base.SDKUtil;
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.PayPalRESTException;
import com.paypal.http.HttpResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import static com.ai.da.common.constant.PayPalCheckoutConstant.MODE;
// #Validate Webhook Sample
//
// This sample code demonstrates how to validate a webhook received on your
// web server. This sample assumes that you use the java servlet, which returns
// the HttpServletRequest object. However, you can modify this code to
// your specific case.
//
@Slf4j
@Service
public class CallBackServiceImpl implements CallBackService {
@Value("${paypal.client-id}")
private String clientId;
@Value("${paypal.client-secret}")
private String clientSecret;
@Resource
private PayPalClient payPalClient;
@Resource
private PayPalCheckoutService payPalCheckoutService;
@Override
public Boolean doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
return doPost(req, resp);
}
// ##Validate Webhook
protected Boolean doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try {
String body = getBody(req);
Map webhookEvent = new ObjectMapper().readValue(body, Map.class);
HashMap<String, Object> webhookRequest = new HashMap<>();
webhookRequest.put("auth_algo",SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-AUTH-ALGO"));
webhookRequest.put("cert_url",SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-CERT-URL"));
webhookRequest.put("transmission_id",SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-TRANSMISSION-ID"));
webhookRequest.put("transmission_sig",SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-TRANSMISSION-SIG"));
webhookRequest.put("transmission_time",SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-TRANSMISSION-TIME"));
webhookRequest.put("webhook_id",PayPalCheckoutConstant.WEBHOOK_ID);
webhookRequest.put("webhook_event",webhookEvent);
WebhookVerifyRequest webhookVerifyRequest = new WebhookVerifyRequest();
webhookVerifyRequest.authorization(payPalCheckoutService.getOAuth());
webhookVerifyRequest.requestBody(webhookRequest);
// 验签
HttpResponse<HashMap> verified = payPalClient.client(MODE, clientId, clientSecret).execute(webhookVerifyRequest);
boolean verifyResult = verified.result().get("verification_status").toString().equals("SUCCESS");
if (verifyResult){
// ### Api Context
APIContext apiContext = new APIContext(clientId, clientSecret, PayPalCheckoutConstant.MODE);
// Set the webhookId that you received when you created this webhook.
apiContext.addConfiguration(Constants.PAYPAL_WEBHOOK_ID, PayPalCheckoutConstant.WEBHOOK_ID);
Boolean result = Event.validateReceivedEvent(apiContext, getHeadersInfo(
req), body);
log.info("Webhook Validated: " + result);
if (result){
// 处理订单数据
LinkedHashMap<String,LinkedHashMap<String,String>> webhookEventMap = (LinkedHashMap<String,LinkedHashMap<String,String>>) webhookEvent;
String orderId = webhookEventMap.get("resource").get("id");
payPalCheckoutService.processOrder(orderId);
return Boolean.TRUE;
}
}
} catch (PayPalRESTException | InvalidKeyException | NoSuchAlgorithmException | SignatureException e) {
log.error(e.getMessage());
}
return Boolean.FALSE;
}
// Simple helper method to help you extract the headers from HttpServletRequest object.
private static Map<String, String> getHeadersInfo(HttpServletRequest request) {
Map<String, String> map = new HashMap<String, String>();
@SuppressWarnings("rawtypes")
Enumeration headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String key = (String) headerNames.nextElement();
String value = request.getHeader(key);
map.put(key, value);
}
return map;
}
// Simple helper method to fetch request data as a string from HttpServletRequest object.
private static String getBody(HttpServletRequest request) throws IOException {
String body;
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
body = stringBuilder.toString();
log.info("回调参数 ===> {}", body);
return body;
}
}

View File

@@ -4,6 +4,7 @@ import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.context.UserContext; import com.ai.da.common.context.UserContext;
import com.ai.da.common.enums.CreditsEventsEnum; import com.ai.da.common.enums.CreditsEventsEnum;
import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.mapper.primary.AccountMapper; import com.ai.da.mapper.primary.AccountMapper;
import com.ai.da.mapper.primary.CreditsDetailMapper; import com.ai.da.mapper.primary.CreditsDetailMapper;
import com.ai.da.mapper.primary.entity.Account; import com.ai.da.mapper.primary.entity.Account;
@@ -15,23 +16,31 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.netty.util.internal.StringUtil; import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
@Service @Service
public class CreditsServiceImpl extends ServiceImpl<CreditsDetailMapper, CreditsDetail> implements CreditsService { public class CreditsServiceImpl extends ServiceImpl<CreditsDetailMapper, CreditsDetail> implements CreditsService {
@Resource @Value("${redis.key.credits.pre-deduction}")
private AccountService accountService; private String creditsDeduction;
@Resource
private AccountService accountService;
@Resource @Resource
private AccountMapper accountMapper; private AccountMapper accountMapper;
@Resource
private RedisUtil redisUtil;
@Override @Override
public void initCredits() { public void initCredits() {
@@ -116,20 +125,20 @@ public class CreditsServiceImpl extends ServiceImpl<CreditsDetailMapper, Credits
public void insertToCreditsDetail(Long accountId, String changeEvent, String credits, String changeType) { public void insertToCreditsDetail(Long accountId, String changeEvent, String credits, String changeType) {
CreditsDetail creditsDetail = new CreditsDetail(); CreditsDetail creditsDetail = new CreditsDetail();
Account account = accountMapper.selectById(accountId); Account account = accountMapper.selectById(accountId);
// BigDecimal finalCredits; BigDecimal finalCredits;
String changeCredits; String changeCredits;
if ("positive".equals(changeType)) { if ("positive".equals(changeType)) {
// finalCredits = account.getCredits().add(new BigDecimal(credits)); finalCredits = account.getCredits().add(new BigDecimal(credits));
changeCredits = "+" + credits; changeCredits = "+" + credits;
} else { } else {
// finalCredits = account.getCredits().subtract(new BigDecimal(credits)); finalCredits = account.getCredits().subtract(new BigDecimal(credits));
changeCredits = "-" + credits; changeCredits = "-" + credits;
} }
creditsDetail.setAccountId(accountId); creditsDetail.setAccountId(accountId);
creditsDetail.setChangeEvent(changeEvent); creditsDetail.setChangeEvent(changeEvent);
creditsDetail.setChangedCredits(changeCredits); creditsDetail.setChangedCredits(changeCredits);
// creditsDetail.setCredits(finalCredits); creditsDetail.setCredits(finalCredits);
creditsDetail.setCredits(account.getCredits()); // creditsDetail.setCredits(account.getCredits());
creditsDetail.setCreateTime(LocalDateTime.now()); creditsDetail.setCreateTime(LocalDateTime.now());
baseMapper.insert(creditsDetail); baseMapper.insert(creditsDetail);
@@ -179,4 +188,59 @@ public class CreditsServiceImpl extends ServiceImpl<CreditsDetailMapper, Credits
} }
return Boolean.TRUE; return Boolean.TRUE;
} }
/*
* 积分扣除升级 -- 预扣积分
* 思路:
* 1、先判断当前积分扣除待扣积分后剩余积分够不够当前操作需要的积分
* 2、将需要进行积分扣除操作请求的 任务id和需要扣除的积分存到redis
* 3、执行成功后从redis中拿出当前任务id对应需要扣除的积分扣除积分更新数据库积分移除redis的记录
* 4、执行失败直接移除记录
*/
/** 积分预扣除 */
public Boolean creditsPreDeduction(CreditsEventsEnum event, Integer num){
Long accountId = UserContext.getUserHolder().getId();
// 1、获取当前需要预扣除的积分
Set<String> keys = redisUtil.getKeysFromString(creditsDeduction + ":" + accountId + ":*");
List<String> multiValue = redisUtil.getMultiValue(keys);
int sum = multiValue.stream().mapToInt(Integer::parseInt).sum();
sum += Integer.parseInt(event.getValue()) * num;
// 2、获取当前积分
BigDecimal existingCredits = accountMapper.selectById(accountId).getCredits();
BigDecimal subtract = existingCredits.subtract(new BigDecimal(sum));
// 3、判断剩余积分是否够本次操作
if (subtract.compareTo(BigDecimal.ZERO) < 0){
// 3.1 不够,直接返回余额不够,充值
return Boolean.FALSE;
}
return Boolean.TRUE;
}
/** 执行扣除积分,更新数据库 */
@Override
@Transactional(rollbackFor = Exception.class)
public void taskCreditsDeduction(Long accountId, String taskId){
String key = creditsDeduction + ":" + accountId + ":" + taskId;
// 1、获取当前任务id对应的积分
String value = redisUtil.getFromString(key);
// 1.1 没有。返回,报错,未找到当前任务
if (StringUtil.isNullOrEmpty(value)){
throw new BusinessException("当前任务不存在,无法扣除积分");
}
// 2、操作数据库扣除积分
BigDecimal existingCredits = accountMapper.selectById(accountId).getCredits();
BigDecimal subtract = existingCredits.subtract(new BigDecimal(value));
accountService.updateCredits(accountId, subtract.toString());
// 3、从redis中移除当前待扣积分
redisUtil.removeFromString(key);
}
} }

View File

@@ -62,6 +62,12 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
@Value("${paypal.client-secret}") @Value("${paypal.client-secret}")
private String clientSecret; private String clientSecret;
@Value("${paypal.mode}")
private String mode;
@Value("${paypal.webhook_id}")
private String webhookId;
@Resource @Resource
private PayPalClient payPalClient; private PayPalClient payPalClient;
@Resource @Resource
@@ -90,7 +96,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
request.requestBody(buildRequestBody(String.valueOf(orderInfo.getTotalFee()), returnUrl)); request.requestBody(buildRequestBody(String.valueOf(orderInfo.getTotalFee()), returnUrl));
HttpResponse<Order> response = null; HttpResponse<Order> response = null;
try { try {
response = payPalClient.client(MODE, clientId, clientSecret).execute(request); response = payPalClient.client(mode, clientId, clientSecret).execute(request);
} catch (Exception e) { } catch (Exception e) {
log.error("调用paypal订单创建失败失败原因 ===> {}", e.getMessage()); log.error("调用paypal订单创建失败失败原因 ===> {}", e.getMessage());
throw new BusinessException("Order creation failed"); throw new BusinessException("Order creation failed");
@@ -136,21 +142,21 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
webhookRequest.put("transmission_id", SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-TRANSMISSION-ID")); webhookRequest.put("transmission_id", SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-TRANSMISSION-ID"));
webhookRequest.put("transmission_sig", SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-TRANSMISSION-SIG")); webhookRequest.put("transmission_sig", SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-TRANSMISSION-SIG"));
webhookRequest.put("transmission_time", SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-TRANSMISSION-TIME")); webhookRequest.put("transmission_time", SDKUtil.validateAndGet(getHeadersInfo(req), "PAYPAL-TRANSMISSION-TIME"));
webhookRequest.put("webhook_id", PayPalCheckoutConstant.WEBHOOK_ID); webhookRequest.put("webhook_id", webhookId);
webhookRequest.put("webhook_event", webhookEvent); webhookRequest.put("webhook_event", webhookEvent);
WebhookVerifyRequest webhookVerifyRequest = new WebhookVerifyRequest(); WebhookVerifyRequest webhookVerifyRequest = new WebhookVerifyRequest();
webhookVerifyRequest.authorization(getOAuth()); webhookVerifyRequest.authorization(getOAuth());
webhookVerifyRequest.requestBody(webhookRequest); webhookVerifyRequest.requestBody(webhookRequest);
// 验签 // 验签
HttpResponse<HashMap> verified = payPalClient.client(MODE, clientId, clientSecret).execute(webhookVerifyRequest); HttpResponse<HashMap> verified = payPalClient.client(mode, clientId, clientSecret).execute(webhookVerifyRequest);
boolean verifyResult = verified.result().get("verification_status").toString().equals("SUCCESS"); boolean verifyResult = verified.result().get("verification_status").toString().equals("SUCCESS");
if (verifyResult) { if (verifyResult) {
// ### Api Context // ### Api Context
APIContext apiContext = new APIContext(clientId, clientSecret, PayPalCheckoutConstant.MODE); APIContext apiContext = new APIContext(clientId, clientSecret, mode);
// Set the webhookId that you received when you created this webhook. // Set the webhookId that you received when you created this webhook.
apiContext.addConfiguration(Constants.PAYPAL_WEBHOOK_ID, PayPalCheckoutConstant.WEBHOOK_ID); apiContext.addConfiguration(Constants.PAYPAL_WEBHOOK_ID, webhookId);
Boolean result = Event.validateReceivedEvent(apiContext, getHeadersInfo( Boolean result = Event.validateReceivedEvent(apiContext, getHeadersInfo(
req), body); req), body);
log.info("Webhook Validated: " + result); log.info("Webhook Validated: " + result);
@@ -328,7 +334,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
HttpResponse<Order> response = null; HttpResponse<Order> response = null;
try { try {
response = payPalClient.client(MODE, clientId, clientSecret).execute(request); response = payPalClient.client(mode, clientId, clientSecret).execute(request);
} catch (Exception e) { } catch (Exception e) {
log.error("paypal订单查询失败失败原因 ===> {}", e.getMessage()); log.error("paypal订单查询失败失败原因 ===> {}", e.getMessage());
} }
@@ -371,7 +377,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
HttpResponse<Order> response; HttpResponse<Order> response;
try { try {
response = payPalClient.client(MODE, clientId, clientSecret).execute(request); response = payPalClient.client(mode, clientId, clientSecret).execute(request);
} catch (Exception e) { } catch (Exception e) {
log.error("调用paypal扣款失败失败原因 ===> {}", e.getMessage()); log.error("调用paypal扣款失败失败原因 ===> {}", e.getMessage());
throw new BusinessException("Order deduction failed."); throw new BusinessException("Order deduction failed.");
@@ -421,7 +427,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
public String queryCapture(String orderNo) throws IOException { public String queryCapture(String orderNo) throws IOException {
CapturesGetRequest request = new CapturesGetRequest("扣款id CaptureOrder生成"); CapturesGetRequest request = new CapturesGetRequest("扣款id CaptureOrder生成");
HttpResponse<com.paypal.payments.Capture> response = payPalClient.client(MODE, clientId, clientSecret).execute(request); HttpResponse<com.paypal.payments.Capture> response = payPalClient.client(mode, clientId, clientSecret).execute(request);
System.out.println("Status Code: " + response.statusCode()); System.out.println("Status Code: " + response.statusCode());
System.out.println("Status: " + response.result().status()); System.out.println("Status: " + response.result().status());
System.out.println("Capture ids: " + response.result().id()); System.out.println("Capture ids: " + response.result().id());
@@ -449,7 +455,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
ordersGetRequest.authorization("Bearer " + getOAuth()); ordersGetRequest.authorization("Bearer " + getOAuth());
boolean result; boolean result;
try { try {
ordersGetResponse = payPalClient.client(MODE, clientId, clientSecret).execute(ordersGetRequest); ordersGetResponse = payPalClient.client(mode, clientId, clientSecret).execute(ordersGetRequest);
} catch (Exception e) { } catch (Exception e) {
log.error("调用paypal订单查询失败失败原因 ===> {}", e.getMessage()); log.error("调用paypal订单查询失败失败原因 ===> {}", e.getMessage());
throw new BusinessException("Order query failed"); throw new BusinessException("Order query failed");
@@ -463,7 +469,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
request.requestBody(buildRefundRequestBody(String.valueOf(orderInfo.getTotalFee()), reason)); request.requestBody(buildRefundRequestBody(String.valueOf(orderInfo.getTotalFee()), reason));
HttpResponse<com.paypal.payments.Refund> response = null; HttpResponse<com.paypal.payments.Refund> response = null;
try { try {
response = payPalClient.client(MODE, clientId, clientSecret).execute(request); response = payPalClient.client(mode, clientId, clientSecret).execute(request);
} catch (IOException e) { } catch (IOException e) {
log.error("调用paypal退款申请失败失败原因 {}", e.getMessage()); log.error("调用paypal退款申请失败失败原因 {}", e.getMessage());
throw new BusinessException("Request for refund failed"); throw new BusinessException("Request for refund failed");
@@ -529,7 +535,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
*/ */
public String queryRefund(String orderNo) throws IOException { public String queryRefund(String orderNo) throws IOException {
RefundsGetRequest request = new RefundsGetRequest("退款id RefundOrder生成"); RefundsGetRequest request = new RefundsGetRequest("退款id RefundOrder生成");
HttpResponse<com.paypal.payments.Refund> response = payPalClient.client(MODE, clientId, clientSecret).execute(request); HttpResponse<com.paypal.payments.Refund> response = payPalClient.client(mode, clientId, clientSecret).execute(request);
System.out.println("Status Code: " + response.statusCode()); System.out.println("Status Code: " + response.statusCode());
System.out.println("Status: " + response.result().status()); System.out.println("Status: " + response.result().status());
System.out.println("Refund Id: " + response.result().id()); System.out.println("Refund Id: " + response.result().id());
@@ -554,7 +560,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
AuthenticationRequest authenticationRequest = new AuthenticationRequest(); AuthenticationRequest authenticationRequest = new AuthenticationRequest();
authenticationRequest.authorization(clientId, clientSecret); authenticationRequest.authorization(clientId, clientSecret);
try { try {
HttpResponse<HashMap> authResult = payPalClient.client(MODE, clientId, clientSecret).execute(authenticationRequest); HttpResponse<HashMap> authResult = payPalClient.client(mode, clientId, clientSecret).execute(authenticationRequest);
String accessToken = authResult.result().get("access_token").toString(); String accessToken = authResult.result().get("access_token").toString();
long expiresIn = Long.parseLong(authResult.result().get("expires_in").toString()); long expiresIn = Long.parseLong(authResult.result().get("expires_in").toString());
// 3、存redis // 3、存redis

View File

@@ -1,6 +1,7 @@
package com.ai.da.service.impl; package com.ai.da.service.impl;
import com.ai.da.common.config.exception.BusinessException; import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.context.UserContext; import com.ai.da.common.context.UserContext;
import com.ai.da.common.enums.CreditsEventsEnum; import com.ai.da.common.enums.CreditsEventsEnum;
import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.PageBaseResponse;
@@ -65,25 +66,24 @@ public class SuperResolutionServiceImpl extends ServiceImpl<TaskListMapper, Task
@Value("${minio.endpoint}") @Value("${minio.endpoint}")
private String endpoint; private String endpoint;
@Value("${redis.key.credits.pre-deduction}")
private String creditsDeduction;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public List<String> prepareForSR(List<SuperResolutionDTO> superResolutionDTOList) { public List<String> prepareForSR(List<SuperResolutionDTO> superResolutionDTOList) {
Long accountId = UserContext.getUserHolder().getId(); Long accountId = UserContext.getUserHolder().getId();
// 1、判断用户当前积分是否够本次超分消耗 // 1、判断用户当前积分是否够本次超分消耗
Boolean preDeduction = creditsService.creditsPreDeduction(CreditsEventsEnum.SUPER_RESOLUTION, superResolutionDTOList.size());
Boolean credits = creditsService.checkCredits(accountId, CreditsEventsEnum.SUPER_RESOLUTION, superResolutionDTOList.size()); if (!preDeduction) {
// todo 积分扣除待升级
if (credits) {
// 先扣除积分,后失败后再加上
creditsService.creditsDecrease(accountId, CreditsEventsEnum.SUPER_RESOLUTION.getName());
} else {
throw new BusinessException("Not enough Credits"); throw new BusinessException("Not enough Credits");
} }
ArrayList<String> uuidList = new ArrayList<>(); ArrayList<String> uuidList = new ArrayList<>();
for (SuperResolutionDTO superResolutionDTO : superResolutionDTOList) { for (SuperResolutionDTO superResolutionDTO : superResolutionDTOList) {
// todo 校验倍率是否是2的幂次(前端已做)
// 2、生成唯一id 使用uuid // 2、生成唯一id 使用uuid
String uuid = UUID.randomUUID().toString(); String uuid = UUID.randomUUID().toString();
int num = 1; int num = 1;
@@ -119,17 +119,20 @@ public class SuperResolutionServiceImpl extends ServiceImpl<TaskListMapper, Task
baseMapper.insert(taskList); baseMapper.insert(taskList);
// 5、加入任务列表 设置状态为 等待中 // 5、添加当前任务的预扣积分到redis 任务有效期一天,若待扣积分两天还没被移除,说明任务已经失败,待扣积分自动失效
redisUtil.addToString(creditsDeduction + ":" + accountId + ":" + uuid, CreditsEventsEnum.SUPER_RESOLUTION.getValue(), CommonConstant.CREDITS_EXPIRE_TIME);
// 6、加入任务列表 设置状态为 等待中
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String name = superResolutionDTO.getImages(); String name = superResolutionDTO.getImages();
taskListService.addToTaskListRedis(new TaskDTO<>(uuid, "SR", name.substring(name.lastIndexOf("/") + 1), superResolutionDTO, "Waiting", LocalDateTime.now().format(dateTimeFormatter))); taskListService.addToTaskListRedis(new TaskDTO<>(uuid, "SR", name.substring(name.lastIndexOf("/") + 1), superResolutionDTO, "Waiting", LocalDateTime.now().format(dateTimeFormatter)));
// 6、将消息发布到MQ消息队列 // 7、将消息发布到MQ消息队列
log.info("发送消息到SR_QUEUE参数 {}", jsonString); log.info("发送消息到SR_QUEUE参数 {}", jsonString);
rabbitMQService.publishMessageToSR(jsonString); rabbitMQService.publishMessageToSR(jsonString);
} }
// 6、返回唯一id列表 // 8、返回唯一id列表
return uuidList; return uuidList;
} }
@@ -156,9 +159,8 @@ public class SuperResolutionServiceImpl extends ServiceImpl<TaskListMapper, Task
CreditsEventsEnum.SUPER_RESOLUTION.getName(), CreditsEventsEnum.SUPER_RESOLUTION.getName(),
CreditsEventsEnum.SUPER_RESOLUTION.getValue(), CreditsEventsEnum.SUPER_RESOLUTION.getValue(),
"negative"); "negative");
} else { // 4、扣除积分
// 将之前扣除的积分返还 creditsService.taskCreditsDeduction(accountId, taskId);
creditsService.creditsIncrease(accountId, CreditsEventsEnum.SUPER_RESOLUTION.getName());
} }
} }

View File

@@ -1,5 +1,6 @@
package com.ai.da.service.impl; package com.ai.da.service.impl;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.context.UserContext; import com.ai.da.common.context.UserContext;
import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.utils.MinioUtil; import com.ai.da.common.utils.MinioUtil;
@@ -61,8 +62,8 @@ public class TaskListServiceImpl extends ServiceImpl<TaskListMapper, TaskList> i
taskDTOS.add(new TaskDTO<>()); taskDTOS.add(new TaskDTO<>());
} else { } else {
SuperResolutionDTO inputParam = taskDTO.getInputParam(); SuperResolutionDTO inputParam = taskDTO.getInputParam();
inputParam.setImages(minioUtil.getPresignedUrl(inputParam.getImages(), 24 * 60)); inputParam.setImages(minioUtil.getPresignedUrl(inputParam.getImages(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
taskDTO.setOutputImage(StringUtil.isNullOrEmpty(taskDTO.getOutputImage()) ? null : minioUtil.getPresignedUrl(taskDTO.getOutputImage(), 24 * 60)); taskDTO.setOutputImage(StringUtil.isNullOrEmpty(taskDTO.getOutputImage()) ? null : minioUtil.getPresignedUrl(taskDTO.getOutputImage(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
taskDTOS.add(taskDTO); taskDTOS.add(taskDTO);
} }
}); });
@@ -71,7 +72,7 @@ public class TaskListServiceImpl extends ServiceImpl<TaskListMapper, TaskList> i
public void addToTaskListRedis(TaskDTO<SuperResolutionDTO> taskDTO) { public void addToTaskListRedis(TaskDTO<SuperResolutionDTO> taskDTO) {
String key = taskListKey + ":" + UserContext.getUserHolder().getId() + ":" + taskDTO.getTaskId(); String key = taskListKey + ":" + UserContext.getUserHolder().getId() + ":" + taskDTO.getTaskId();
redisUtil.addToString(key, new Gson().toJson(taskDTO), 24L * 60 * 60 * 3); redisUtil.addToString(key, new Gson().toJson(taskDTO), CommonConstant.TASK_EXPIRE_TIME);
} }
// 3、更新任务状态 // 3、更新任务状态
@@ -104,8 +105,8 @@ public class TaskListServiceImpl extends ServiceImpl<TaskListMapper, TaskList> i
// 成功失败的都返回 // 成功失败的都返回
TaskVO task = new TaskVO(); TaskVO task = new TaskVO();
task.setImageName(s.getInputUrl().substring(s.getInputUrl().lastIndexOf("/") + 1)); task.setImageName(s.getInputUrl().substring(s.getInputUrl().lastIndexOf("/") + 1));
task.setInputImage(minioUtil.getPresignedUrl(s.getInputUrl(), 24 * 60)); task.setInputImage(minioUtil.getPresignedUrl(s.getInputUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
task.setOutputImage(StringUtil.isNullOrEmpty(s.getOutputUrl()) ? null : minioUtil.getPresignedUrl(s.getOutputUrl(), 24 * 60)); task.setOutputImage(StringUtil.isNullOrEmpty(s.getOutputUrl()) ? null : minioUtil.getPresignedUrl(s.getOutputUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
task.setStatus(s.getStatus()); task.setStatus(s.getStatus());
task.setTaskId(s.getTaskId()); task.setTaskId(s.getTaskId());
task.setCreateDate(s.getCreateTime().format(dateTimeFormatter)); task.setCreateDate(s.getCreateTime().format(dateTimeFormatter));

View File

@@ -82,4 +82,5 @@ redis.key.resultMap=ResultMap
redis.key.orderForSR=OrderForSR redis.key.orderForSR=OrderForSR
redis.key.SRCancelSet=SRCancelSet redis.key.SRCancelSet=SRCancelSet
redis.key.SRExceptionMap=SRExceptionMap redis.key.SRExceptionMap=SRExceptionMap
redis.key.taskList=TaskList redis.key.taskList=TaskList
redis.key.credits.pre-deduction=Credits:PreDeduction

View File

@@ -1,20 +1,23 @@
# developer-sandbox # developer-sandbox-xp
#paypal.client-id=ATbaebYi7-GXWRWJqwRLYMzKEbwjh4BFRqD4Y13i4lZq0rplWIM_IpPrtPKpdkAt_KrPXd6IJTwsDqa5 paypal.client-id=ATbaebYi7-GXWRWJqwRLYMzKEbwjh4BFRqD4Y13i4lZq0rplWIM_IpPrtPKpdkAt_KrPXd6IJTwsDqa5
#paypal.client-secret=EHWWJqGmmbfjLXqCUpGrvxRYBPPtWvA3hR5ZaAyHlGSVJiHoQPS8skbNaJ9h39VObnchUbgiY2pPu__s paypal.client-secret=EHWWJqGmmbfjLXqCUpGrvxRYBPPtWvA3hR5ZaAyHlGSVJiHoQPS8skbNaJ9h39VObnchUbgiY2pPu__s
#paypal.receiver.email=sb-ukxfk29608925@business.example.com paypal.receiver.email=sb-ukxfk29608925@business.example.com
#paypal.mode=sandbox paypal.mode=sandbox
# local
#paypal.webhook_id=31797347YC028794L #paypal.webhook_id=31797347YC028794L
# dev
paypal.webhook_id=51V87014T6406322F
# aida-sandbox # aida-sandbox-kim
#paypal.client-id=AbDDH8jnTrKqjnWLFgEu6LogYzVz2ZLuirE4W54t1M4lrofrP5OzXfhbxqktLLFB-rAO9KeYQVYFJ_tO #paypal.client-id=AbDDH8jnTrKqjnWLFgEu6LogYzVz2ZLuirE4W54t1M4lrofrP5OzXfhbxqktLLFB-rAO9KeYQVYFJ_tO
#paypal.client-secret=EOOoiIAe_dyR2YhY7qCIqWipZvYXCDrmBlFYchphuvkPFms1spsBGTlStlrx580y4hN-EukWwF9m_LAs #paypal.client-secret=EOOoiIAe_dyR2YhY7qCIqWipZvYXCDrmBlFYchphuvkPFms1spsBGTlStlrx580y4hN-EukWwF9m_LAs
#paypal.receiver.email=sb-4xe8i29784722@business.example.com #paypal.receiver.email=sb-4xe8i29784722@business.example.com
#paypal.mode=sandbox #paypal.mode=sandbox
#paypal.webhook_id=1WH327112B602422N #paypal.webhook_id=1WH327112B602422N
# aida-live # aida-live-kim
paypal.client-id=ASWSIZ3MXJU5w5VOeOHeigWcSw6iinl30ZCipruziKpHclxP0ryf8-7VKG1Ba2VwZwa2DMvGEzTfCTgz #paypal.client-id=ASWSIZ3MXJU5w5VOeOHeigWcSw6iinl30ZCipruziKpHclxP0ryf8-7VKG1Ba2VwZwa2DMvGEzTfCTgz
paypal.client-secret=EHQg_K5PSqmp4FJlzEcOEH_kFkmq4aBzaI7jridw53L6cOQRULBAnfv2KakRfrsqaU1PDSkO4Co9Vyxc #paypal.client-secret=EHQg_K5PSqmp4FJlzEcOEH_kFkmq4aBzaI7jridw53L6cOQRULBAnfv2KakRfrsqaU1PDSkO4Co9Vyxc
paypal.receiver.email=kimwong@code-create.com.hk #paypal.receiver.email=kimwong@code-create.com.hk
paypal.mode=live #paypal.mode=live
paypal.webhook_id=41L14847MC833625B #paypal.webhook_id=41L14847MC833625B