Procházet zdrojové kódy

分布锁/缓存管理/钱包申请

xiongzhu před 3 roky
rodič
revize
781ec5b5e5

+ 7 - 3
src/main/java/com/izouma/nineth/annotations/RedisLock.java

@@ -1,7 +1,5 @@
 package com.izouma.nineth.annotations;
 
-import com.izouma.nineth.enums.RedisLockBehavior;
-
 import java.lang.annotation.*;
 import java.util.concurrent.TimeUnit;
 
@@ -15,5 +13,11 @@ public @interface RedisLock {
 
     TimeUnit unit() default TimeUnit.SECONDS;
 
-    RedisLockBehavior behavior() default RedisLockBehavior.THROW;
+    Behavior behavior() default Behavior.THROW;
+
+    enum Behavior {
+        WAIT,
+        THROW
+    }
+
 }

+ 36 - 22
src/main/java/com/izouma/nineth/aspect/RedisLockAspect.java

@@ -8,6 +8,8 @@ import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
 import org.aspectj.lang.annotation.Pointcut;
 import org.aspectj.lang.reflect.MethodSignature;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.DefaultParameterNameDiscoverer;
 import org.springframework.data.redis.core.BoundValueOperations;
@@ -26,10 +28,13 @@ import java.util.Optional;
 @Slf4j
 public class RedisLockAspect {
 
-    private DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
+    private final DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
 
-    @Autowired
-    private RedisTemplate<String, Object> redisTemplate;
+    private final RedissonClient redissonClient;
+
+    public RedisLockAspect(RedissonClient redissonClient) {
+        this.redissonClient = redissonClient;
+    }
 
     @Pointcut("@annotation(com.izouma.nineth.annotations.RedisLock)")
     public void redisLockPointCut() {
@@ -37,7 +42,6 @@ public class RedisLockAspect {
 
     @Around(value = "redisLockPointCut() && @annotation(redisLock)")
     public Object redisLock(ProceedingJoinPoint joinPoint, RedisLock redisLock) {
-        log.info("enter redisLock aspect");
         ExpressionParser parser = new SpelExpressionParser();
         EvaluationContext context = new StandardEvaluationContext(joinPoint.getSignature());
         MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
@@ -52,27 +56,37 @@ public class RedisLockAspect {
             key = Optional.ofNullable(parser.parseExpression(redisLock.value()).getValue(context))
                     .map(Object::toString)
                     .orElse("default");
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
-        log.info("redisLock aspect key: {}", key);
-        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(key);
-        Boolean success = ops.setIfAbsent(1, redisLock.expire(), redisLock.unit());
-        log.info("redisLock aspect lock success: {}", success);
-        if (Boolean.TRUE.equals(success)) {
-            Object res = null;
+        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("获取锁失败");
+            }
+            log.info("get redisLock success");
+        }
+        Object res = null;
+        try {
+            res = joinPoint.proceed();
             try {
-                res = joinPoint.proceed();
-            } catch (Throwable e) {
-                redisTemplate.delete(key);
-                if (e instanceof BusinessException) {
-                    throw (BusinessException) e;
-                }
-                throw new RuntimeException(e);
+                lock.unlock();
+            } catch (Exception ignored) {
             }
-            redisTemplate.delete(key);
-            return res;
+        } catch (Throwable e) {
+            try {
+                lock.unlock();
+            } catch (Exception ignored) {
+            }
+            if (e instanceof BusinessException) {
+                throw (BusinessException) e;
+            }
+            throw new RuntimeException(e);
         }
-        throw new BusinessException("发生错误,请稍后再试");
+        return res;
     }
-
 }

+ 3 - 0
src/main/java/com/izouma/nineth/domain/User.java

@@ -173,4 +173,7 @@ public class User extends UserBaseEntity implements Serializable {
 
     @Column(columnDefinition = "tinyint unsigned default 0")
     private boolean company = false;
+
+    @Column(columnDefinition = "tinyint unsigned default 0")
+    private boolean walletEnabled = false;
 }

+ 0 - 6
src/main/java/com/izouma/nineth/enums/RedisLockBehavior.java

@@ -1,6 +0,0 @@
-package com.izouma.nineth.enums;
-
-public enum RedisLockBehavior {
-    THROW,
-    RETRY
-}

+ 3 - 1
src/main/java/com/izouma/nineth/repo/OrderRepo.java

@@ -10,6 +10,7 @@ import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 
 import javax.transaction.Transactional;
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.Collection;
 import java.util.List;
@@ -82,5 +83,6 @@ public interface OrderRepo extends JpaRepository<Order, Long>, JpaSpecificationE
     @Modifying
     int processingOrder(Long id, LocalDateTime payTime, PayMethod payMethod, String transactionId);
 
-
+    @Query(value = "select sum(price) from order_info where user_id = 6330925 and status = 'FINISH'", nativeQuery = true)
+    BigDecimal sumUserPrice(Long userId);
 }

+ 13 - 5
src/main/java/com/izouma/nineth/service/IdentityAuthService.java

@@ -133,13 +133,17 @@ public class IdentityAuthService {
 //            }
 //        }
 //    }
-    public void validate(String name, String phone, String idno) {
-        String body = HttpRequest.post("https://zid.market.alicloudapi.com/idcheck/Post")
+    public static void validate(String name, String phone, String idno) {
+        HttpRequest request = HttpRequest.post("https://zid.market.alicloudapi.com/idcheck/Post")
                 .header("Authorization", "APPCODE b48bc8f6759345a79ae20a951f03dabe")
                 .contentType(HttpRequest.CONTENT_TYPE_FORM)
                 .form("cardNo", idno)
-                .form("realName", name)
-                .body();
+                .form("realName", name);
+        int code = request.code();
+        if (code != 200) {
+            throw new BusinessException("网络异常", "网络异常");
+        }
+        String body = request.body();
         JSONObject jsonObject = JSONObject.parseObject(body);
         log.info("validate {} {} \n{}", name, idno, JSON.toJSONString(jsonObject, SerializerFeature.PrettyFormat));
         if (jsonObject.getInteger("error_code") != 0) {
@@ -221,7 +225,9 @@ public class IdentityAuthService {
             List<IdentityAuth> list = identityAuthRepo.findByStatusAndAutoValidated(AuthStatus.PENDING, false);
             list.parallelStream().forEach(identityAuth -> {
                 Map<String, Object> map = auth(identityAuth);
-                audit(identityAuth.getId(), (AuthStatus) map.get("status"), (String) map.get("reason"));
+                if (map != null) {
+                    audit(identityAuth.getId(), (AuthStatus) map.get("status"), (String) map.get("reason"));
+                }
             });
         } catch (Exception e) {
             log.error("批量自动实名出错", e);
@@ -269,6 +275,8 @@ public class IdentityAuthService {
                         log.error("自动实名出错", e);
                         if ("不匹配".equals(e.getMessage())) {
                             result.put("status", AuthStatus.FAIL);
+                        } else if ("网络异常".equals(e.getMessage())) {
+                            return null;
                         } else {
                             result.put("status", AuthStatus.PENDING);
                         }

+ 1 - 6
src/main/java/com/izouma/nineth/service/OrderService.java

@@ -13,7 +13,6 @@ import com.github.binarywang.wxpay.constant.WxPayConstants;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.google.common.base.Splitter;
-import com.huifu.adapay.Adapay;
 import com.huifu.adapay.core.exception.BaseAdaPayException;
 import com.huifu.adapay.model.AdapayCommon;
 import com.huifu.adapay.model.Payment;
@@ -22,7 +21,6 @@ import com.izouma.nineth.domain.Collection;
 import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.MarketSettlement;
 import com.izouma.nineth.dto.PageQuery;
-import com.izouma.nineth.dto.PayQuery;
 import com.izouma.nineth.dto.UserBankCard;
 import com.izouma.nineth.enums.*;
 import com.izouma.nineth.event.CreateAssetEvent;
@@ -39,7 +37,6 @@ import io.github.bucket4j.Bucket;
 import io.github.bucket4j.BucketConfiguration;
 import io.github.bucket4j.Refill;
 import io.github.bucket4j.distributed.proxy.ProxyManager;
-import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.codec.EncoderException;
 import org.apache.commons.codec.net.URLCodec;
@@ -51,7 +48,6 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.rocketmq.client.producer.SendResult;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
 import org.springframework.cache.annotation.Cacheable;
-import org.springframework.context.annotation.Lazy;
 import org.springframework.context.event.EventListener;
 import org.springframework.core.env.Environment;
 import org.springframework.data.domain.Page;
@@ -71,7 +67,6 @@ import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.format.DateTimeFormatter;
-import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -721,7 +716,7 @@ public class OrderService {
                             smsService.sellOut(userRepo.findPhoneById(asset.getUserId()));
                         }
 
-                        userBalanceService.settleOrder(order);
+                        userBalanceService.realtimeSettleOrder(order);
                     } else {
                         orderRepo.save(order);
                         //藏品其他信息/是否vip

+ 36 - 0
src/main/java/com/izouma/nineth/service/SysConfigService.java

@@ -50,6 +50,10 @@ public class SysConfigService {
         return Integer.parseInt(str);
     }
 
+    public String getString(String name) {
+        return sysConfigRepo.findByName(name).map(SysConfig::getValue).orElse(null);
+    }
+
     @PostConstruct
     public void init() {
         List<SysConfig> list = sysConfigRepo.findAll();
@@ -134,6 +138,14 @@ public class SysConfigService {
                     .value("100")
                     .build());
         }
+        if (list.stream().noneMatch(i -> i.getName().equals("max_recharge_amount"))) {
+            sysConfigRepo.save(SysConfig.builder()
+                    .name("max_recharge_amount")
+                    .desc("最大充值金额")
+                    .type(SysConfig.ValueType.NUMBER)
+                    .value("5000")
+                    .build());
+        }
         if (list.stream().noneMatch(i -> i.getName().equals("enable_balance_pay"))) {
             sysConfigRepo.save(SysConfig.builder()
                     .name("enable_balance_pay")
@@ -150,6 +162,14 @@ public class SysConfigService {
                     .value("100")
                     .build());
         }
+        if (list.stream().noneMatch(i -> i.getName().equals("withdraw_charge"))) {
+            sysConfigRepo.save(SysConfig.builder()
+                    .name("withdraw_charge")
+                    .desc("提现手续费(%,最低)")
+                    .type(SysConfig.ValueType.STRING)
+                    .value("8,2")
+                    .build());
+        }
         if (list.stream().noneMatch(i -> i.getName().equals("enable_withdraw"))) {
             sysConfigRepo.save(SysConfig.builder()
                     .name("enable_withdraw")
@@ -182,6 +202,22 @@ public class SysConfigService {
                     .value("0")
                     .build());
         }
+        if (list.stream().noneMatch(i -> i.getName().equals("realtime_settle_order"))) {
+            sysConfigRepo.save(SysConfig.builder()
+                    .name("realtime_settle_order")
+                    .desc("开启订单实时结算")
+                    .type(SysConfig.ValueType.BOOLEAN)
+                    .value("0")
+                    .build());
+        }
+        if (list.stream().noneMatch(i -> i.getName().equals("wallet_enable_amount"))) {
+            sysConfigRepo.save(SysConfig.builder()
+                    .name("wallet_enable_amount")
+                    .desc("开启钱包所需最小消费金额")
+                    .type(SysConfig.ValueType.NUMBER)
+                    .value("1")
+                    .build());
+        }
         SearchMode searchMode = SearchMode.valueOf(sysConfigRepo.findByName("default_search_mode").get().getValue());
         JpaUtils.setDefaultSearchMode(searchMode);
 

+ 4 - 3
src/main/java/com/izouma/nineth/service/UserBalanceService.java

@@ -37,10 +37,8 @@ import javax.transaction.Transactional;
 import java.io.*;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
-import java.time.Duration;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
-import java.time.LocalTime;
 import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.concurrent.ExecutionException;
@@ -523,7 +521,10 @@ public class UserBalanceService {
                 .build());
     }
 
-    public void settleOrder(Order order) {
+    public void realtimeSettleOrder(Order order) {
+        if (!sysConfigService.getBoolean("realtime_settle_order")) {
+            return;
+        }
         BalanceRecord record = balanceRecordRepo.findByOrderIdAndType(order.getId(), BalanceType.SELL);
         if (record != null) {
             return;

+ 33 - 3
src/main/java/com/izouma/nineth/service/UserService.java

@@ -62,6 +62,9 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.text.SimpleDateFormat;
 import java.time.Duration;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.regex.Pattern;
@@ -94,6 +97,7 @@ public class UserService {
     private WeakPassRepo                  weakPassRepo;
     private UserBalanceRepo               userBalanceRepo;
     private ContentAuditService           contentAuditService;
+    private OrderRepo                     orderRepo;
 
     public User update(User user) {
         if (!SecurityUtils.hasRole(AuthorityName.ROLE_ADMIN)) {
@@ -119,6 +123,7 @@ public class UserService {
     public User save(User user) {
         if (user.getId() != null) {
             cacheService.clearUserMy(user.getId());
+            cacheService.clearUser(user.getId());
         }
         return userRepo.save(user);
     }
@@ -577,7 +582,7 @@ public class UserService {
             throw new BusinessException("用户不存在或未认证");
         }
         String realName = identityAuthRepo.findFirstByUserIdAndStatusAndDelFalseOrderByCreatedAtDesc(
-                user.getId(), AuthStatus.SUCCESS)
+                        user.getId(), AuthStatus.SUCCESS)
                 .map(IdentityAuth::getRealName).orElse("").replaceAll(".*(?=.)", "**");
         Map<String, Object> map = new HashMap<>();
         map.put("id", user.getId());
@@ -590,8 +595,8 @@ public class UserService {
 
     public Map<String, Object> searchByPhoneAdmin(String phoneStr) {
         List<String> phone = Arrays.stream(phoneStr.replaceAll("\n", " ")
-                .replaceAll("\r\n", " ")
-                .split(" "))
+                        .replaceAll("\r\n", " ")
+                        .split(" "))
                 .map(String::trim)
                 .filter(s -> !StringUtils.isEmpty(s))
                 .collect(Collectors.toList());
@@ -881,4 +886,29 @@ public class UserService {
         result.setCount(BigInteger.valueOf(invitedUserDTOS.size()));
         return result;
     }
+
+    public void enableWallet(Long userId) {
+        User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
+        if (user.isWalletEnabled()) {
+            return;
+        }
+        if (!sysConfigService.getBoolean("enable_wallet")) {
+            throw new BusinessException("绿魔卡功能暂未开启");
+        }
+        IdentityAuth identityAuth = identityAuthRepo.findByUserId(userId).stream().findFirst().orElse(null);
+        if (identityAuth == null) {
+            throw new BusinessException("请先完成实名认证");
+        }
+        long age = ChronoUnit.YEARS.between(LocalDate.parse(identityAuth.getIdNo().substring(6, 14),
+                DateTimeFormatter.ofPattern("yyyyMMdd")), LocalDate.now());
+        if (!((age >= 22 && age <= 55))) {
+            throw new BusinessException("仅22至55周岁藏家可申请绿魔卡");
+        }
+        BigDecimal amount = sysConfigService.getBigDecimal("wallet_enable_amount");
+        if (Optional.ofNullable(orderRepo.sumUserPrice(userId)).orElse(BigDecimal.ZERO).compareTo(amount) < 0) {
+            throw new BusinessException("申请绿魔卡需满" + amount + "绿洲石");
+        }
+        user.setWalletEnabled(true);
+        save(user);
+    }
 }

+ 15 - 1
src/main/java/com/izouma/nineth/service/WithdrawApplyService.java

@@ -16,6 +16,7 @@ import com.izouma.nineth.repo.WithdrawApplyRepo;
 import com.izouma.nineth.utils.JpaUtils;
 import com.izouma.nineth.utils.SnowflakeIdWorker;
 import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.core.env.Environment;
 import org.springframework.data.domain.Page;
 import org.springframework.stereotype.Service;
@@ -26,6 +27,7 @@ import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.util.Arrays;
 import java.util.Optional;
+import java.util.regex.Pattern;
 
 @Service
 @AllArgsConstructor
@@ -83,6 +85,18 @@ public class WithdrawApplyService {
                 userBalanceService.modifyBalance(apply.getUserId(), apply.getAmount(), BalanceType.DENY,
                         "用户未绑卡", false, null);
             } else {
+                BigDecimal chargeAmount;
+                String withdrawCharge = sysConfigService.getString("withdraw_charge");
+                if (StringUtils.isNotEmpty(withdrawCharge) && Pattern.matches("^(\\d+|\\d+.\\d+),\\d+$", withdrawCharge)) {
+                    String[] arr = withdrawCharge.split(",");
+                    chargeAmount = new BigDecimal(arr[0]);
+                    BigDecimal minChargeAmount = new BigDecimal(arr[1]);
+                    if (chargeAmount.compareTo(minChargeAmount) < 0) {
+                        chargeAmount = minChargeAmount;
+                    }
+                } else {
+                    chargeAmount = BigDecimal.ZERO;
+                }
                 String withdrawId = snowflakeIdWorker.nextId() + "";
                 try {
                     String msg = "";
@@ -91,7 +105,7 @@ public class WithdrawApplyService {
                     if (Arrays.asList(env.getActiveProfiles()).contains("prod")) {
                         try {
                             JSONObject res = sandPayService.transfer(withdrawId, bankCard.getRealName(), bankCard.getBankNo(),
-                                    apply.getAmount());
+                                    apply.getAmount().subtract(chargeAmount));
                             if ("0000".equals(res.getString("respCode"))) {
                                 success = true;
                             } else {

+ 36 - 0
src/main/java/com/izouma/nineth/web/CacheController.java

@@ -0,0 +1,36 @@
+package com.izouma.nineth.web;
+
+import com.izouma.nineth.service.CacheService;
+import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.text.CaseUtils;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+@RestController
+@RequestMapping("/cache")
+@AllArgsConstructor
+public class CacheController {
+
+    private final CacheService cacheService;
+
+    @RequestMapping("/clear")
+    @PreAuthorize("hasRole('ADMIN')")
+    public void clear(String name, String stringParam, Long longParam) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+        Method method;
+        if (stringParam != null) {
+            method = CacheService.class.getMethod("clear" + StringUtils.capitalize((name)), String.class);
+            method.invoke(cacheService, stringParam);
+        } else if (longParam != null) {
+            method = CacheService.class.getMethod("clear" + StringUtils.capitalize((name)), Long.class);
+            method.invoke(cacheService, longParam);
+        } else {
+            method = CacheService.class.getMethod("clear" + StringUtils.capitalize((name)));
+            method.invoke(cacheService);
+        }
+    }
+}

+ 38 - 27
src/main/vue/src/router.js

@@ -713,57 +713,68 @@ const router = new Router({
                     name: 'TagEdit',
                     component: () => import(/* webpackChunkName: "tagEdit" */ '@/views/TagEdit.vue'),
                     meta: {
-                       title: '标签编辑',
-                    },
+                        title: '标签编辑'
+                    }
                 },
                 {
                     path: '/tagList',
                     name: 'TagList',
                     component: () => import(/* webpackChunkName: "tagList" */ '@/views/TagList.vue'),
                     meta: {
-                       title: '标签',
-                    },
-               },
+                        title: '标签'
+                    }
+                },
                 {
                     path: '/priceListEdit',
                     name: 'PriceListEdit',
                     component: () => import(/* webpackChunkName: "priceListEdit" */ '@/views/PriceListEdit.vue'),
                     meta: {
-                       title: 'pricelist编辑',
-                    },
+                        title: 'pricelist编辑'
+                    }
                 },
                 {
                     path: '/priceListList',
                     name: 'PriceListList',
                     component: () => import(/* webpackChunkName: "priceListList" */ '@/views/PriceListList.vue'),
                     meta: {
-                       title: 'pricelist',
-                    },
-               },
-               {
-                   path: '/payMgmt',
-                   name: 'PayMgmt',
-                   component: () => import(/* webpackChunkName: "payMgmt" */ '@/views/PayMgmt.vue'),
-                   meta: {
-                      title: '支付管理',
-                   },
-              },
+                        title: 'pricelist'
+                    }
+                },
+                {
+                    path: '/payMgmt',
+                    name: 'PayMgmt',
+                    component: () => import(/* webpackChunkName: "payMgmt" */ '@/views/PayMgmt.vue'),
+                    meta: {
+                        title: '支付管理'
+                    }
+                },
                 {
                     path: '/withdrawApplyEdit',
                     name: 'WithdrawApplyEdit',
-                    component: () => import(/* webpackChunkName: "withdrawApplyEdit" */ '@/views/WithdrawApplyEdit.vue'),
+                    component: () =>
+                        import(/* webpackChunkName: "withdrawApplyEdit" */ '@/views/WithdrawApplyEdit.vue'),
                     meta: {
-                       title: '提现申请编辑',
-                    },
+                        title: '提现申请编辑'
+                    }
                 },
                 {
                     path: '/withdrawApplyList',
                     name: 'WithdrawApplyList',
-                    component: () => import(/* webpackChunkName: "withdrawApplyList" */ '@/views/WithdrawApplyList.vue'),
+                    component: () =>
+                        import(/* webpackChunkName: "withdrawApplyList" */ '@/views/WithdrawApplyList.vue'),
+                    meta: {
+                        title: '提现申请'
+                    }
+                },
+                {
+                    path: '/cache',
+                    name: 'cache',
+                    component: () =>
+                        import(/* webpackChunkName: "cache" */ '@/views/Cache.vue'),
                     meta: {
-                       title: '提现申请',
-                    },
-               }
+                        title: '缓存清理'
+                    }
+                }
                 /**INSERT_LOCATION**/
             ]
         },
@@ -804,7 +815,7 @@ router.beforeEach((to, from, next) => {
         window.open(url);
         return;
     }
-    if (!store.state.userInfo && to.path !== '/login' && to.path!=='/photoProcessing') {
+    if (!store.state.userInfo && to.path !== '/login' && to.path !== '/photoProcessing') {
         http.axios
             .get('/user/my')
             .then(res => {
@@ -823,4 +834,4 @@ router.beforeEach((to, from, next) => {
     }
 });
 
-export default router;
+export default router;

+ 50 - 0
src/main/vue/src/views/Cache.vue

@@ -0,0 +1,50 @@
+<template>
+    <div class="edit-view">
+        <div class="edit-view__content-wrapper">
+            <div class="edit-view__content-section" v-loading="loading">
+                <el-input v-model="param" placeholder="输入参数"></el-input>
+                <el-button @click="clean('user', null, param)">user</el-button>
+                <el-button @click="clean('user')">all user</el-button>
+                <el-button @click="clean('userMy', null, param)">userMy</el-button>
+                <el-button @click="clean('userMy')">all userMy</el-button>
+                <el-button @click="clean('collection')">all collection</el-button>
+                <el-button @click="clean('recommend')">all recommend</el-button>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {
+            loading: false,
+            param: null
+        };
+    },
+    methods: {
+        clean(name, stringParam, longParam) {
+            this.loading = true;
+            this.$http
+                .post('/cache/clear', { name, stringParam, longParam })
+                .then(res => {
+                    this.loading = false;
+                    this.$message.success('成功');
+                })
+                .catch(e => {
+                    this.loading = false;
+                    this.$message.error(e.error || '失败');
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.el-input {
+    width: 300px;
+    margin-right: 20px;
+    margin-bottom: 20px;
+}
+.el-button {
+    margin-bottom: 20px;
+}
+</style>

+ 16 - 0
src/test/java/com/izouma/nineth/CommonTest.java

@@ -16,6 +16,7 @@ import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.dto.SandPaySettle;
 import com.izouma.nineth.dto.UserWithdraw;
+import com.izouma.nineth.service.IdentityAuthService;
 import com.izouma.nineth.service.UserService;
 import com.izouma.nineth.utils.AESEncryptUtil;
 import com.izouma.nineth.utils.DateTimeUtils;
@@ -92,7 +93,10 @@ import java.security.spec.X509EncodedKeySpec;
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
 import java.text.NumberFormat;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
 import java.util.List;
 import java.util.*;
 import java.util.concurrent.ExecutorService;
@@ -699,4 +703,16 @@ public class CommonTest {
     public void decrypt() throws Exception {
         System.out.println(AESEncryptUtil.decrypt("3BBC5669B95729554056D247338D3BAECA4483E429514227058BF3503F2D42A0"));
     }
+
+    @Test
+    public void auth() {
+        IdentityAuthService.validate("熊竹", "15077886171", "321002199408304611");
+        IdentityAuthService.validate("熊竹", "15077886171", "321002199408304614");
+    }
+
+    @Test
+    public void testAge() {
+        System.out.println(ChronoUnit.YEARS.between(LocalDate.parse("321002199408304614".substring(6, 14),
+                DateTimeFormatter.ofPattern("yyyyMMdd")), LocalDate.now()));
+    }
 }

+ 46 - 0
src/test/java/com/izouma/nineth/TestRedissonLock.java

@@ -0,0 +1,46 @@
+package com.izouma.nineth;
+
+import org.junit.Test;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.concurrent.TimeUnit;
+
+public class TestRedissonLock extends ApplicationTests {
+
+    @Autowired
+    private RedissonClient redissonClient;
+
+    @Test
+    public void testLock() throws InterruptedException {
+        RLock lock = redissonClient.getLock("testLock");
+        Thread t1 = new Thread(() -> {
+            lock.lock(10, TimeUnit.SECONDS);
+            System.out.println("线程1获取锁");
+            try {
+                Thread.sleep(2000);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+            lock.unlock();
+            System.out.println("线程1释放锁");
+        });
+        Thread t2 = new Thread(() -> {
+            lock.lock(10, TimeUnit.SECONDS);
+            System.out.println("线程2获取锁");
+            try {
+                Thread.sleep(2000);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+            lock.unlock();
+            System.out.println("线程2释放锁");
+        });
+
+        t1.start();
+        t2.start();
+        t1.join();
+        t2.join();
+    }
+}