xiongzhu 2 жил өмнө
parent
commit
b24e9a8cdb

+ 5 - 0
pom.xml

@@ -258,6 +258,11 @@
             <artifactId>spring-boot-starter-freemarker</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-webflux</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>

+ 58 - 10
src/main/java/com/izouma/awesomeAdmin/aspect/RedisLockAspect.java

@@ -3,6 +3,7 @@ package com.izouma.awesomeAdmin.aspect;
 import com.izouma.awesomeAdmin.annotations.RedisLock;
 import com.izouma.awesomeAdmin.exception.BusinessException;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
@@ -18,7 +19,11 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
 import org.springframework.stereotype.Component;
 
 import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 @Aspect
 @Component
@@ -50,34 +55,39 @@ public class RedisLockAspect {
         }
         String key = redisLock.value();
         try {
-            key = Optional.ofNullable(parser.parseExpression(redisLock.value()).getValue(context))
-                    .map(Object::toString)
-                    .orElse("default");
-        } catch (Exception ignored) {
+            key = Optional.ofNullable(parser.parseExpression(key).getValue(context))
+                          .map(Object::toString)
+                          .orElse(key);
+        } catch (Exception e) {
+            log.error("redisLock key parse error", e);
         }
-        log.info("enter redisLock aspect key: {}", key);
         RLock lock = redissonClient.getLock(key);
         if (redisLock.behavior() == RedisLock.Behavior.WAIT) {
+            log.info("⌛️wait lock...{}", key);
             lock.lock(redisLock.expire(), redisLock.unit());
-            log.info("get redisLock success");
+            log.info("✅lock success {}", key);
         } else {
             if (!lock.tryLock()) {
-                log.info("get redisLock fail");
+                log.info("❌lock fail {}", key);
                 throw new BusinessException(redisLock.message());
             }
-            log.info("get redisLock success");
+            log.info("✅lock success {}", key);
         }
         Object res = null;
         try {
             res = joinPoint.proceed();
             try {
                 lock.unlock();
-            } catch (Exception ignored) {
+                log.info("♻️lock released {}", key);
+            } catch (Exception ex) {
+                log.error("❌️lock release failed {}", key, ex);
             }
         } catch (Throwable e) {
             try {
                 lock.unlock();
-            } catch (Exception ignored) {
+                log.info("♻️lock released {}", key);
+            } catch (Exception ex) {
+                log.error("❌️lock release failed {}", key, ex);
             }
             if (e instanceof BusinessException) {
                 throw (BusinessException) e;
@@ -85,5 +95,43 @@ public class RedisLockAspect {
             throw new RuntimeException(e);
         }
         return res;
+
+
+//        try {
+//            key = Optional.ofNullable(parser.parseExpression(redisLock.value()).getValue(context))
+//                    .map(Object::toString)
+//                    .orElse("default");
+//        } catch (Exception ignored) {
+//        }
+//        log.info("enter redisLock aspect key: {}", key);
+//        RLock lock = redissonClient.getLock(key);
+//        if (redisLock.behavior() == RedisLock.Behavior.WAIT) {
+//            lock.lock(redisLock.expire(), redisLock.unit());
+//            log.info("get redisLock success");
+//        } else {
+//            if (!lock.tryLock()) {
+//                log.info("get redisLock fail");
+//                throw new BusinessException(redisLock.message());
+//            }
+//            log.info("get redisLock success");
+//        }
+//        Object res = null;
+//        try {
+//            res = joinPoint.proceed();
+//            try {
+//                lock.unlock();
+//            } catch (Exception ignored) {
+//            }
+//        } catch (Throwable e) {
+//            try {
+//                lock.unlock();
+//            } catch (Exception ignored) {
+//            }
+//            if (e instanceof BusinessException) {
+//                throw (BusinessException) e;
+//            }
+//            throw new RuntimeException(e);
+//        }
+//        return res;
     }
 }

+ 9 - 2
src/main/java/com/izouma/awesomeAdmin/config/Constants.java

@@ -64,8 +64,15 @@ public interface Constants {
     }
 
     interface Redis {
-        String FINANCE_PRODUCT_SALE_AMOUNT = "financeProductSaleAmount::";
-        String UPDATE_SALE_AMOUNT_QUEUE    = "updateSaleAmountQueue";
+        static String FINANCE_PRODUCT_SALE_AMOUNT(Long id) {
+            return "financeProductSaleAmount::" + id;
+        }
+
+        String UPDATE_SALE_AMOUNT_QUEUE = "updateSaleAmountQueue";
+
+        static String PRODUCT(Long id) {
+            return "product::" + id;
+        }
     }
 
     interface ErrorCode {

+ 26 - 0
src/main/java/com/izouma/awesomeAdmin/config/RestTemplateConfig.java

@@ -0,0 +1,26 @@
+package com.izouma.awesomeAdmin.config;
+
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.reactive.function.client.WebClient;
+
+import java.time.Duration;
+
+@Configuration
+public class RestTemplateConfig {
+
+    @Bean
+    public RestTemplate restTemplate(RestTemplateBuilder builder) {
+        return builder.build();
+    }
+
+    @Bean
+    public WebClient webClient() {
+        return WebClient.builder()
+                        .build();
+    }
+}

+ 3 - 0
src/main/java/com/izouma/awesomeAdmin/service/DelegationService.java

@@ -15,6 +15,7 @@ import com.izouma.awesomeAdmin.utils.SecurityUtils;
 import com.izouma.awesomeAdmin.utils.Translator;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RedissonClient;
 import org.springframework.core.env.Environment;
 import org.springframework.stereotype.Service;
 
@@ -37,6 +38,7 @@ public class DelegationService {
     private final SaleBatchRepo      saleBatchRepo;
     private final UserBalanceService userBalanceService;
     private final CommissionService  commissionService;
+    private final RedissonClient     redissonClient;
 
     public Delegation payDelegationBalance(Long userId, Long orderId) {
         SecurityUtils.checkBanned();
@@ -170,6 +172,7 @@ public class DelegationService {
         orderRepo.save(sellerOrder);
 
         activeDelegation(delegation);
+        redissonClient.getAtomicLong(Constants.Redis.PRODUCT(delegation.getProductId())).delete();
         return delegation;
     }
 

+ 1 - 1
src/main/java/com/izouma/awesomeAdmin/service/FinanceOrderService.java

@@ -67,7 +67,7 @@ public class FinanceOrderService {
                 .orElseThrow(new BusinessException(Translator.toLocale("financeOrder.duration_not_available")));
 
         RQueue<Long> queue = redissonClient.getQueue(Constants.Redis.UPDATE_SALE_AMOUNT_QUEUE);
-        RAtomicDouble atomicSale = redissonClient.getAtomicDouble(Constants.Redis.FINANCE_PRODUCT_SALE_AMOUNT + productId);
+        RAtomicDouble atomicSale = redissonClient.getAtomicDouble(Constants.Redis.FINANCE_PRODUCT_SALE_AMOUNT(productId));
         double saleAmount = atomicSale.addAndGet(stakeAmount.doubleValue());
         log.info("create financeOrder, userId: {}, productId: {},  saleAmount: {}", userId, productId, saleAmount);
         try {

+ 1 - 1
src/main/java/com/izouma/awesomeAdmin/service/FinanceProductService.java

@@ -162,7 +162,7 @@ public class FinanceProductService {
         List<Long> ids = queue.poll(10000);
         ids.stream().collect(Collectors.groupingBy(l -> l)).forEach((id, list) -> {
             financeProductRepo.findById(id).ifPresent(fp -> {
-                double saleAmount = redissonClient.getAtomicDouble(Constants.Redis.FINANCE_PRODUCT_SALE_AMOUNT + id)
+                double saleAmount = redissonClient.getAtomicDouble(Constants.Redis.FINANCE_PRODUCT_SALE_AMOUNT(id))
                                                   .get();
                 financeProductRepo.updateSale(id, list.size(),
                         new BigDecimal(saleAmount).max(BigDecimal.ZERO).min(fp.getAmount()));

+ 3 - 8
src/main/java/com/izouma/awesomeAdmin/service/OrderService.java

@@ -140,15 +140,8 @@ public class OrderService {
     }
 
     @Transactional
-    @RedisLock(value = "createOrder::#userId", behavior = RedisLock.Behavior.WAIT)
+    @RedisLock(value = "'createOrderProduct::'+#productId", behavior = RedisLock.Behavior.WAIT)
     public Order createOrder(Long userId, Long productId, Long addressId) {
-        try {
-            RAtomicLong r = redissonClient.getAtomicLong("product::" + productId);
-            r.incrementAndGet();
-        } catch (Exception e) {
-            log.error("redisson error", e);
-            throw e;
-        }
         SecurityUtils.checkBanned();
         if (!sysConfigService.getBoolean(Constants.SYSTEM_OPEN)) {
             throw new BusinessException(Translator.toLocale("system.closed"));
@@ -317,6 +310,7 @@ public class OrderService {
 
         commissionRecordRepo.findByOrderId(orderId)
                             .ifPresent(commissionRecordRepo::delete);
+        redissonClient.getAtomicLong(Constants.Redis.PRODUCT(buyerOrder.getProductId())).delete();
     }
 
     public void cancelTrialOrder(Long orderId, boolean checkRole, boolean checkStatus) {
@@ -412,6 +406,7 @@ public class OrderService {
     }
 
     @Transactional
+    @RedisLock(value = "'balancePay:'+#userId+':'+#orderId)")
     public void balancePay(Long userId, Long orderId) {
         SecurityUtils.checkBanned();
         Order buyerOrder = orderRepo.findById(orderId)

+ 1 - 1
src/main/java/com/izouma/awesomeAdmin/service/RechargeOrderService.java

@@ -52,7 +52,7 @@ public class RechargeOrderService {
         return map;
     }
 
-    @RedisLock(value = "rechargeNotify:#orderId", behavior = RedisLock.Behavior.WAIT)
+    @RedisLock(value = "'rechargeNotify:'+#orderId", behavior = RedisLock.Behavior.WAIT)
     public void notify(Long orderId) {
         RechargeOrder rechargeOrder = rechargeOrderRepo.findById(orderId)
                                                        .orElseThrow(new BusinessException(Translator.toLocale("record.not_found")));

+ 3 - 3
src/main/java/com/izouma/awesomeAdmin/service/WithdrawApplyService.java

@@ -207,7 +207,7 @@ public class WithdrawApplyService {
         return withdrawApply;
     }
 
-    @RedisLock("withdraw:#id")
+    @RedisLock("'withdraw:'+#id")
     @Transactional
     public void approve(Long id) {
         WithdrawApply apply = withdrawApplyRepo.findById(id)
@@ -257,7 +257,7 @@ public class WithdrawApplyService {
         withdrawApplyRepo.save(apply);
     }
 
-    @RedisLock("withdraw:#id")
+    @RedisLock("'withdraw:'+#id")
     @Transactional
     public void deny(Long id) {
         WithdrawApply apply = withdrawApplyRepo.findById(id)
@@ -272,7 +272,7 @@ public class WithdrawApplyService {
         withdrawApplyRepo.save(apply);
     }
 
-    @RedisLock("withdraw:#id")
+    @RedisLock("'withdraw:'+#id")
     @Transactional
     public void success(Long id) {
         WithdrawApply apply = withdrawApplyRepo.findById(id)

+ 43 - 0
src/test/java/com/izouma/awesomeAdmin/service/OrderServiceTest.java

@@ -0,0 +1,43 @@
+package com.izouma.awesomeAdmin.service;
+
+import com.izouma.awesomeAdmin.domain.Product;
+import com.izouma.awesomeAdmin.dto.PageQuery;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Mono;
+
+import java.util.ArrayList;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class OrderServiceTest {
+    @Autowired
+    private OrderService   orderService;
+    @Autowired
+    private ProductService productService;
+    @Autowired
+    private WebClient      webClient;
+
+    @Test
+    public void createOrder() {
+        ParameterizedTypeReference<Page<Product>> typeReference = new ParameterizedTypeReference<Page<Product>>() {
+        };
+        Mono<Page<Product>> mono = webClient.post()
+                                            .uri("http://localhost:8080/product/list")
+                                            .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
+                                            .body(new PageQuery(), PageQuery.class)
+                                            .retrieve().bodyToMono(typeReference);
+        mono.subscribe(page -> {
+            System.out.println(page.getTotalElements());
+        });
+    }
+}