1、接入超分功能

2、添加积分系统
3、新增订单查询,积分详细查询
This commit is contained in:
2024-03-15 15:38:56 +08:00
parent bf05f88c00
commit 305324fe1a
35 changed files with 798 additions and 55 deletions

View File

@@ -210,6 +210,11 @@ public class AliPayServiceImpl implements AliPayService {
orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS);
//记录支付日志
paymentInfoService.createPaymentInfoForAliPay(params);
// 添加积分变更记录
creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(),
CreditsEventsEnum.BUY_CREDITS.getName() + "--Alipay",
CreditsEventsEnum.BUY_CREDITS.getValue(),
"positive");
// 更新积分
creditsService.buyCredits(orderByOrderNo.getAccountId(),Integer.parseInt(totalAmount) / Integer.parseInt(CreditsEventsEnum.PRICE.getValue()));
} finally {
@@ -307,6 +312,11 @@ public class AliPayServiceImpl implements AliPayService {
orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS);
//并记录支付日志
paymentInfoService.createPaymentInfoForAliPay(alipayTradeQueryResponse);
// 添加积分变更记录
creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(),
CreditsEventsEnum.BUY_CREDITS.getName() + "--Alipay",
CreditsEventsEnum.BUY_CREDITS.getValue(),
"positive");
// 更新积分
creditsService.buyCredits(orderByOrderNo.getAccountId(),orderByOrderNo.getTotalFee() / Integer.parseInt(CreditsEventsEnum.PRICE.getValue()));
}

View File

@@ -3,17 +3,29 @@ package com.ai.da.service.impl;
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.mapper.primary.AccountMapper;
import com.ai.da.mapper.primary.CreditsDetailMapper;
import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.mapper.primary.entity.CreditsDetail;
import com.ai.da.model.dto.QueryIncomeOrExpenditureDTO;
import com.ai.da.service.AccountService;
import com.ai.da.service.CreditsService;
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.stereotype.Service;
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.Objects;
@Service
public class CreditsServiceImpl implements CreditsService {
public class CreditsServiceImpl extends ServiceImpl<CreditsDetailMapper, CreditsDetail> implements CreditsService {
@Resource
private AccountService accountService;
@@ -88,4 +100,66 @@ public class CreditsServiceImpl implements CreditsService {
BigDecimal subtracted = existingCredits.subtract(newCredits);
accountService.updateCredits(accountId, subtracted.toString());
}
/**
* 向积分变更详细表添加记录
* @param changeEvent 导致积分变更的事件
* @param credits 变更的积分
* @param changeType 变更类型 positive->增 negative->减
*/
@Override
public void insertToCreditsDetail(Long accountId, String changeEvent, String credits, String changeType){
CreditsDetail creditsDetail = new CreditsDetail();
Account account = accountMapper.selectById(accountId);
BigDecimal finalCredits;
String changeCredits;
if ("positive".equals(changeType)){
finalCredits = account.getCredits().add(new BigDecimal(credits));
changeCredits = "+" + credits;
}else {
finalCredits = account.getCredits().subtract(new BigDecimal(credits));
changeCredits = "-" + credits;
}
creditsDetail.setAccountId(accountId);
creditsDetail.setChangeEvent(changeEvent);
creditsDetail.setChangedCredits(changeCredits);
creditsDetail.setCredits(finalCredits);
creditsDetail.setCreateTime(LocalDateTime.now());
baseMapper.insert(creditsDetail);
}
@Override
public PageBaseResponse<CreditsDetail> queryCreditsDetailsPage(QueryIncomeOrExpenditureDTO queryPageByTimeDTO){
QueryWrapper<CreditsDetail> qw = new QueryWrapper<>();
qw.eq("account_id",UserContext.getUserHolder().getId());
String startTime = queryPageByTimeDTO.getStartTime();
String endTime = queryPageByTimeDTO.getEndTime();
if (StringUtil.isNullOrEmpty(startTime)){
startTime = "2024-03-01 00:00:00";
}
if (StringUtil.isNullOrEmpty(endTime)){
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
endTime = now.format(dateTimeFormatter);
}
if (!Objects.isNull(queryPageByTimeDTO.getIsIncome())){
if (queryPageByTimeDTO.getIsIncome()){
qw.likeRight("changed_credits","+");
}else {
qw.likeRight("changed_credits","-");
}
}
qw.between("create_time", startTime, endTime);
qw.orderByDesc("create_time");
Page<CreditsDetail> pageInfo = new Page<>(queryPageByTimeDTO.getPage(), queryPageByTimeDTO.getSize());
Page<CreditsDetail> orderInfo = baseMapper.selectPage(pageInfo, qw);
if (CollectionUtils.isEmpty(orderInfo.getRecords())) {
return PageBaseResponse.success(new Page<>());
}
return PageBaseResponse.success(orderInfo);
}
}

View File

@@ -68,13 +68,13 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
@Resource
private GenerateCancelMapper generateCancelMapper;
@Value("${redis.key.consumptionOrder}")
@Value("${redis.key.orderForGenerate}")
private String consumptionOrderKey;
@Value("${redis.key.cancelSet}")
@Value("${redis.key.generateCancelSet}")
private String cancelSetKey;
@Value("${redis.key.exceptionMap}")
@Value("${redis.key.generateExceptionMap}")
private String exceptionMapKey;
@Value("${redis.key.resultMap}")
@@ -368,7 +368,7 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
redisUtil.addToZSet(consumptionOrderKey, uuid, maxScore);
// 4、将消息发布到MQ消息队列
rabbitMQService.publishMessage(jsonString);
rabbitMQService.publishMessageToGenerate(jsonString);
// 5、返回唯一id
return new PrepareForGenerateVO(uuid, 2 - trialsCount);

View File

@@ -4,20 +4,27 @@ package com.ai.da.service.impl;
import com.ai.da.common.context.UserContext;
import com.ai.da.common.enums.CreditsEventsEnum;
import com.ai.da.common.enums.OrderStatusEnum;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.utils.OrderNoUtils;
import com.ai.da.mapper.primary.OrderInfoMapper;
import com.ai.da.mapper.primary.ProductMapper;
import com.ai.da.mapper.primary.entity.OrderInfo;
import com.ai.da.model.dto.QueryPageByTimeDTO;
import com.ai.da.model.vo.AuthPrincipalVo;
import com.ai.da.service.OrderInfoService;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
@Service
@@ -172,12 +179,30 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
return orderInfo;
}
public List<OrderInfo> getOrderByAccountId(Long accountId){
@Override
public PageBaseResponse<OrderInfo> getOrderByPage(QueryPageByTimeDTO queryPageByTimeDTO){
QueryWrapper<OrderInfo> qw = new QueryWrapper<>();
qw.eq("account_id",accountId);
qw.orderByDesc("create_time");
qw.eq("account_id",UserContext.getUserHolder().getId());
return baseMapper.selectList(qw);
String startTime = queryPageByTimeDTO.getStartTime();
String endTime = queryPageByTimeDTO.getEndTime();
if (StringUtil.isNullOrEmpty(startTime)){
startTime = "2024-02-01 00:00:00";
}
if (StringUtil.isNullOrEmpty(endTime)){
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
endTime = now.format(dateTimeFormatter);
}
qw.between("create_time", startTime, endTime);
qw.orderByDesc("create_time");
Page<OrderInfo> pageInfo = new Page<>(queryPageByTimeDTO.getPage(), queryPageByTimeDTO.getSize());
Page<OrderInfo> orderInfo = baseMapper.selectPage(pageInfo, qw);
if (CollectionUtils.isEmpty(orderInfo.getRecords())) {
return PageBaseResponse.success(new Page<>());
}
return PageBaseResponse.success(orderInfo);
}
public void updateOrderNoById(Long id, String orderNo){

View File

@@ -7,10 +7,17 @@ import com.ai.da.common.constant.PayPalCheckoutConstant;
import com.ai.da.common.enums.*;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.common.utils.paypalRequest.AuthenticationRequest;
import com.ai.da.common.utils.paypalRequest.WebhookVerifyRequest;
import com.ai.da.mapper.primary.entity.OrderInfo;
import com.ai.da.mapper.primary.entity.RefundInfo;
import com.ai.da.service.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
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 com.paypal.http.exceptions.SerializeException;
import com.paypal.http.serializer.Json;
@@ -24,9 +31,19 @@ import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
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.*;
import static com.ai.da.common.constant.PayPalCheckoutConstant.*;
@@ -47,19 +64,14 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
@Resource
private PayPalClient payPalClient;
@Resource
private OrderInfoService orderInfoService;
@Resource
private PaymentInfoService paymentInfoService;
@Resource
private RefundInfoService refundsInfoService;
@Resource
private CreditsService creditsService;
@Resource
private RedisUtil redisUtil;
@@ -67,6 +79,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
* 创建订单的方法
*/
@Override
@Transactional(rollbackFor = Exception.class)
public HashMap<String, String> createOrder(Integer amount, String returnUrl) throws SerializeException {
// 生成订单
log.info("生成订单");
@@ -102,7 +115,6 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
String orderId = response.result().id();
orderInfoService.updateOrderNoById(orderInfo.getId(), orderId);
HashMap<String, String> returnData = new HashMap<>();
returnData.put("approve",approve);
returnData.put("orderNo",orderId);
@@ -111,6 +123,99 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
return returnData;
}
// ##Validate Webhook
public 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(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");
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;
}
/**
* 生成订单主体信息
*/
@@ -256,6 +361,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
/**
* 用户授权支付成功,进行扣款操作
*/
@Transactional(rollbackFor = Exception.class)
public Order captureOrder(String orderId) {
OrdersCaptureRequest request = new OrdersCaptureRequest(orderId);
request.requestBody(new OrderRequest());
@@ -330,6 +436,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
/**
* 申请退款
*/
@Transactional(rollbackFor = Exception.class)
public Boolean refundOrder(String orderId,String reason) throws IOException {
RefundInfo refundByOrderNo = refundsInfoService.createRefundByOrderNo(orderId, reason);
@@ -458,6 +565,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
}
// 处理当前订单
@Transactional(rollbackFor = Exception.class)
public void processOrder(String orderId){
// 1、确定当前订单是否已经被扣款
OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderId);
@@ -473,6 +581,11 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
orderInfoService.updateStatusByOrderNo(orderId, OrderStatusEnum.SUCCESS);
//记录支付日志
paymentInfoService.createPaymentInfoForPayPal(capturedOrder);
// 添加积分变更记录
creditsService.insertToCreditsDetail(orderInfo.getAccountId(),
CreditsEventsEnum.BUY_CREDITS.getName() + "--PayPal",
CreditsEventsEnum.BUY_CREDITS.getValue(),
"positive");
// 更新积分
creditsService.buyCredits(orderInfo.getAccountId(), orderInfo.getTotalFee() / Integer.parseInt(CreditsEventsEnum.PRICE.getValue()));
}

View File

@@ -27,10 +27,14 @@ public class RabbitMQServiceImpl implements RabbitMQService {
private MQPublisher mqPublisher;
@Override
public void publishMessage(String message) {
public void publishMessageToGenerate(String message) {
mqPublisher.sendGenerateMessage(message);
}
@Override
public void publishMessageToSR(String message) {
mqPublisher.sendSRMessage(message);
}
@Override
public Integer getMessageCount(String queueUrl) {

View File

@@ -0,0 +1,122 @@
package com.ai.da.service.impl;
import com.ai.da.common.context.UserContext;
import com.ai.da.common.enums.CreditsEventsEnum;
import com.ai.da.common.utils.AsyncCallerUtil;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.mapper.primary.SuperResolutionMapper;
import com.ai.da.mapper.primary.entity.SuperResolution;
import com.ai.da.model.dto.SuperResolutionDTO;
import com.ai.da.python.PythonService;
import com.ai.da.service.CreditsService;
import com.ai.da.service.RabbitMQService;
import com.ai.da.service.SuperResolutionService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.UUID;
@Service
public class SuperResolutionServiceImpl extends ServiceImpl<SuperResolutionMapper, SuperResolution> implements SuperResolutionService {
public static final Integer creditsConsumption = 100;
@Resource
private CreditsService creditsService;
@Resource
private RabbitMQService rabbitMQService;
@Resource
private AsyncCallerUtil asyncCallerUtil;
@Resource
private PythonService pythonService;
@Resource
private RedisUtil redisUtil;
@Value("${redis.key.orderForSR}")
private String orderForSR;
@Value("${redis.key.resultMap}")
private String resultMapKey;
@Override
public String prepareForSR(SuperResolutionDTO superResolutionDTO) {
// 异步处理
// 判断用户当前积分是否够本次超分消耗
String credits = creditsService.getCredits();
if (new BigDecimal(credits).subtract(new BigDecimal(creditsConsumption)).compareTo(BigDecimal.ZERO) < 0){
return "Not enough Credits";
}
// 2、生成唯一id 使用uuid
String uuid = UUID.randomUUID().toString();
int num = 1;
// 判断已经正常生成结果的uuid或正在排队的uuid中是否有相同的id
while ((redisUtil.isElementExistsInMap(resultMapKey, uuid) ||
redisUtil.isElementExistsInZSet(orderForSR, uuid))
&& num < 10) {
uuid = UUID.randomUUID().toString();
num++;
}
// 无依据确定的数字
if (num > 10) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
uuid = UUID.randomUUID().toString();
}
superResolutionDTO.setUniqueId(uuid);
String jsonString = JSON.toJSONString(superResolutionDTO);
// 3、加入redis排队便于获取实时排队信息
Double maxScore = redisUtil.getMaxScore(orderForSR);
redisUtil.addToZSet(orderForSR, uuid, maxScore);
// 4、将消息发布到MQ消息队列
rabbitMQService.publishMessageToSR(jsonString);
// 5、返回唯一id
return uuid;
}
@Transactional(rollbackFor = Exception.class)
@Override
public String SR(SuperResolutionDTO superResolutionDTO){
// 1、向模型发起请求
// String srResult = asyncCallerUtil.SR(superResolutionDTO);
String srResult = pythonService.superResolution(superResolutionDTO);
// 2、向数据库插入数据
SuperResolution superResolution = new SuperResolution();
superResolution.setInput_url(superResolutionDTO.getImages());
superResolution.setScale(superResolutionDTO.getScale());
superResolution.setOutput_url(srResult);
superResolution.setCreateTime(LocalDateTime.now());
baseMapper.insert(superResolution);
// 3、记录积分变更
creditsService.insertToCreditsDetail(UserContext.getUserHolder().getId(),
CreditsEventsEnum.SUPER_RESOLUTION.getName(),
CreditsEventsEnum.SUPER_RESOLUTION.getValue(),
"negative");
// 4、扣除积分
creditsService.creditsDecrease(UserContext.getUserHolder().getId(), CreditsEventsEnum.SUPER_RESOLUTION.getValue());
// 4、将数据存在数据库
return srResult;
}
}