2 Комити 20803da06c ... 5c74334864

Аутор SHA1 Порука Датум
  hidewnd 5c74334864 fix:答题服务幂等ID生成逻辑优化 пре 1 недеља
  hidewnd 3e85370cb5 feat:ios服务登陆幂等处理 пре 1 недеља

+ 2 - 0
yt-common/src/main/java/com/ytpm/app/param/IosLoginParam.java

@@ -35,4 +35,6 @@ public class IosLoginParam {
     private String iconUrl;
     @ApiModelProperty(value = "手机信息json")
     private String phoneJson;
+    @ApiModelProperty(value = "幂等ID")
+    private String requestId;
 }

+ 65 - 35
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/controller/WxController.java

@@ -11,37 +11,45 @@ import com.ytpm.app.enums.AppTypeEnums;
 import com.ytpm.app.enums.LoginType;
 import com.ytpm.app.model.YtAppDefaultConfig;
 import com.ytpm.app.model.YtDyzAdRecord;
-import com.ytpm.app.model.YtDyzPowerRecord;
 import com.ytpm.app.model.YtDyzUser;
 import com.ytpm.app.param.AppConfigUpdateParam;
 import com.ytpm.app.param.IosLoginParam;
 import com.ytpm.app.param.WxLoginParam;
-import com.ytpm.app.view.*;
+import com.ytpm.app.view.IosPowerResView;
+import com.ytpm.app.view.IosUserInfo;
+import com.ytpm.app.view.WxDefaultConfig;
+import com.ytpm.app.view.WxLoginResult;
+import com.ytpm.app.view.WxUserInfo;
 import com.ytpm.feign.RiskFeign;
 import com.ytpm.general.RepMessage;
 import com.ytpm.general.Result;
 import com.ytpm.general.StatusCode;
-import com.ytpm.handle.CommonException;
 import com.ytpm.lemonios.dao.AdRecordMapper;
 import com.ytpm.lemonios.dao.AppUserMapper;
 import com.ytpm.lemonios.dao.DitchMapper;
+import com.ytpm.lemonios.redis.RedisService;
 import com.ytpm.lemonios.service.AppUserService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.TimeUnit;
 
 
 @Slf4j
@@ -51,16 +59,18 @@ import java.util.Objects;
 @RequestMapping("/wx")
 public class WxController {
     private final static String GRANT_TYPE = "authorization_code";
-    @Autowired
+    @Resource
     private AppUserMapper appUserMapper;
-    @Autowired
+    @Resource
     private AdRecordMapper recordMapper;
-    @Autowired
+    @Resource
     private RiskFeign riskFeign;
-    @Autowired
+    @Resource
     private AppUserService appUserService;
-    @Autowired
+    @Resource
     private DitchMapper ditchMapper;
+    @Resource
+    private RedisService redisService;
     @Value("${yt.ios.appid:}")
     private String appId;
 
@@ -93,25 +103,59 @@ public class WxController {
         return Result.resultOk(RepMessage.LOGIN_SUCCESS, old);
     }
 
+    @ApiOperation("获取IOS登陆幂等Token")
+    @GetMapping("/get/requestId")
+    public Result<String> getRequestId(@RequestParam("ditchId") String ditchId, @RequestParam("iosId") String iosId){
+        String redisKey = StrUtil.format("visitor:requestId:{}:{}", ditchId, iosId);
+        String requestId = "";
+        if (redisService.hasKey(redisKey)) {
+            requestId = redisService.getStr(redisKey);
+        }
+        if (StrUtil.isEmpty(requestId)) {
+            requestId = IdUtil.fastSimpleUUID();
+            boolean setSuccess = redisService.setIfAbsent(redisKey, requestId, 1, TimeUnit.MINUTES);
+            if (!setSuccess) {
+                requestId = redisService.getStr(redisKey);
+                if (StrUtil.isEmpty(requestId)) {
+                    requestId = IdUtil.fastSimpleUUID();
+                    redisService.setTimeOutMinutesStr(redisKey, requestId, 1);
+                } else {
+                    redisService.expire(redisKey, 1, TimeUnit.MINUTES);
+                }
+            }
+        }
+        return Result.resultObjOk(requestId);
+    }
+
     @PostMapping("/iosLogin")
     @ApiOperation("IOS登录")
     @Transactional
     public Result<YtDyzUser> iosLogin(@RequestBody IosLoginParam param, HttpServletRequest request) {
         //根据应用ID获取配置调用接口登录
         WxDefaultConfig defaultConfig = appUserMapper.getDefaultConfigByDitchId(param.getDitchId());
-
         // 当默认配置不存在时,尝试通过渠道信息获取备用配置
         if (Objects.isNull(defaultConfig)) {
             // 1. 检查渠道是否存在(提前拦截无效情况)
             YtDitch ditch = ditchMapper.selectById(param.getDitchId());
-            if (ditch == null) {
-                return new Result<>(StatusCode.ACCESS_ERR, "登录失败,未找到相应配置!");
+            if (ditch != null) {
+                // 2. 通过渠道的appId获取备用配置
+                defaultConfig = appUserMapper.getByAppId(ditch.getAppId());
             }
-            // 2. 通过渠道的appId获取备用配置
-            defaultConfig = appUserMapper.getByAppId(ditch.getAppId());
-            if (Objects.isNull(defaultConfig)) {
-                return new Result<>(StatusCode.ACCESS_ERR, "登录失败,未找到相应配置!");
+        }
+        if (Objects.isNull(defaultConfig)) {
+            return new Result<>(StatusCode.ACCESS_ERR, "登录失败,未找到相应配置!");
+        }
+        // 幂等请求校验
+        if (StrUtil.isNotEmpty(param.getRequestId())) {
+            String redisKey = StrUtil.format("visitor:requestId:{}:{}", param.getDitchId(), param.getIosId());
+            if (!redisService.hasKey(redisKey)) {
+                return new Result<>(StatusCode.ACCESS_ERR, "登录失败,重复请求!");
             }
+            String cacheKey = redisService.getStr(redisKey);
+            if (!StrUtil.equals(cacheKey, param.getRequestId())) {
+                return new Result<>(StatusCode.ACCESS_ERR, "登录失败,重复请求!");
+            }
+            redisService.del(redisKey);
         }
         IosUserInfo userInfo = setIosUserInfo(param);
         param.setLoginIp(getClientIp(request));
@@ -119,10 +163,10 @@ public class WxController {
         //调用风控服务校验默认风控配置
         old.setRiskCode("313");
         Result<?> result = riskFeign.checkRisk(old);
-        if(result.getCode()!=200){
-            return new Result<>(StatusCode.ACCESS_ERR,result.getMessage());
+        if (result.getCode() != 200) {
+            return new Result<>(StatusCode.ACCESS_ERR, result.getMessage());
         }
-        if (old.getLastLoginTime() != null && old.getRegistryTime() != null){
+        if (old.getLastLoginTime() != null && old.getRegistryTime() != null) {
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
             old.setLastLoginTimeStr(sdf.format(old.getLastLoginTime()));
             old.setRegistryTimeStr(sdf.format(old.getRegistryTime()));
@@ -142,20 +186,6 @@ public class WxController {
         }
         //2.拿3条记录 设置到user
         List<YtDyzAdRecord> adRecordList = recordMapper.getByIosIdBeforeLogin(param.getIosId());
-        List<YtDyzAdRecord> newAdRecordList = new ArrayList<>();
-        if (adRecordList != null && !adRecordList.isEmpty()) {
-            for (YtDyzAdRecord adRecord : adRecordList) {
-                if (adRecord.getAdSourceType() == 0){
-                    newAdRecordList.add(adRecord);
-                }
-                if (adRecord.getAdSourceType() == 2){
-                    newAdRecordList.add(adRecord);
-                }
-                if (adRecord.getAdSourceType() == 4){
-                    newAdRecordList.add(adRecord);
-                }
-            }
-        }
 
         user.setPreAdRecordList(adRecordList);
         user.setLoginType(LoginType.VISITOR);

+ 11 - 3
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/redis/RedisService.java

@@ -103,6 +103,10 @@ public class RedisService {
         valOpsStr.set(key,val,timeOut, TimeUnit.MINUTES);
     }
 
+    public boolean setIfAbsent(String key, String val ,long timeOut, TimeUnit timeUnit){
+        return Boolean.TRUE.equals(valOpsStr.setIfAbsent(key, val, timeOut, timeUnit));
+    }
+
     /**
      * 删除指定key
      * @param key
@@ -115,9 +119,13 @@ public class RedisService {
      * 设置指定key值的超时时间
      * @param key
      */
-    public void expire(String key,long timeOut){
-        TimeUnit timeUnit=TimeUnit.MILLISECONDS;
-        stringRedisTemplate.expire(key,timeOut, timeUnit);
+    public void expire(String key, long timeOut) {
+        TimeUnit timeUnit = TimeUnit.MILLISECONDS;
+        stringRedisTemplate.expire(key, timeOut, timeUnit);
+    }
+
+    public void expire(String key, long timeOut, TimeUnit timeUnit) {
+        stringRedisTemplate.expire(key, timeOut, timeUnit);
     }
 
     /**

+ 11 - 1
yt-question/yt-question-service/src/main/java/com/ytpm/question/controller/VisitorController.java

@@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
+import java.util.concurrent.TimeUnit;
 
 /**
  * 游客登陆
@@ -55,7 +56,16 @@ public class VisitorController {
         }
         if (StrUtil.isEmpty(requestId)) {
             requestId = IdUtil.fastSimpleUUID();
-            redisService.setTimeOutMinutesStr(redisKey, requestId, 1);
+            boolean setSuccess = redisService.setIfAbsent(redisKey, requestId, 1, TimeUnit.MINUTES);
+            if (!setSuccess) {
+                requestId = redisService.getStr(redisKey);
+                if (StrUtil.isEmpty(requestId)) {
+                    requestId = IdUtil.fastSimpleUUID();
+                    redisService.setTimeOutMinutesStr(redisKey, requestId, 1);
+                } else {
+                    redisService.expire(redisKey, 1, TimeUnit.MINUTES);
+                }
+            }
         }
         return Result.resultObjOk(requestId);
     }

+ 8 - 0
yt-question/yt-question-service/src/main/java/com/ytpm/question/redis/RedisService.java

@@ -106,6 +106,10 @@ public class RedisService {
         stringRedisTemplate.opsForValue().set(key, val, timeOut, TimeUnit.MINUTES);
     }
 
+    public boolean setIfAbsent(String key, String val ,long timeOut, TimeUnit timeUnit){
+        return Boolean.TRUE.equals(valOpsObj.setIfAbsent(key, val, timeOut, timeUnit));
+    }
+
     /**
      * 删除指定key
      *
@@ -125,6 +129,10 @@ public class RedisService {
         stringRedisTemplate.expire(key, timeOut, timeUnit);
     }
 
+    public void expire(String key, long timeOut, TimeUnit timeUnit) {
+        stringRedisTemplate.expire(key, timeOut, timeUnit);
+    }
+
     /**
      * 根据前缀批量删除
      *