diff --git a/src/main/java/com/ai/da/common/RabbitMQ/MQConfig.java b/src/main/java/com/ai/da/common/RabbitMQ/MQConfig.java index 79ecda25..78e6fc25 100644 --- a/src/main/java/com/ai/da/common/RabbitMQ/MQConfig.java +++ b/src/main/java/com/ai/da/common/RabbitMQ/MQConfig.java @@ -10,14 +10,14 @@ public class MQConfig { public static final String GENERATE_EXCHANGE_FANOUT = "generate-exchange"; // 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-dev"; -// public static final String GENERATE_QUEUE = "generate-queue"; +// public static final String GENERATE_QUEUE = "generate-queue-dev"; + 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-local"; +// public static final String SR_QUEUE = "SR-queue-dev"; + 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-dev"; + public static final String SR_RESULT_QUEUE = "SuperResolution-local"; +// public static final String SR_RESULT_QUEUE = "SuperResolution-dev"; public MQConfig() { } diff --git a/src/main/java/com/ai/da/common/constant/CommonConstant.java b/src/main/java/com/ai/da/common/constant/CommonConstant.java new file mode 100644 index 00000000..f7ad3b1c --- /dev/null +++ b/src/main/java/com/ai/da/common/constant/CommonConstant.java @@ -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; +} diff --git a/src/main/java/com/ai/da/common/constant/PayPalCheckoutConstant.java b/src/main/java/com/ai/da/common/constant/PayPalCheckoutConstant.java index 31cc4adf..21b3694b 100644 --- a/src/main/java/com/ai/da/common/constant/PayPalCheckoutConstant.java +++ b/src/main/java/com/ai/da/common/constant/PayPalCheckoutConstant.java @@ -2,9 +2,6 @@ package com.ai.da.common.constant; public class PayPalCheckoutConstant { -// public static String MODE = "sandbox"; - public static String MODE = "live"; - public static final String CAPTURE = "CAPTURE"; /** * 该标签将覆盖PayPal网站上PayPal帐户中的公司名称 @@ -168,12 +165,6 @@ public class PayPalCheckoutConstant { 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"; diff --git a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java index 23566466..a244bead 100644 --- a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java +++ b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java @@ -9,7 +9,7 @@ public enum CreditsEventsEnum { PRICE("price","1"), // 6USD -> 1000 points ==> 10HKD -> 215 points ==> 2HKD -> 43points - BUY_CREDITS("Buy Credits","43"), + BUY_CREDITS("Buy Credits","50"), INIT("init", "1000"), diff --git a/src/main/java/com/ai/da/common/utils/RedisUtil.java b/src/main/java/com/ai/da/common/utils/RedisUtil.java index 9fa37738..ef67de8f 100644 --- a/src/main/java/com/ai/da/common/utils/RedisUtil.java +++ b/src/main/java/com/ai/da/common/utils/RedisUtil.java @@ -136,6 +136,10 @@ public class RedisUtil { } //- - - - - - - - - - - - - - - - - - - - - String类型 - - - - - - - - - - - - - - - - - - - - + public void addToString(String key, String value){ + redisTemplate.opsForValue().set(key,value); + } + public void addToString(String key, String value, Long expiresIn){ redisTemplate.opsForValue().set(key,value,expiresIn, TimeUnit.SECONDS); } @@ -156,4 +160,8 @@ public class RedisUtil { return redisTemplate.getExpire(key); } + public void removeFromString(String key){ + redisTemplate.delete(key); + } + } diff --git a/src/main/java/com/ai/da/controller/PayPalCheckoutController.java b/src/main/java/com/ai/da/controller/PayPalCheckoutController.java index 2ed119a7..d1ad9134 100644 --- a/src/main/java/com/ai/da/controller/PayPalCheckoutController.java +++ b/src/main/java/com/ai/da/controller/PayPalCheckoutController.java @@ -1,7 +1,6 @@ package com.ai.da.controller; import com.ai.da.common.response.Response; -import com.ai.da.service.CallBackService; import com.ai.da.service.PayPalCheckoutService; import com.paypal.http.HttpResponse; import com.paypal.http.exceptions.SerializeException; @@ -61,7 +60,6 @@ public class PayPalCheckoutController { }else { return Response.fail("Request for refund failed."); } - } @ApiOperation("执行扣款") @@ -70,8 +68,5 @@ public class PayPalCheckoutController { Order response = payPalCheckoutService.captureOrder(orderNo); return Response.success(response); } - - - } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/Product.java b/src/main/java/com/ai/da/mapper/primary/entity/Product.java index de2df0cf..ddea327e 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/Product.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/Product.java @@ -10,4 +10,6 @@ public class Product extends BaseEntity{ private String title; //商品名称 private Integer price; //价格(分) + + private Integer credits; // 积分 } diff --git a/src/main/java/com/ai/da/service/CreditsService.java b/src/main/java/com/ai/da/service/CreditsService.java index a2947b5b..a9d35d17 100644 --- a/src/main/java/com/ai/da/service/CreditsService.java +++ b/src/main/java/com/ai/da/service/CreditsService.java @@ -26,4 +26,8 @@ public interface CreditsService extends IService { PageBaseResponse queryCreditsDetailsPage(QueryIncomeOrExpenditureDTO queryPageByTimeDTO); Boolean checkCredits(Long accountId, CreditsEventsEnum event, Integer num); + + Boolean creditsPreDeduction(CreditsEventsEnum event, Integer num); + + void taskCreditsDeduction(Long accountId, String taskId); } diff --git a/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java b/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java index 10342ad0..c947ac97 100644 --- a/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java @@ -4,6 +4,7 @@ import com.ai.da.common.config.exception.BusinessException; import com.ai.da.common.context.UserContext; import com.ai.da.common.enums.CreditsEventsEnum; 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.CreditsDetailMapper; 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.service.impl.ServiceImpl; import io.netty.util.internal.StringUtil; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.List; import java.util.Objects; +import java.util.Set; @Service public class CreditsServiceImpl extends ServiceImpl implements CreditsService { - @Resource - private AccountService accountService; + @Value("${redis.key.credits.pre-deduction}") + private String creditsDeduction; + @Resource + private AccountService accountService; @Resource private AccountMapper accountMapper; + @Resource + private RedisUtil redisUtil; @Override public void initCredits() { @@ -116,20 +125,20 @@ public class CreditsServiceImpl extends ServiceImpl keys = redisUtil.getKeysFromString(creditsDeduction + ":" + accountId + ":*"); + List 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); + } + } diff --git a/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java b/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java index bc7c7434..929cb3c5 100644 --- a/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java @@ -62,6 +62,12 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { @Value("${paypal.client-secret}") private String clientSecret; + @Value("${paypal.mode}") + private String mode; + + @Value("${paypal.webhook_id}") + private String webhookId; + @Resource private PayPalClient payPalClient; @Resource @@ -90,7 +96,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { request.requestBody(buildRequestBody(String.valueOf(orderInfo.getTotalFee()), returnUrl)); HttpResponse response = null; try { - response = payPalClient.client(MODE, clientId, clientSecret).execute(request); + response = payPalClient.client(mode, clientId, clientSecret).execute(request); } catch (Exception e) { log.error("调用paypal订单创建失败,失败原因 ===> {}", e.getMessage()); 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_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_id", webhookId); webhookRequest.put("webhook_event", webhookEvent); WebhookVerifyRequest webhookVerifyRequest = new WebhookVerifyRequest(); webhookVerifyRequest.authorization(getOAuth()); webhookVerifyRequest.requestBody(webhookRequest); // 验签 - HttpResponse verified = payPalClient.client(MODE, clientId, clientSecret).execute(webhookVerifyRequest); + HttpResponse 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); + APIContext apiContext = new APIContext(clientId, clientSecret, mode); // 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( req), body); log.info("Webhook Validated: " + result); @@ -328,7 +334,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { HttpResponse response = null; try { - response = payPalClient.client(MODE, clientId, clientSecret).execute(request); + response = payPalClient.client(mode, clientId, clientSecret).execute(request); } catch (Exception e) { log.error("paypal订单查询失败,失败原因 ===> {}", e.getMessage()); } @@ -371,7 +377,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { HttpResponse response; try { - response = payPalClient.client(MODE, clientId, clientSecret).execute(request); + response = payPalClient.client(mode, clientId, clientSecret).execute(request); } catch (Exception e) { log.error("调用paypal扣款失败,失败原因 ===> {}", e.getMessage()); throw new BusinessException("Order deduction failed."); @@ -421,7 +427,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { public String queryCapture(String orderNo) throws IOException { CapturesGetRequest request = new CapturesGetRequest("扣款id, CaptureOrder生成"); - HttpResponse response = payPalClient.client(MODE, clientId, clientSecret).execute(request); + HttpResponse response = payPalClient.client(mode, clientId, clientSecret).execute(request); System.out.println("Status Code: " + response.statusCode()); System.out.println("Status: " + response.result().status()); System.out.println("Capture ids: " + response.result().id()); @@ -449,7 +455,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { ordersGetRequest.authorization("Bearer " + getOAuth()); boolean result; try { - ordersGetResponse = payPalClient.client(MODE, clientId, clientSecret).execute(ordersGetRequest); + ordersGetResponse = payPalClient.client(mode, clientId, clientSecret).execute(ordersGetRequest); } catch (Exception e) { log.error("调用paypal订单查询失败,失败原因 ===> {}", e.getMessage()); throw new BusinessException("Order query failed"); @@ -463,7 +469,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { request.requestBody(buildRefundRequestBody(String.valueOf(orderInfo.getTotalFee()), reason)); HttpResponse response = null; try { - response = payPalClient.client(MODE, clientId, clientSecret).execute(request); + response = payPalClient.client(mode, clientId, clientSecret).execute(request); } catch (IOException e) { log.error("调用paypal退款申请失败,失败原因 {}", e.getMessage()); throw new BusinessException("Request for refund failed"); @@ -529,7 +535,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { */ public String queryRefund(String orderNo) throws IOException { RefundsGetRequest request = new RefundsGetRequest("退款id RefundOrder生成"); - HttpResponse response = payPalClient.client(MODE, clientId, clientSecret).execute(request); + HttpResponse response = payPalClient.client(mode, clientId, clientSecret).execute(request); System.out.println("Status Code: " + response.statusCode()); System.out.println("Status: " + response.result().status()); System.out.println("Refund Id: " + response.result().id()); @@ -554,7 +560,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { AuthenticationRequest authenticationRequest = new AuthenticationRequest(); authenticationRequest.authorization(clientId, clientSecret); try { - HttpResponse authResult = payPalClient.client(MODE, clientId, clientSecret).execute(authenticationRequest); + HttpResponse authResult = payPalClient.client(mode, clientId, clientSecret).execute(authenticationRequest); String accessToken = authResult.result().get("access_token").toString(); long expiresIn = Long.parseLong(authResult.result().get("expires_in").toString()); // 3、存redis diff --git a/src/main/java/com/ai/da/service/impl/SuperResolutionServiceImpl.java b/src/main/java/com/ai/da/service/impl/SuperResolutionServiceImpl.java index c9ecdec7..eeb565e8 100644 --- a/src/main/java/com/ai/da/service/impl/SuperResolutionServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/SuperResolutionServiceImpl.java @@ -1,6 +1,7 @@ package com.ai.da.service.impl; 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.enums.CreditsEventsEnum; import com.ai.da.common.response.PageBaseResponse; @@ -65,25 +66,24 @@ public class SuperResolutionServiceImpl extends ServiceImpl prepareForSR(List superResolutionDTOList) { Long accountId = UserContext.getUserHolder().getId(); // 1、判断用户当前积分是否够本次超分消耗 - - Boolean credits = creditsService.checkCredits(accountId, CreditsEventsEnum.SUPER_RESOLUTION, superResolutionDTOList.size()); - // todo 积分扣除待升级 - if (credits) { - // 先扣除积分,后失败后再加上 - creditsService.creditsDecrease(accountId, CreditsEventsEnum.SUPER_RESOLUTION.getName()); - } else { + Boolean preDeduction = creditsService.creditsPreDeduction(CreditsEventsEnum.SUPER_RESOLUTION, superResolutionDTOList.size()); + if (!preDeduction) { throw new BusinessException("Not enough Credits"); } ArrayList uuidList = new ArrayList<>(); - for (SuperResolutionDTO superResolutionDTO : superResolutionDTOList) { + // todo 校验倍率是否是2的幂次(前端已做) + // 2、生成唯一id 使用uuid String uuid = UUID.randomUUID().toString(); int num = 1; @@ -119,17 +119,20 @@ public class SuperResolutionServiceImpl extends ServiceImpl(uuid, "SR", name.substring(name.lastIndexOf("/") + 1), superResolutionDTO, "Waiting", LocalDateTime.now().format(dateTimeFormatter))); - // 6、将消息发布到MQ消息队列 + // 7、将消息发布到MQ消息队列 log.info("发送消息到SR_QUEUE,参数 :{}", jsonString); rabbitMQService.publishMessageToSR(jsonString); } - // 6、返回唯一id列表 + // 8、返回唯一id列表 return uuidList; } @@ -156,9 +159,8 @@ public class SuperResolutionServiceImpl extends ServiceImpl i taskDTOS.add(new TaskDTO<>()); } else { SuperResolutionDTO inputParam = taskDTO.getInputParam(); - inputParam.setImages(minioUtil.getPresignedUrl(inputParam.getImages(), 24 * 60)); - taskDTO.setOutputImage(StringUtil.isNullOrEmpty(taskDTO.getOutputImage()) ? null : minioUtil.getPresignedUrl(taskDTO.getOutputImage(), 24 * 60)); + inputParam.setImages(minioUtil.getPresignedUrl(inputParam.getImages(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); + taskDTO.setOutputImage(StringUtil.isNullOrEmpty(taskDTO.getOutputImage()) ? null : minioUtil.getPresignedUrl(taskDTO.getOutputImage(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); taskDTOS.add(taskDTO); } }); @@ -71,7 +72,7 @@ public class TaskListServiceImpl extends ServiceImpl i public void addToTaskListRedis(TaskDTO taskDTO) { 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、更新任务状态 @@ -104,8 +105,8 @@ public class TaskListServiceImpl extends ServiceImpl i // 成功失败的都返回 TaskVO task = new TaskVO(); task.setImageName(s.getInputUrl().substring(s.getInputUrl().lastIndexOf("/") + 1)); - task.setInputImage(minioUtil.getPresignedUrl(s.getInputUrl(), 24 * 60)); - task.setOutputImage(StringUtil.isNullOrEmpty(s.getOutputUrl()) ? null : minioUtil.getPresignedUrl(s.getOutputUrl(), 24 * 60)); + task.setInputImage(minioUtil.getPresignedUrl(s.getInputUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); + task.setOutputImage(StringUtil.isNullOrEmpty(s.getOutputUrl()) ? null : minioUtil.getPresignedUrl(s.getOutputUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); task.setStatus(s.getStatus()); task.setTaskId(s.getTaskId()); task.setCreateDate(s.getCreateTime().format(dateTimeFormatter));