Browse Source

修复部分缺陷

marxjaw 4 months ago
parent
commit
a63aaff181
45 changed files with 685 additions and 132 deletions
  1. 0 6
      yt-advertise/advertise-service/src/main/java/com/ytpm/service/TakuApiService.java
  2. 5 2
      yt-agent/agent-service/src/main/java/com/ytpm/controller/YtAppUserController.java
  3. 7 0
      yt-agent/agent-service/src/main/java/com/ytpm/dao/AppMapper.java
  4. 2 1
      yt-agent/agent-service/src/main/java/com/ytpm/service/YtAppUserService.java
  5. 35 12
      yt-agent/agent-service/src/main/java/com/ytpm/service/impl/YtAppUserServiceImpl.java
  6. 6 0
      yt-agent/agent-service/src/main/resources/mapper/AppMapper.xml
  7. 15 0
      yt-app/app-feign/src/main/java/com/ytpm/feign/AppFeign.java
  8. 1 1
      yt-app/app-service/src/main/java/com/ytpm/config/YtWebMvcConfigurerAdapter.java
  9. 2 2
      yt-app/app-service/src/main/java/com/ytpm/config/interceptor/PostHttpRequestInterceptor.java
  10. 2 2
      yt-app/app-service/src/main/java/com/ytpm/config/interceptor/UserActionInterceptor.java
  11. 2 2
      yt-app/app-service/src/main/java/com/ytpm/config/shiro/UserRealm.java
  12. 70 0
      yt-app/app-service/src/main/java/com/ytpm/controller/UserController.java
  13. 113 7
      yt-app/app-service/src/main/java/com/ytpm/controller/WxController.java
  14. 18 2
      yt-app/app-service/src/main/java/com/ytpm/dao/AppUserMapper.java
  15. 9 1
      yt-app/app-service/src/main/java/com/ytpm/dao/LoginRecordMapper.java
  16. 1 1
      yt-app/app-service/src/main/java/com/ytpm/service/AppUserService.java
  17. 1 1
      yt-app/app-service/src/main/java/com/ytpm/service/impl/AppUserServiceImpl.java
  18. 1 1
      yt-app/app-service/src/main/java/com/ytpm/service/impl/QuestionServiceImpl.java
  19. 0 1
      yt-app/app-service/src/main/java/com/ytpm/util/ShiroFilterUtils.java
  20. 2 2
      yt-app/app-service/src/main/java/com/ytpm/util/ShiroSubjectUtil.java
  21. 75 4
      yt-app/app-service/src/main/resources/mapper/AppUserMapper.xml
  22. 6 0
      yt-app/app-service/src/main/resources/mapper/LoginRecordMapper.xml
  23. 11 0
      yt-common/src/main/java/com/ytpm/agent/enums/UserStatusEnum.java
  24. 2 0
      yt-common/src/main/java/com/ytpm/agent/model/YtPlatformBanned.java
  25. 2 0
      yt-common/src/main/java/com/ytpm/agent/model/YtPlatformDeblocking.java
  26. 1 1
      yt-common/src/main/java/com/ytpm/app/model/ActiveUser.java
  27. 1 2
      yt-common/src/main/java/com/ytpm/app/model/YtDyzLoginRecord.java
  28. 1 1
      yt-common/src/main/java/com/ytpm/app/model/YtDyzPowerRecord.java
  29. 13 2
      yt-common/src/main/java/com/ytpm/app/model/YtDyzUser.java
  30. 2 0
      yt-common/src/main/java/com/ytpm/app/view/WxDefaultConfig.java
  31. 12 0
      yt-common/src/main/java/com/ytpm/risk/view/RiskAccessView.java
  32. 3 0
      yt-risk/risk-feign/src/main/java/com/ytpm/feign/RiskFeign.java
  33. 5 0
      yt-risk/risk-manage/pom.xml
  34. 1 1
      yt-risk/risk-manage/src/main/java/com/ytpm/config/ResourceServerConfig.java
  35. 16 0
      yt-risk/risk-manage/src/main/java/com/ytpm/config/WebMvcConfig.java
  36. 30 0
      yt-risk/risk-manage/src/main/java/com/ytpm/controller/PublicApiController.java
  37. 2 2
      yt-risk/risk-manage/src/main/java/com/ytpm/controller/RiskManageController.java
  38. 5 0
      yt-risk/risk-manage/src/main/java/com/ytpm/dao/RiskConfigMapper.java
  39. 6 0
      yt-risk/risk-manage/src/main/java/com/ytpm/dao/RiskUserMapper.java
  40. 38 0
      yt-risk/risk-manage/src/main/java/com/ytpm/interceptor/OpenApiInterceptor.java
  41. 7 1
      yt-risk/risk-manage/src/main/java/com/ytpm/service/RiskService.java
  42. 99 29
      yt-risk/risk-manage/src/main/java/com/ytpm/service/impl/RiskServiceImpl.java
  43. 20 0
      yt-risk/risk-manage/src/main/resources/mapper/RiskConfigMapper.xml
  44. 22 45
      yt-risk/risk-manage/src/main/resources/mapper/RiskManageMapper.xml
  45. 13 0
      yt-risk/risk-manage/src/main/resources/mapper/RiskUserMapper.xml

+ 0 - 6
yt-advertise/advertise-service/src/main/java/com/ytpm/service/TakuApiService.java

@@ -88,12 +88,6 @@ public interface TakuApiService {
      * 查询综合报表
      */
     Result<ComprehensiveReportView> comprehensiveReport(ComprehensiveReportParam param);
-
-    /**
-     * TODO 查询留存价值报表  建议晚上10点后拉取前一日较为准确
-     */
-
-
     /**
      * 查询ROI报表
      */

+ 5 - 2
yt-agent/agent-service/src/main/java/com/ytpm/controller/YtAppUserController.java

@@ -1,5 +1,7 @@
 package com.ytpm.controller;
 
+import com.ytpm.agent.model.YtAppUser;
+import com.ytpm.agent.view.AgentUserInfo;
 import com.ytpm.app.param.YtAppUserListParam;
 import com.ytpm.app.view.AppUserStaticsView;
 import com.ytpm.app.view.YtAppUserListView;
@@ -7,6 +9,7 @@ import com.ytpm.general.ResultTable;
 import com.ytpm.service.YtAppUserService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -30,8 +33,8 @@ public class YtAppUserController {
      */
     @PostMapping("/getUserList")
     @ApiOperation(value = "查询App用户列表")
-    public ResultTable<YtAppUserListView> selectAppUserList(@RequestBody YtAppUserListParam param){
-        return appUserService.selectAppUserList(param);
+    public ResultTable<YtAppUserListView> selectAppUserList(@RequestBody YtAppUserListParam param, @AuthenticationPrincipal AgentUserInfo userInfo) {
+        return appUserService.selectAppUserList(param, userInfo);
     }
 
     /**

+ 7 - 0
yt-agent/agent-service/src/main/java/com/ytpm/dao/AppMapper.java

@@ -4,6 +4,8 @@ import com.ytpm.agent.model.YtApp;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
+
 @Mapper
 public interface AppMapper {
     /**
@@ -25,4 +27,9 @@ public interface AppMapper {
      * 删除应用
      */
     void deleteApp(String appId);
+
+    /**
+     * 查询用户的应用列表
+     */
+    List<YtApp> queryAll(@Param("userId") String userId);
 }

+ 2 - 1
yt-agent/agent-service/src/main/java/com/ytpm/service/YtAppUserService.java

@@ -1,5 +1,6 @@
 package com.ytpm.service;
 
+import com.ytpm.agent.view.AgentUserInfo;
 import com.ytpm.app.param.YtAppUserListParam;
 import com.ytpm.app.view.AppUserStaticsView;
 import com.ytpm.app.view.YtAppUserListView;
@@ -13,7 +14,7 @@ public interface YtAppUserService {
      * @param param 列表入参
      * @return 分页列表
      */
-    ResultTable<YtAppUserListView> selectAppUserList(YtAppUserListParam param);
+    ResultTable<YtAppUserListView> selectAppUserList(YtAppUserListParam param, AgentUserInfo userInfo);
 
     /**
      * 查询用户广告数据统计列表

+ 35 - 12
yt-agent/agent-service/src/main/java/com/ytpm/service/impl/YtAppUserServiceImpl.java

@@ -1,17 +1,24 @@
 package com.ytpm.service.impl;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
+import com.ytpm.agent.model.YtApp;
+import com.ytpm.agent.view.AgentUserInfo;
 import com.ytpm.app.model.YtAppUserLoginRecord;
+import com.ytpm.app.model.YtDyzLoginRecord;
+import com.ytpm.app.model.YtDyzUser;
 import com.ytpm.app.param.YtAppUserListParam;
 import com.ytpm.app.view.AppUserStaticsView;
 import com.ytpm.app.view.YtAppUserListView;
 import com.ytpm.dao.AgentStaticsMapper;
+import com.ytpm.dao.AppMapper;
 import com.ytpm.dao.AppUserLoginMapper;
 import com.ytpm.dao.AppUserMapper;
 import com.ytpm.dao.AppVideoWatchMapper;
 import com.ytpm.dao.AppWithdrawMapper;
+import com.ytpm.feign.AppFeign;
 import com.ytpm.general.ResultTable;
 import com.ytpm.service.YtAppUserService;
 import org.springframework.stereotype.Service;
@@ -31,6 +38,8 @@ public class YtAppUserServiceImpl implements YtAppUserService {
     @Resource
     private AppUserMapper appUserMapper;
     @Resource
+    private AppMapper appMapper;
+    @Resource
     private AppUserLoginMapper userLoginMapper;
     @Resource
     private AppVideoWatchMapper videoWatchMapper;
@@ -38,6 +47,8 @@ public class YtAppUserServiceImpl implements YtAppUserService {
     private AppWithdrawMapper withdrawMapper;
     @Resource
     private AgentStaticsMapper staticsMapper;
+    @Resource
+    private AppFeign appFeign;
 
 
     /**
@@ -46,18 +57,30 @@ public class YtAppUserServiceImpl implements YtAppUserService {
      * @return 分页列表
      */
     @Override
-    public ResultTable<YtAppUserListView> selectAppUserList(YtAppUserListParam param) {
-        PageHelper.startPage(param.getPage(), param.getLimit());
-        List<YtAppUserListView> views = appUserMapper.selectAppUserList(param);
-        if(CollUtil.isNotEmpty(views)){
-            String userId;
-            String appId;
-            for (YtAppUserListView view : views) {
-                userId = view.getUserId();
-                appId = view.getAppId();
-                setLoginInfo(userId,appId,view);//查询并设置登录信息
-                setTodayVideoNum(userId,appId,view);//查询用户当日播放视频总数
-                setWithDrawInfo(userId,appId,view);//查询用户提现记录计算提现笔数
+    public ResultTable<YtAppUserListView> selectAppUserList(YtAppUserListParam param, AgentUserInfo userInfo) {
+        //查询当前用户的所有应用  TODO 后续增加应用的 Feign 全路径包名
+        List<YtApp> ytApps = appMapper.queryAll(userInfo.getUserId());
+        //远程调用各应用查询用户数据 目前先只有好运答题王 TODO 根据包名反射创建Feign 遍历远程方法进行调用获取用户信息
+        List<YtAppUserListView> views = new ArrayList<>();
+        ResultTable<YtDyzUser> resultTable = appFeign.queryAll();
+        for (YtApp ytApp : ytApps) {
+            if("a684009039113d".equals(ytApp.getAppId())){
+                YtAppUserListView ytAppUserListView;
+                for (YtDyzUser datum : resultTable.getData()) {
+                    List<YtDyzLoginRecord> recordList = datum.getLoginRecordList();
+                    ytAppUserListView = new YtAppUserListView();
+                    BeanUtil.copyProperties(datum, ytAppUserListView);
+                    ytAppUserListView.setAppId(ytApp.getAppId());
+                    ytAppUserListView.setAppName(ytApp.getAppName());
+                    ytAppUserListView.setAppType(ytApp.getAppType());
+                    ytAppUserListView.setChannelId(ytApp.getChannelId());
+                    if(CollUtil.isNotEmpty(recordList)){
+                        ytAppUserListView.setDeviceRepeatCount((int) recordList.stream().map(YtDyzLoginRecord::getDeviceModel).distinct().count());
+                        ytAppUserListView.setIpRepeatCount((int)recordList.stream().map(YtDyzLoginRecord::getIpAddr).distinct().count());
+                        ytAppUserListView.setCommunicationOperator(recordList.get(0).getOperator());
+                    }
+                    views.add(ytAppUserListView);
+                }
             }
         }
         return ResultTable.resultTableOk(new PageInfo<YtAppUserListView>(views));

+ 6 - 0
yt-agent/agent-service/src/main/resources/mapper/AppMapper.xml

@@ -79,4 +79,10 @@
         from yt_app
         where app_id = #{appId}
     </select>
+    <select id="queryAll" resultType="com.ytpm.agent.model.YtApp">
+        select
+            app_id, app_key, app_name, user_id, app_type, apk_url, qr_code, version_code, update_tips, enabled, store_on_sale, store_type, store_url, package_name, domain, category, sub_category, coppa, screen_orientation, ccpa
+        from yt_app
+        where user_id = #{userId}
+    </select>
 </mapper>

+ 15 - 0
yt-app/app-feign/src/main/java/com/ytpm/feign/AppFeign.java

@@ -1,7 +1,22 @@
 package com.ytpm.feign;
 
+import com.ytpm.app.model.YtDyzUser;
+import com.ytpm.general.Result;
+import com.ytpm.general.ResultTable;
 import org.springframework.cloud.openfeign.FeignClient;
+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.RequestParam;
 
 @FeignClient(name = "app-service")
 public interface AppFeign {
+    @GetMapping("/user/queryAll")
+    ResultTable<YtDyzUser> queryAll();
+    @GetMapping("/user/getUserInfo")
+    Result<YtDyzUser> getUserInfo(@RequestParam("userId") String userId);
+    @GetMapping("/user/getUserList")
+    ResultTable<YtDyzUser> getUserList(@RequestParam("userIds") String userIds);
+    @PostMapping("/user/updateUserInfo")
+    Result<?> updateUserInfo(@RequestBody YtDyzUser dyzUser);
 }

+ 1 - 1
yt-app/app-service/src/main/java/com/ytpm/config/YtWebMvcConfigurerAdapter.java

@@ -22,7 +22,7 @@ public class YtWebMvcConfigurerAdapter implements WebMvcConfigurer {
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
         registry.addInterceptor(new HttpInterceptor()).addPathPatterns("/**").excludePathPatterns("/resources/**");
-        registry.addInterceptor(userActionInterceptor).addPathPatterns("/**").excludePathPatterns("/wx/**","/question/**","/sys/toLogin*","/login/**","/resources/**","/fastDFS/**","/error",
+        registry.addInterceptor(userActionInterceptor).addPathPatterns("/**").excludePathPatterns("/user/**","/wx/**","/question/**","/sys/toLogin*","/login/**","/resources/**","/fastDFS/**","/error",
                 "/doc.html","/api/v2/**","/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security",
                 "/swagger-ui.html", "/webjars/**","/swagger-resources/configuration/ui","/swagger-ui.html");
         registry.addInterceptor(postHttpRequestInterceptor).addPathPatterns("/**").excludePathPatterns("/sys/toLogin*","/resources/**"

+ 2 - 2
yt-app/app-service/src/main/java/com/ytpm/config/interceptor/PostHttpRequestInterceptor.java

@@ -4,8 +4,8 @@ import com.alibaba.fastjson.JSON;
 import com.ytpm.constant.StrConstant;
 import com.ytpm.general.Result;
 import com.ytpm.general.StatusCode;
-import com.ytpm.model.ActiveUser;
-import com.ytpm.model.YtDyzUser;
+import com.ytpm.app.model.ActiveUser;
+import com.ytpm.app.model.YtDyzUser;
 import com.ytpm.util.RedisService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.shiro.SecurityUtils;

+ 2 - 2
yt-app/app-service/src/main/java/com/ytpm/config/interceptor/UserActionInterceptor.java

@@ -2,8 +2,8 @@ package com.ytpm.config.interceptor;
 
 import com.ytpm.constant.StrConstant;
 import com.ytpm.general.Result;
-import com.ytpm.model.ActiveUser;
-import com.ytpm.model.YtDyzUser;
+import com.ytpm.app.model.ActiveUser;
+import com.ytpm.app.model.YtDyzUser;
 import com.ytpm.util.ShiroFilterUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.shiro.SecurityUtils;

+ 2 - 2
yt-app/app-service/src/main/java/com/ytpm/config/shiro/UserRealm.java

@@ -1,7 +1,7 @@
 package com.ytpm.config.shiro;
 
-import com.ytpm.model.ActiveUser;
-import com.ytpm.model.YtDyzUser;
+import com.ytpm.app.model.ActiveUser;
+import com.ytpm.app.model.YtDyzUser;
 import com.ytpm.service.AppUserService;
 import org.apache.shiro.authc.AuthenticationException;
 import org.apache.shiro.authc.AuthenticationInfo;

+ 70 - 0
yt-app/app-service/src/main/java/com/ytpm/controller/UserController.java

@@ -0,0 +1,70 @@
+package com.ytpm.controller;
+
+import com.github.pagehelper.PageInfo;
+import com.ytpm.app.model.YtDyzUser;
+import com.ytpm.dao.AppUserMapper;
+import com.ytpm.dao.LoginRecordMapper;
+import com.ytpm.general.RepMessage;
+import com.ytpm.general.Result;
+import com.ytpm.general.ResultTable;
+import org.springframework.beans.factory.annotation.Autowired;
+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 java.util.List;
+
+@RestController
+@RequestMapping("/user")
+public class UserController {
+
+    @Autowired
+    private AppUserMapper appUserMapper;
+    @Autowired
+    private LoginRecordMapper loginRecordMapper;
+
+    /**
+     * 查询app 所有玩家
+     */
+    @GetMapping("/queryAll")
+    public ResultTable<YtDyzUser> queryAll(){
+        List<YtDyzUser> dyzUsers = appUserMapper.queryAll();
+        for (YtDyzUser user : dyzUsers) {
+            user.setLoginRecordList(loginRecordMapper.getLoginRecords(user.getWxOpenId()));
+        }
+        return ResultTable.resultTableOk(new PageInfo<YtDyzUser>(dyzUsers));
+    }
+
+    /**
+     * 主键查询用户信息
+     */
+    @GetMapping("/getUserInfo")
+    public Result<YtDyzUser> getUserInfo(@RequestParam("userId") String userId){
+        YtDyzUser user = appUserMapper.selectPrimaryKey(userId);
+        user.setLoginRecordList(loginRecordMapper.getLoginRecords(user.getWxOpenId()));
+        return Result.resultObjOk(user);
+    }
+
+    /**
+     * 查询用户信息
+     */
+    @GetMapping("/getUserList")
+    public ResultTable<YtDyzUser> getUserList(@RequestParam("userIds") String userIds){
+        List<YtDyzUser> userList = appUserMapper.getUserList(userIds);
+        for (YtDyzUser user : userList) {
+            user.setLoginRecordList(loginRecordMapper.getLoginRecords(user.getWxOpenId()));
+        }
+        return ResultTable.resultTableOk(new PageInfo<>(userList));
+    }
+    /**
+     * 修改用户信息
+     */
+    @PostMapping("/updateUserInfo")
+    public Result<?> updateUserInfo(@RequestBody YtDyzUser dyzUser){
+        appUserMapper.updateUser(dyzUser);
+        return Result.resultOk(RepMessage.MODIFY_SUCCESS);
+    }
+}

+ 113 - 7
yt-app/app-service/src/main/java/com/ytpm/controller/WxController.java

@@ -1,5 +1,7 @@
 package com.ytpm.controller;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.http.HttpUtil;
 import com.alibaba.fastjson.JSON;
@@ -13,13 +15,16 @@ import com.ytpm.constant.StrConstant;
 import com.ytpm.dao.AppUserMapper;
 import com.ytpm.dao.LoginRecordMapper;
 import com.ytpm.dao.QuestionMapper;
+import com.ytpm.feign.RiskFeign;
 import com.ytpm.general.RepMessage;
 import com.ytpm.general.Result;
 import com.ytpm.handle.CustomerException;
-import com.ytpm.model.ActiveUser;
-import com.ytpm.model.YtDyzLoginRecord;
-import com.ytpm.model.YtDyzPowerRecord;
-import com.ytpm.model.YtDyzUser;
+import com.ytpm.app.model.ActiveUser;
+import com.ytpm.app.model.YtDyzLoginRecord;
+import com.ytpm.app.model.YtDyzPowerRecord;
+import com.ytpm.app.model.YtDyzUser;
+import com.ytpm.risk.view.RiskConfigView;
+import com.ytpm.risk.view.RiskTemplateView;
 import com.ytpm.util.ShiroSubjectUtil;
 import com.ytpm.util.WebUtils;
 import io.swagger.annotations.Api;
@@ -38,8 +43,14 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.lang.reflect.Field;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
 import java.util.Date;
+import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 
 @Slf4j
@@ -50,7 +61,11 @@ public class WxController {
     @Value("${wx.openid}")
     private  String APP_ID;
     @Value("${wx.secret}")
-    private  String SECRET;
+    private String SECRET;
+    @Value("${yt.platform.secret}")
+    private String PLATFORM_ACCESS_SECRET;
+    @Value("${yt.platform.appId}")
+    private String PLATFORM_APP_ID;
     private final static String GRANT_TYPE = "authorization_code";
 
     @Autowired
@@ -59,6 +74,8 @@ public class WxController {
     private LoginRecordMapper loginRecordMapper;
     @Autowired
     private QuestionMapper questionMapper;
+    @Autowired
+    private RiskFeign riskFeign;
 
     @PostMapping("/login")
     @ApiOperation("微信登录")
@@ -69,7 +86,6 @@ public class WxController {
         String result = HttpUtil.get(wxLoginUrl);
         WxLoginResult loginResult = JSON.parseObject(result, WxLoginResult.class);
         log.error("授权码获取的登录结果:{}",loginResult);
-        // TODO 拿到openid 调用风控服务过审,不满足风控要求则抛出异常
         // 根据token和openid 获取用户信息
         String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token="+loginResult.getAccess_token()+"&openid="+loginResult.getOpenid()+"&lang=zh_CN";
         String curUser = HttpUtil.get(userInfoUrl);
@@ -81,12 +97,17 @@ public class WxController {
         //查询用户表是否存在该用户,不存在则注册保存用户信息
         YtDyzUser old = appUserMapper.getYtAppUser(loginResult.getOpenid());
         if(Objects.nonNull(old)){
+            //处于风控状态的用户不允许登录
+            if(!old.getUserStatus().equals(UserStatusEnum.NORMAL.getCode())){
+                throw new CustomerException("当前用户处于"+UserStatusEnum.getByCode(old.getUserStatus())+"中,无法登录");
+            }
 //            ShiroAuth(wxUserInfo);//Shiro 登录逻辑
             YtDyzUser newUser = new YtDyzUser();
             newUser.setNickName(wxUserInfo.getNickname());
             newUser.setHeadImg(wxUserInfo.getHeadimgurl());
             newUser.setLastLoginTime(new Date());
             newUser.setLastLoginIp(param.getLoginIp());
+            newUser.setLoginDays(old.getLoginDays()+1);
             appUserMapper.updateUser(newUser);
         }else{
             old = new YtDyzUser();
@@ -94,11 +115,96 @@ public class WxController {
         }
         // 添加用户登录记录
         addLoginRecord(wxUserInfo,param);
+        //TODO 返回数据前校验当前应用的风控规则
+//        Result<RiskTemplateView> riskCondition = riskFeign.getRiskCondition(PLATFORM_APP_ID, PLATFORM_ACCESS_SECRET);
+//        checkCondition(old,riskCondition.getData());
         //设置最后一次答题问题ID、今日答题数、历史答题数
         setExtInfo(old,wxUserInfo.getHeadimgurl());
         return Result.resultOk(RepMessage.LOGIN_SUCCESS, old);
     }
 
+    /**
+     * 校验风控规则
+     * TODO 第一版本仅处理登录相关  后续优化成 按照粒度(不同APP不同粒度:如答题粒度分为 用户、登录、答题记录、提现记录等) 划分
+     */
+    private void checkCondition(Object obj,RiskTemplateView data) {
+        List<RiskConfigView> configList = data.getConfigList();
+        for (RiskConfigView configView : configList) {
+            //校验配置类型对应字段 这里传入的Obj 就是风控粒度对象
+            checkConfig(obj,configView);
+        }
+    }
+
+    /**
+     * 逐个校验配置  当前仅有好运答题王的用户
+     */
+    private void checkConfig(Object obj, RiskConfigView vo) {
+        Field[] fields = obj.getClass().getDeclaredFields();
+        List<Field> cFields = Arrays.stream(fields).filter(
+                s -> s.getName().equals(vo.getFieldName())).collect(Collectors.toList());
+        if(CollUtil.isEmpty(cFields)){
+            throw new CustomerException("未匹配到准入条件字段请联系管理员!");
+        }
+        Field conditionField = cFields.get(0);
+        conditionField.setAccessible(true);
+        try{
+            //多选校验值包含 单选校验值相等
+            Object o = conditionField.get(obj);
+            if(2==vo.getMulty()){
+                checkSameVal(o, vo.getConfigVal(), vo.getFieldDesc());
+            }else{
+                checkContainsVal(o,vo.getConfigVal(), vo.getFieldDesc());
+            }
+        }catch (Exception e){
+            throw new CustomerException(e.getMessage());
+        }
+    }
+
+    /**
+     * 校验值包含
+     */
+    private void checkContainsVal(Object o, String configVal, String fieldDesc) {
+        try{
+            String[] split = configVal.split(",");
+            if(o instanceof Date){
+                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                Date begin = format.parse(split[0]);
+                Date end = format.parse(split[1]);
+                Date date = (Date) o;
+                if(!DateUtil.isIn(date, begin, end)){
+                    throw new CustomerException(fieldDesc+"不符合准入条件!");
+                }
+            }else{
+                if(!Arrays.asList(split).contains(o.toString())){
+                    throw new CustomerException(fieldDesc+"不符合准入条件!");
+                }
+            }
+        }catch (Exception e){
+            throw new CustomerException(e.getMessage());
+        }
+    }
+
+    /**
+     * 校验值相同
+     */
+    private void checkSameVal(Object o, String configVal,String desc) {
+        if(o instanceof Integer && Integer.parseInt(configVal) != (Integer) o){
+            throw new CustomerException(desc+"不符合准入条件!");
+        }
+        if(o instanceof String && !configVal.equals(String.valueOf(o))){
+            throw new CustomerException(desc+"不符合准入条件!");
+        }
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        try {
+            if(o instanceof Date && !format.parse(configVal).equals((Date)o)){
+                throw new CustomerException(desc+"不符合准入条件!");
+            }
+        } catch (ParseException e) {
+            throw new CustomerException(e.getMessage());
+        }
+    }
+
+
     /**
      * Shiro 认证登录
      */
@@ -162,7 +268,7 @@ public class WxController {
     @ApiOperation("获取微信默认配置项")
     @GetMapping("/defaultConfig")
     public Result<WxDefaultConfig> getWxDefaultConfig() {
-        return Result.resultObjOk(new WxDefaultConfig(APP_ID, SECRET));
+        return Result.resultObjOk(new WxDefaultConfig(APP_ID, SECRET,PLATFORM_APP_ID,PLATFORM_ACCESS_SECRET));
     }
 
     @ApiOperation("体力增加")

+ 18 - 2
yt-app/app-service/src/main/java/com/ytpm/dao/AppUserMapper.java

@@ -1,10 +1,12 @@
 package com.ytpm.dao;
 
-import com.ytpm.model.YtDyzPowerRecord;
-import com.ytpm.model.YtDyzUser;
+import com.ytpm.app.model.YtDyzPowerRecord;
+import com.ytpm.app.model.YtDyzUser;
 import org.apache.ibatis.annotations.Param;
 import org.mapstruct.Mapper;
 
+import java.util.List;
+
 @Mapper
 public interface AppUserMapper {
 
@@ -13,6 +15,11 @@ public interface AppUserMapper {
      */
     YtDyzUser getYtAppUser(@Param("openid")String openid);
 
+    /**
+     * 主键查询
+     */
+    YtDyzUser selectPrimaryKey(@Param("userId")String userId);
+
     /**
      * 新增应用用户
      */
@@ -36,4 +43,13 @@ public interface AppUserMapper {
      * 修改用户信息
      */
     void updateUser(YtDyzUser newUser);
+    /**
+     * 查询所有玩家
+     */
+    List<YtDyzUser> queryAll();
+
+    /**
+     * 查询用户信息
+     */
+    List<YtDyzUser> getUserList(@Param("userIds") String userIds);
 }

+ 9 - 1
yt-app/app-service/src/main/java/com/ytpm/dao/LoginRecordMapper.java

@@ -1,12 +1,20 @@
 package com.ytpm.dao;
 
-import com.ytpm.model.YtDyzLoginRecord;
+import com.ytpm.app.model.YtDyzLoginRecord;
+import org.apache.ibatis.annotations.Param;
 import org.mapstruct.Mapper;
 
+import java.util.List;
+
 @Mapper
 public interface LoginRecordMapper {
     /**
      * 增加用户登录记录
      */
     void insertOne(YtDyzLoginRecord loginRecord);
+
+    /**
+     * 查询用户登录记录
+     */
+    List<YtDyzLoginRecord> getLoginRecords(@Param("wxOpenId")String wxOpenId);
 }

+ 1 - 1
yt-app/app-service/src/main/java/com/ytpm/service/AppUserService.java

@@ -1,6 +1,6 @@
 package com.ytpm.service;
 
-import com.ytpm.model.YtDyzUser;
+import com.ytpm.app.model.YtDyzUser;
 
 public interface AppUserService {
     /**

+ 1 - 1
yt-app/app-service/src/main/java/com/ytpm/service/impl/AppUserServiceImpl.java

@@ -1,7 +1,7 @@
 package com.ytpm.service.impl;
 
 import com.ytpm.dao.AppUserMapper;
-import com.ytpm.model.YtDyzUser;
+import com.ytpm.app.model.YtDyzUser;
 import com.ytpm.service.AppUserService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;

+ 1 - 1
yt-app/app-service/src/main/java/com/ytpm/service/impl/QuestionServiceImpl.java

@@ -11,7 +11,7 @@ import com.ytpm.dao.QuestionMapper;
 import com.ytpm.general.RepMessage;
 import com.ytpm.general.Result;
 import com.ytpm.general.ResultTable;
-import com.ytpm.model.YtDyzPowerRecord;
+import com.ytpm.app.model.YtDyzPowerRecord;
 import com.ytpm.service.QuestionService;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;

+ 0 - 1
yt-app/app-service/src/main/java/com/ytpm/util/ShiroFilterUtils.java

@@ -10,7 +10,6 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.PrintWriter;
 
-import com.ytpm.model.ActiveUser;
 /**
  * 
  * @项目名称:zld-xdxt

+ 2 - 2
yt-app/app-service/src/main/java/com/ytpm/util/ShiroSubjectUtil.java

@@ -1,7 +1,7 @@
 package com.ytpm.util;
 
-import com.ytpm.model.ActiveUser;
-import com.ytpm.model.YtDyzUser;
+import com.ytpm.app.model.ActiveUser;
+import com.ytpm.app.model.YtDyzUser;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.session.Session;
 import org.apache.shiro.subject.Subject;

+ 75 - 4
yt-app/app-service/src/main/resources/mapper/AppUserMapper.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ytpm.dao.AppUserMapper">
-    <insert id="addOne" parameterType="com.ytpm.model.YtDyzUser">
+    <insert id="addOne" parameterType="com.ytpm.app.model.YtDyzUser">
         insert into yt_dyz_user
         (
          user_id,
@@ -65,22 +65,93 @@
     <update id="subOnePower">
         update yt_dyz_user set power = power-1 where user_id = #{userId}
     </update>
-    <update id="updateUser">
+    <update id="updateUser" parameterType="com.ytpm.app.model.YtDyzUser">
         update yt_dyz_user
         <set>
             <if test="nickName != null">
                 nick_name = #{nickName},
             </if>
             <if test="headImg != null">
-                head_img = #{headImg}
+                head_img = #{headImg},
+            </if>
+            <if test="power != null">
+                power = #{power},
+            </if>
+            <if test="registryTime != null">
+                registry_time = #{registryTime},
+            </if>
+            <if test="lastLoginTime != null">
+                last_login_time = #{lastLoginTime},
+            </if>
+            <if test="lastLoginIp != null">
+                last_login_ip = #{lastLoginIp},
+            </if>
+            <if test="loginDays != null">
+                login_days = #{loginDays},
+            </if>
+            <if test="totalVideo != null">
+                total_video = #{totalVideo},
+            </if>
+            <if test="totalIncome != null">
+                total_income = #{totalIncome},
+            </if>
+            <if test="redPacketBalance != null">
+                red_packet_balance = #{redPacketBalance},
+            </if>
+            <if test="redPacketAmount != null">
+                red_packet_amount = #{redPacketAmount},
+            </if>
+            <if test="pointsBalance != null">
+                points_balance = #{pointsBalance},
+            </if>
+            <if test="pointsTotal != null">
+                points_total = #{pointsTotal},
+            </if>
+            <if test="withdrawTotal != null">
+                withdraw_total = #{withdrawTotal},
+            </if>
+            <if test="signDays != null">
+                sign_days = #{signDays},
+            </if>
+            <if test="userStatus != null">
+                user_status = #{userStatus},
+            </if>
+            <if test="riskReason != null">
+                risk_reason = #{riskReason},
+            </if>
+            <if test="wxOpenId != null">
+                wx_open_id = #{wxOpenId},
+            </if>
+            <if test="platformId != null">
+                platform_id = #{platformId}
             </if>
         </set>
         where user_id = #{userId}
     </update>
-    <select id="getYtAppUser" resultType="com.ytpm.model.YtDyzUser">
+    <select id="getYtAppUser" resultType="com.ytpm.app.model.YtDyzUser">
         select
            user_id, nick_name,head_img, power, registry_time, last_login_time, last_login_ip, login_days, total_video, total_income, red_packet_balance, red_packet_amount, points_balance, points_total, withdraw_total, sign_days, user_status, risk_reason, wx_open_id, platform_id
         from yt_dyz_user
         where wx_open_id = #{openid}
     </select>
+    <select id="queryAll" resultType="com.ytpm.app.model.YtDyzUser">
+        select
+            user_id, nick_name,head_img, power, registry_time, last_login_time, last_login_ip, login_days, total_video, total_income, red_packet_balance, red_packet_amount, points_balance, points_total, withdraw_total, sign_days, user_status, risk_reason, wx_open_id, platform_id
+        from yt_dyz_user
+    </select>
+    <select id="selectPrimaryKey" resultType="com.ytpm.app.model.YtDyzUser">
+        select
+            user_id, head_img, nick_name, registry_time, last_login_time, last_login_ip, login_days, total_video, total_income, red_packet_balance, red_packet_amount, points_balance, points_total, withdraw_total, sign_days, user_status, risk_reason, wx_open_id, platform_id, power
+        from yt_dyz_user
+        where user_id = #{userId}
+    </select>
+    <select id="getUserList" resultType="com.ytpm.app.model.YtDyzUser">
+        select
+            user_id, head_img, nick_name, registry_time, last_login_time, last_login_ip, login_days, total_video, total_income, red_packet_balance, red_packet_amount, points_balance, points_total, withdraw_total, sign_days, user_status, risk_reason, wx_open_id, platform_id, power
+        from yt_dyz_user
+        where user_id in
+        <foreach collection="userIds.split(',')" item="item" separator="," open="(" close=")">
+            #{item}
+        </foreach>
+    </select>
 </mapper>

+ 6 - 0
yt-app/app-service/src/main/resources/mapper/LoginRecordMapper.xml

@@ -26,4 +26,10 @@
          #{ipAddr}
          );
     </insert>
+    <select id="getLoginRecords" resultType="com.ytpm.app.model.YtDyzLoginRecord">
+        select
+            record_id, user_id, login_time, device_brand, device_model, login_ip, operator, ip_addr
+        from yt_dyz_login_record
+        where user_id = #{wxOpenId}
+    </select>
 </mapper>

+ 11 - 0
yt-common/src/main/java/com/ytpm/agent/enums/UserStatusEnum.java

@@ -21,4 +21,15 @@ public enum UserStatusEnum {
         this.desc = desc;
     }
 
+    /**
+     * 根据编码获取状态
+     */
+    public static String getByCode(Integer code){
+        for (UserStatusEnum value : UserStatusEnum.values()) {
+            if(!value.getCode().equals(code))continue;
+            return value.getDesc();
+        }
+        return "";
+    }
+
 }

+ 2 - 0
yt-common/src/main/java/com/ytpm/agent/model/YtPlatformBanned.java

@@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModel;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.springframework.beans.factory.annotation.Value;
 
 import java.util.Date;
 
@@ -14,6 +15,7 @@ import java.util.Date;
 public class YtPlatformBanned {
     private String bannedId;
     private String userId;
+    private String appId;
     private String channelId;
     private Date bannedTime;
     private String bannedReason;

+ 2 - 0
yt-common/src/main/java/com/ytpm/agent/model/YtPlatformDeblocking.java

@@ -19,6 +19,8 @@ public class YtPlatformDeblocking {
     private String bannedId;
     @ApiModelProperty("用户ID")
     private String userId;
+    @ApiModelProperty("应用ID")
+    private String appId;
     @ApiModelProperty("渠道ID")
     private String channelId;
     @ApiModelProperty("解禁时间")

+ 1 - 1
yt-app/app-service/src/main/java/com/ytpm/model/ActiveUser.java → yt-common/src/main/java/com/ytpm/app/model/ActiveUser.java

@@ -1,4 +1,4 @@
-package com.ytpm.model;
+package com.ytpm.app.model;
 
 import lombok.AllArgsConstructor;
 import lombok.Data;

+ 1 - 2
yt-app/app-service/src/main/java/com/ytpm/model/YtDyzLoginRecord.java → yt-common/src/main/java/com/ytpm/app/model/YtDyzLoginRecord.java

@@ -1,6 +1,5 @@
-package com.ytpm.model;
+package com.ytpm.app.model;
 
-import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;

+ 1 - 1
yt-app/app-service/src/main/java/com/ytpm/model/YtDyzPowerRecord.java → yt-common/src/main/java/com/ytpm/app/model/YtDyzPowerRecord.java

@@ -1,4 +1,4 @@
-package com.ytpm.model;
+package com.ytpm.app.model;
 
 import lombok.Data;
 

+ 13 - 2
yt-app/app-service/src/main/java/com/ytpm/model/YtDyzUser.java → yt-common/src/main/java/com/ytpm/app/model/YtDyzUser.java

@@ -1,6 +1,6 @@
-package com.ytpm.model;
+package com.ytpm.app.model;
 
-import com.ytpm.app.model.YtDyzAnswerRecord;
+import com.ytpm.custom.CustomField;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
@@ -31,6 +31,7 @@ public class YtDyzUser {
     @ApiModelProperty("用户头像")
     private String headImg;
     /** 注册时间 */
+    @CustomField
     @ApiModelProperty("注册时间")
     private Date registryTime;
     /** 最新登录时间 */
@@ -40,33 +41,39 @@ public class YtDyzUser {
     @ApiModelProperty("最新登录IP")
     private String lastLoginIp;
     /** 登录天数 */
+    @CustomField
     @ApiModelProperty("登录天数")
     private Integer loginDays;
     /** 总观看视频数 */
+    @CustomField
     @ApiModelProperty("总观看视频数")
     private String totalVideo;
     /** 总收益 */
     @ApiModelProperty("总收益")
     private BigDecimal totalIncome;
     /** 红包余额 */
+    @CustomField
     @ApiModelProperty("红包余额")
     private BigDecimal redPacketBalance;
     /** 红包总金额 */
     @ApiModelProperty("红包总金额")
     private BigDecimal redPacketAmount;
     /** 积分余额 */
+    @CustomField
     @ApiModelProperty("积分余额")
     private BigDecimal pointsBalance;
     /** 积分总额 */
     @ApiModelProperty("积分总额")
     private BigDecimal pointsTotal;
     /** 提现总额 */
+    @CustomField
     @ApiModelProperty("提现总额")
     private BigDecimal withdrawTotal;
     /** 用户签到天数 */
     @ApiModelProperty("用户签到天数")
     private Integer signDays;
     /** 用户状态 */
+    @CustomField(value = "user_status",desc = "用户状态")
     @ApiModelProperty("用户状态")
     private Integer userStatus;
     /** 风控原因 */
@@ -85,6 +92,7 @@ public class YtDyzUser {
     @ApiModelProperty("体力")
     private Integer power;
     /** 今日答题数 */
+    @CustomField
     @ApiModelProperty("今日答题数")
     private Integer todayAnswerCount;
     /** 历史答题数 */
@@ -93,4 +101,7 @@ public class YtDyzUser {
     /** 答题历史记录 */
     @ApiModelProperty("答题历史记录")
     private List<YtDyzAnswerRecord> answerRecordList;
+    /** 登录历史记录 */
+    @ApiModelProperty("登录历史记录")
+    private List<YtDyzLoginRecord> loginRecordList;
 }

+ 2 - 0
yt-common/src/main/java/com/ytpm/app/view/WxDefaultConfig.java

@@ -12,4 +12,6 @@ import lombok.NoArgsConstructor;
 public class WxDefaultConfig {
     private String appId;
     private String secret;
+    private String platformAppId;
+    private String platformAppSecret;
 }

+ 12 - 0
yt-common/src/main/java/com/ytpm/risk/view/RiskAccessView.java

@@ -0,0 +1,12 @@
+package com.ytpm.risk.view;
+
+import lombok.Data;
+
+@Data
+public class RiskAccessView {
+    private String appId;
+    private String appName;
+    private String userId;
+    private String accessId;
+    private String accessSecret;
+}

+ 3 - 0
yt-risk/risk-feign/src/main/java/com/ytpm/feign/RiskFeign.java

@@ -61,4 +61,7 @@ public interface RiskFeign {
 
     @GetMapping("/riskManage/checkRisk")
     Result<?> checkRisk(@RequestParam("openid")String openid);
+
+    @GetMapping("/public/getRiskCondition")
+    Result<RiskTemplateView> getRiskCondition(@RequestParam("app_id")String appId, @RequestParam("access_secret")String secret);
 }

+ 5 - 0
yt-risk/risk-manage/pom.xml

@@ -41,6 +41,11 @@
             <artifactId>agent-feign</artifactId>
             <version>1.0-SNAPSHOT</version>
         </dependency>
+        <dependency>
+            <groupId>com.ytpm</groupId>
+            <artifactId>app-feign</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 1 - 1
yt-risk/risk-manage/src/main/java/com/ytpm/config/ResourceServerConfig.java

@@ -64,7 +64,7 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
     public void configure(HttpSecurity http) throws Exception {
         http.headers().frameOptions().disable()
                 .and()
-                .authorizeRequests().antMatchers("/riskManage/checkRisk","/api/public/**","/doc.html","/api/v2/**","/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security",
+                .authorizeRequests().antMatchers("/public/**","/riskManage/checkRisk","/api/public/**","/doc.html","/api/v2/**","/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security",
                         "/swagger-ui.html", "/webjars/**","/swagger-resources/configuration/ui","/swagger-ui.html").permitAll()
                 .anyRequest().authenticated();
     }

+ 16 - 0
yt-risk/risk-manage/src/main/java/com/ytpm/config/WebMvcConfig.java

@@ -0,0 +1,16 @@
+package com.ytpm.config;
+
+import com.ytpm.interceptor.OpenApiInterceptor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(new OpenApiInterceptor())
+                .addPathPatterns("/public/**")
+                .excludePathPatterns("/**");
+    }
+}

+ 30 - 0
yt-risk/risk-manage/src/main/java/com/ytpm/controller/PublicApiController.java

@@ -0,0 +1,30 @@
+package com.ytpm.controller;
+
+import com.ytpm.general.Result;
+import com.ytpm.risk.view.RiskTemplateView;
+import com.ytpm.service.RiskService;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/public")
+public class PublicApiController {
+
+    @Autowired
+    private RiskService riskService;
+
+    /**
+     * 根据appId查询应用配置模版
+     */
+    @ApiOperation("返回指定应用关联的风控配置")
+    @GetMapping("/getRiskCondition")
+    public Result<RiskTemplateView> getRiskCondition(@RequestParam("app_id")String appId){
+        return riskService.getAppConfig(appId);
+    }
+
+}

+ 2 - 2
yt-risk/risk-manage/src/main/java/com/ytpm/controller/RiskManageController.java

@@ -40,8 +40,8 @@ public class RiskManageController {
     @ApiOperation("禁止用户登录")
     @ApiImplicitParam(name = "userId", value = "用户ID", required = true, paramType = "path")
     @GetMapping("/forbidLogin")
-    public Result<?> forbidLogin(@RequestParam("userId")String userId){
-        return riskService.lockUser(userId);
+    public Result<?> forbidLogin(@RequestParam("userId")String userId, @ApiIgnore  @AuthenticationPrincipal AgentUserInfo userInfo){
+        return riskService.lockUser(userId,userInfo);
     }
 
     /**

+ 5 - 0
yt-risk/risk-manage/src/main/java/com/ytpm/dao/RiskConfigMapper.java

@@ -43,6 +43,11 @@ public interface RiskConfigMapper {
      */
     RiskTemplateView getTemplateView(@Param("templateId") String templateId, @Param("channelId") String channelId);
 
+    /**
+     * 根据APP获取配置模版详情
+     */
+    RiskTemplateView getAppConfig(@Param("appId") String appId);
+
     /**
      * 修改配置值
      */

+ 6 - 0
yt-risk/risk-manage/src/main/java/com/ytpm/dao/RiskUserMapper.java

@@ -3,6 +3,7 @@ package com.ytpm.dao;
 import com.ytpm.agent.model.YtAppUser;
 import com.ytpm.agent.model.YtPlatformBanned;
 import com.ytpm.risk.param.RiskBannedParam;
+import com.ytpm.risk.view.RiskAccessView;
 import org.apache.ibatis.annotations.Param;
 import org.mapstruct.Mapper;
 
@@ -46,4 +47,9 @@ public interface RiskUserMapper {
      * 新增封禁记录
      */
     void addBannedRecord(YtPlatformBanned banned);
+
+    /**
+     * 查询访问控制详情
+     */
+    RiskAccessView selectByAppId(@Param("appId") String appId);
 }

+ 38 - 0
yt-risk/risk-manage/src/main/java/com/ytpm/interceptor/OpenApiInterceptor.java

@@ -0,0 +1,38 @@
+package com.ytpm.interceptor;
+
+
+import com.ytpm.dao.RiskUserMapper;
+import com.ytpm.risk.view.RiskAccessView;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Objects;
+
+@Component
+public class OpenApiInterceptor implements HandlerInterceptor {
+
+    @Resource
+    private RiskUserMapper riskUserMapper;
+
+    /**
+     * 拦截客户端请求判断token为非授权访问则打回
+     */
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        System.out.println("拦截客户端请求:"+request.getRequestURI());
+        String token = request.getParameter("access_secret");
+        String appId = request.getParameter("app_id");
+        RiskAccessView accessView = riskUserMapper.selectByAppId(appId);
+        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
+        if(Objects.isNull(accessView) || !encoder.matches(token, accessView.getAccessSecret())){
+            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+            response.getWriter().write("Unauthorized");
+            return false;
+        }
+        return true;
+    }
+}

+ 7 - 1
yt-risk/risk-manage/src/main/java/com/ytpm/service/RiskService.java

@@ -1,5 +1,6 @@
 package com.ytpm.service;
 
+import com.ytpm.agent.view.AgentUserInfo;
 import com.ytpm.general.Result;
 import com.ytpm.general.ResultTable;
 import com.ytpm.risk.param.RiskBannedListParam;
@@ -27,7 +28,7 @@ public interface RiskService {
     /**
      * 锁定用户禁止登入
      */
-    Result<?> lockUser(String userId);
+    Result<?> lockUser(String userId, AgentUserInfo userInfo);
 
     /**
      * 封禁用户
@@ -72,4 +73,9 @@ public interface RiskService {
      * 校验用户是否处于风控中
      */
     Result<?> checkRisk(String openid);
+
+    /**
+     * 根据appId查询应用配置模版
+     */
+    Result<RiskTemplateView> getAppConfig(String appId);
 }

+ 99 - 29
yt-risk/risk-manage/src/main/java/com/ytpm/service/impl/RiskServiceImpl.java

@@ -11,7 +11,10 @@ import com.ytpm.agent.model.YtAppUser;
 import com.ytpm.agent.model.YtPlatformBanned;
 import com.ytpm.agent.model.YtPlatformDeblocking;
 import com.ytpm.agent.view.AgentEnableAppView;
+import com.ytpm.agent.view.AgentUserInfo;
 import com.ytpm.app.model.YtAppUserLoginRecord;
+import com.ytpm.app.model.YtDyzLoginRecord;
+import com.ytpm.app.model.YtDyzUser;
 import com.ytpm.app.view.YtAppUserListView;
 import com.ytpm.custom.CustomField;
 import com.ytpm.dao.AppLoginRecordMapper;
@@ -19,10 +22,12 @@ import com.ytpm.dao.DictMapper;
 import com.ytpm.dao.RiskConfigMapper;
 import com.ytpm.dao.RiskManageMapper;
 import com.ytpm.dao.RiskUserMapper;
+import com.ytpm.feign.AppFeign;
 import com.ytpm.general.RepMessage;
 import com.ytpm.general.Result;
 import com.ytpm.general.ResultTable;
 import com.ytpm.handle.CustomerException;
+import com.ytpm.risk.enums.BannedTypeEnum;
 import com.ytpm.risk.model.YtRiskConfig;
 import com.ytpm.risk.model.YtRiskTemplate;
 import com.ytpm.risk.param.RiskBannedListParam;
@@ -73,13 +78,25 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
     private RiskManageMapper riskManageMapper;
     @Resource
     private AppLoginRecordMapper loginRecordMapper;
+    @Resource
+    private AppFeign appFeign;
     /**
      * 查询配置字段选项
      */
     @Override
     public ResultTable<RiskConfigView> getRiskConfig() {
-        Field[] fields = ReflectUtil.getClassField(YtAppUserListView.class);
+        Field[] userFields = ReflectUtil.getClassField(YtDyzUser.class);
+        Field[] loginFields = ReflectUtil.getClassField(YtDyzLoginRecord.class);
         List<RiskConfigView> configList = new ArrayList<RiskConfigView>();
+        addConfigItem(userFields,configList);
+        addConfigItem(loginFields,configList);
+        return ResultTable.resultTableOk(new PageInfo<RiskConfigView>(configList));
+    }
+
+    /**
+     * 添加配置项
+     */
+    private void addConfigItem(Field[] fields, List<RiskConfigView> configList) {
         RiskConfigView view;
         for (Field field : fields) {
             field.setAccessible(true);
@@ -92,7 +109,6 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
             view.setFieldDesc(field.getAnnotation(ApiModelProperty.class).value());
             configList.add(view);
         }
-        return ResultTable.resultTableOk(new PageInfo<RiskConfigView>(configList));
     }
 
     /**
@@ -148,18 +164,26 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
      * 锁定用户禁止用户登录
      */
     @Override
-    public Result<?> lockUser(String userId) {
-        YtAppUser appUser =  riskUserMapper.selectByUserId(userId);
+    public Result<?> lockUser(String userId, AgentUserInfo userInfo) {
+        YtDyzUser appUser =  appFeign.getUserInfo(userId).getData();
         if(Objects.isNull(appUser)){
             return Result.resultOk(RepMessage.LOCK_USER_SUCCESS);
         }
         if(UserStatusEnum.LOCK.getCode().equals(appUser.getUserStatus())){
             return Result.resultErr(RepMessage.ALREADY_RISK_USER);
         }
-        YtAppUser user = new YtAppUser();
+        YtDyzUser user = new YtDyzUser();
         user.setUserId(userId);
         user.setUserStatus(UserStatusEnum.LOCK.getCode());
-        riskUserMapper.updateByUserId(user);
+        user.setRiskReason(BannedTypeEnum.CHANNEL.getDesc()+"禁止登录");
+        appFeign.updateUserInfo(user);
+        RiskBannedParam param = new RiskBannedParam();
+        param.setUserId(userId);
+        param.setBannedReason(BannedTypeEnum.CHANNEL.getDesc()+"禁止登录");
+        param.setOperatorName(userInfo.getNickName());
+        param.setOperator(userInfo.getUserId());
+        param.setBannedType(BannedTypeEnum.CHANNEL.getCode());
+        addBannedRecord(Collections.singletonList(user.getUserId()),param);
         return Result.resultOk(RepMessage.LOCK_USER_SUCCESS);
     }
 
@@ -169,11 +193,15 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
     @Transactional(rollbackFor = Exception.class)
     @Override
     public Result<?> banned(RiskBannedParam param) {
-        YtAppUser appUser = riskUserMapper.selectByUserId(param.getUserId());
+        YtDyzUser appUser = appFeign.getUserInfo(param.getUserId()).getData();
         if(Objects.isNull(appUser)||UserStatusEnum.RISK.getCode().equals(appUser.getUserStatus())){
             return Result.resultOk(RepMessage.ALREADY_RISK_USER);
         }
-        riskUserMapper.banned(Collections.singletonList(param.getUserId()));
+        YtDyzUser user = new YtDyzUser();
+        user.setUserId(param.getUserId());
+        user.setUserStatus(UserStatusEnum.RISK.getCode());
+        user.setRiskReason(BannedTypeEnum.CHANNEL.getDesc()+"封禁账号");
+        appFeign.updateUserInfo(user);
         addBannedRecord(Collections.singletonList(param.getUserId()),param);
         return Result.resultOk(RepMessage.ALREADY_RISK_USER);
     }
@@ -204,30 +232,62 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
      * 查询登录记录并设置信息
      */
     private void setBannedLoginInfo(List<RiskBannedListView> bannedList) {
-        List<String> userIdList = bannedList.stream().
-                map(RiskBannedListView::getUserId).collect(Collectors.toList());
-        List<YtAppUserLoginRecord> records = loginRecordMapper.getByUserIds(userIdList);
-        Map<String, List<YtAppUserLoginRecord>> recordMap = records.stream().collect(
-                Collectors.groupingBy(YtAppUserLoginRecord::getUserId));
+        String userIds = bannedList.stream().map(
+                RiskBannedListView::getUserId).distinct().collect(Collectors.joining(","));
+        List<YtDyzUser> data = appFeign.getUserList(userIds).getData();
+        Map<String, YtDyzUser> collect = data.stream().collect(Collectors.toMap(YtDyzUser::getUserId, o->o));
         for (RiskBannedListView view : bannedList) {
-            if(!recordMap.containsKey(view.getUserId()))continue;
-            List<YtAppUserLoginRecord> collect = recordMap.get(view.getUserId()).stream().sorted(Comparator
-                    .comparing(YtAppUserLoginRecord::getLoginTime).reversed()).limit(1).collect(Collectors.toList());
-            YtAppUserLoginRecord record = collect.get(0);
-            view.setPhoneBrand(record.getPhoneBrand());
-            view.setPhoneModel(record.getPhoneModel());
-            view.setCommunicationOperator(record.getCommunicationOperator());
-            view.setIpAddr(record.getIpAddr());
+            if(!collect.containsKey(view.getUserId()))continue;
+            YtDyzUser dyzUser = collect.get(view.getUserId());
+            List<YtDyzLoginRecord> recordList = dyzUser.getLoginRecordList();
+            if(CollUtil.isNotEmpty(recordList)){
+                view.setPhoneModel(recordList.get(0).getDeviceModel());
+                view.setPhoneBrand(recordList.get(0).getDeviceBrand());
+                view.setIpAddr(recordList.get(0).getIpAddr());
+                view.setCommunicationOperator(recordList.get(0).getOperator());
+            }
+            view.setPlatformId(dyzUser.getPlatformId());
+            view.setChannelId(dyzUser.getUserId());
+            view.setUserId(dyzUser.getUserId());
+            view.setNickName(dyzUser.getNickName());
+            view.setRegistryTime(dyzUser.getRegistryTime());
+            view.setLastLoginIp(dyzUser.getLastLoginIp());
+            view.setLastLoginTime(dyzUser.getLastLoginTime());
+            view.setUserStatus(dyzUser.getUserStatus());
         }
     }
 
+    /**
+     * 设置解封用户信息
+     */
+    private void setDeblockLoginInfo(List<RiskDeblockingListView> deblockingList) {
+        String userIds = deblockingList.stream().map(
+                RiskDeblockingListView::getUserId).distinct().collect(Collectors.joining(","));
+        List<YtDyzUser> data = appFeign.getUserList(userIds).getData();
+        Map<String, YtDyzUser> collect = data.stream().collect(Collectors.toMap(YtDyzUser::getUserId, o->o));
+        for (RiskDeblockingListView view : deblockingList) {
+            if(!collect.containsKey(view.getUserId()))continue;
+            YtDyzUser dyzUser = collect.get(view.getUserId());
+            view.setPlatformId(dyzUser.getPlatformId());
+            view.setChannelId(dyzUser.getUserId());
+            view.setUserId(dyzUser.getUserId());
+            view.setNickName(dyzUser.getNickName());
+            view.setRegistryTime(dyzUser.getRegistryTime());
+            view.setLastLoginTime(dyzUser.getLastLoginTime());
+            view.setUserStatus(dyzUser.getUserStatus());
+        }
+    }
     /**
      * 查询解封记录
      */
     @Override
     public ResultTable<RiskDeblockingListView> deblockingList(RiskDeblockingListParam param) {
         PageHelper.startPage(param.getPage(),param.getLimit());
-        return ResultTable.resultTableOk(new PageInfo<RiskDeblockingListView>(riskManageMapper.getDeblockingList(param)));
+        List<RiskDeblockingListView> deblockingList = riskManageMapper.getDeblockingList(param);
+        if(CollUtil.isNotEmpty(deblockingList)){
+            setDeblockLoginInfo(deblockingList);
+        }
+        return ResultTable.resultTableOk(new PageInfo<RiskDeblockingListView>(deblockingList));
     }
 
     /**
@@ -236,7 +296,7 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Result<?> changeUserStatus(RiskUserStatusParam param) {
-        YtAppUser user = riskUserMapper.selectByUserId(param.getUserId());
+        YtDyzUser user = appFeign.getUserInfo(param.getUserId()).getData();
         if(param.getUserStatus().equals(user.getUserStatus())){
             return Result.resultOk(RepMessage.USER_STATUS_MODIFY);
         }
@@ -336,22 +396,30 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
         return Result.resultOk(RepMessage.QUERY_SUCCESS);
     }
 
+    /**
+     * 根据appId查询应用配置模版
+     */
+    @Override
+    public Result<RiskTemplateView> getAppConfig(String appId) {
+        return Result.resultObjOk(configMapper.getAppConfig(appId));
+    }
+
     /**
      * 修改用户信息
      */
-    private void modifyAppUserInfo(YtAppUser user, RiskUserStatusParam param) {
-        YtAppUser appUser = new YtAppUser();
+    private void modifyAppUserInfo(YtDyzUser user, RiskUserStatusParam param) {
+        YtDyzUser appUser = new YtDyzUser();
         appUser.setUserId(param.getUserId());
         appUser.setUserStatus(param.getUserStatus());
         switch (param.getUserStatus()){
             case 2:
-                appUser.setLockReason(param.getReason());
-                break;
+                appUser.setRiskReason(param.getReason());
             case 3: //增加封禁记录
                 RiskBannedParam bannedParam = new RiskBannedParam();
                 BeanUtil.copyProperties(param, bannedParam);
                 bannedParam.setUserId(param.getUserId());
                 bannedParam.setBannedReason(param.getReason());
+                appUser.setRiskReason(param.getReason());
                 addBannedRecord(Collections.singletonList(user.getUserId()),bannedParam);
                 break;
             default: //解禁
@@ -361,7 +429,7 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
                             ,param.getReason(),param.getOperatorName());
                 }
         }
-        riskUserMapper.updateByUserId(appUser);
+        appFeign.updateUserInfo(appUser);
     }
 
     /**
@@ -371,6 +439,7 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
         YtPlatformDeblocking deblocking = new YtPlatformDeblocking();
         deblocking.setDeblockingId(IdUtil.fastSimpleUUID());
         deblocking.setUserId(userId);
+        deblocking.setAppId("a684009039113d");
         deblocking.setOperator(operator);
         deblocking.setOperatorName(operatorName);
         deblocking.setBannedId(bannedId);
@@ -389,10 +458,11 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
             banned = new YtPlatformBanned();
             banned.setBannedId(IdUtil.fastSimpleUUID());
             banned.setUserId(userId);
+            banned.setAppId("a684009039113d");
             banned.setChannelId(param.getOperator());
             banned.setBannedLimit(Objects.isNull(param.getBannedLimit())?defaultLimit:param.getBannedLimit());
             banned.setBannedReason(StrUtil.isBlank(param.getBannedReason())?defaultReason:param.getBannedReason());
-            banned.setBannedType(param.getBannedType());
+            banned.setBannedType(BannedTypeEnum.CHANNEL.getCode());
             banned.setBannedTime(new Date());
             banned.setOperator(param.getOperator());
             banned.setOperatorName(param.getOperatorName());

+ 20 - 0
yt-risk/risk-manage/src/main/resources/mapper/RiskConfigMapper.xml

@@ -169,4 +169,24 @@
             rt.template_id = #{templateId}
           AND rt.channel_id = #{channelId}
     </select>
+    <select id="getAppConfig" resultMap="RiskTemplateViewMap">
+        SELECT
+            rt.template_id,
+            rt.template_code,
+            rt.template_name,
+            rt.template_content,
+            rt.enabled,
+            rc.config_id,
+            rc.field_name,
+            rc.field_desc,
+            rc.config_type,
+            rc.config_val,
+            rc.multy
+        FROM
+            yt_risk_template rt
+               LEFT JOIN yt_risk_template_config rtc ON rt.template_id = rtc.template_id
+               LEFT JOIN yt_risk_config rc ON rtc.config_id = rc.config_id
+        WHERE
+            rt.app_id = #{appId}
+    </select>
 </mapper>

+ 22 - 45
yt-risk/risk-manage/src/main/resources/mapper/RiskManageMapper.xml

@@ -7,6 +7,7 @@
          deblocking_id,
          banned_id,
          user_id,
+         app_id,
          channel_id,
          deblocking_time,
          deblocking_reason,
@@ -18,6 +19,7 @@
          #{deblockingId},
          #{bannedId},
          #{userId},
+         #{appId},
          #{channelId},
          #{deblockingTime},
          #{deblockingReason},
@@ -53,93 +55,68 @@
     <select id="getDeblockingList" resultType="com.ytpm.risk.view.RiskDeblockingListView">
         SELECT
             pd.deblocking_id,
-            au.platform_id,
-            au.channel_id,
-            au.user_id,
-            au.nick_name,
-            au.registry_time,
-            au.last_login_time,
-            au.user_status,
+            pd.banned_id,
+            pd.user_id,
+            pd.channel_id,
             pd.deblocking_time,
             pd.deblocking_reason,
-            au.channel_type,
-            au.channel_origin,
             pd.operator,
             pd.operator_name,
-            au.app_id,
+            a.app_id,
             a.app_name
         FROM
             yt_platform_deblocking pd
-                JOIN yt_app_user au ON pd.user_id = au.user_id
-                JOIN yt_app a ON au.app_id = a.app_id
+            JOIN yt_app a ON pd.app_id = a.app_id
         WHERE
             pd.channel_id = #{channelId}
         <if test="appId != null and appId != ''">
-            and au.app_id = #{appId}
+            and a.app_id = #{appId}
         </if>
         <if test="deblockingReason != null and deblockingReason != ''">
             and pd.deblocking_reason like concat('%',#{deblockingReason},'%')
         </if>
-        <if test="channelType != null">
-            and au.channel_type = #{channelType}
-        </if>
-        <if test="channelOrigin != null">
-            and au.channel_origin = #{channelOrigin}
-        </if>
         <if test="deblockingTimeBegin != null">
             and DATE_FORMAT(pd.deblocking_time,'%Y-%m-%d') <![CDATA[>=]]> DATE_FORMAT(#{deblockingTimeBegin}, '%Y-%m-%d')
         </if>
         <if test="deblockingTimeEnd != null">
             and DATE_FORMAT(pd.deblocking_time,'%Y-%m-%d') <![CDATA[<=]]> DATE_FORMAT(#{deblockingTimeEnd}, '%Y-%m-%d')
         </if>
-        <if test="loginTimeBegin != null">
-            and DATE_FORMAT(au.last_login_time,'%Y-%m-%d') <![CDATA[>=]]> DATE_FORMAT(#{loginTimeBegin}, '%Y-%m-%d')
-        </if>
-        <if test="loginTimeEnd != null">
-            and DATE_FORMAT(au.last_login_time,'%Y-%m-%d') <![CDATA[<=]]> DATE_FORMAT(#{loginTimeEnd}, '%Y-%m-%d')
-        </if>
         ORDER BY pd.deblocking_time DESC
     </select>
 
     <select id="getBannedList" resultType="com.ytpm.risk.view.RiskBannedListView">
         SELECT
         pb.banned_id,
-        au.platform_id,
-        au.channel_id,
-        au.user_id,
-        au.nick_name,
-        au.registry_time,
-        au.last_login_ip,
-        au.last_login_time,
-        au.user_status,
+#         au.platform_id,
+#         au.channel_id,
+#         au.user_id,
+#         au.nick_name,
+#         au.registry_time,
+#         au.last_login_ip,
+#         au.last_login_time,
+#         au.user_status,
         pb.banned_time,
         pb.banned_reason,
-        au.channel_type,
-        au.channel_origin,
+#         au.channel_type,
+#         au.channel_origin,
         pb.banned_type,
         pb.banned_limit,
         pb.operator,
         pb.operator_name,
-        au.app_id,
+        pb.user_id,
+        a.app_id,
         a.app_name
         FROM
         yt_platform_banned pb
-        JOIN yt_app_user au ON pb.user_id = au.user_id
-        JOIN yt_app a ON au.app_id = a.app_id
+        JOIN yt_app a ON pb.app_id = a.app_id
         WHERE
         pb.channel_id = #{channelId}
         <if test="appId != null and appId != ''">
-            and au.app_id = #{appId}
+            and a.app_id = #{appId}
         </if>
         <if test="bannedReason != null and bannedReason != ''">
             and pb.banned_reason like concat('%',#{bannedReason},'%')
         </if>
-        <if test="channelType != null">
-            and au.channel_type = #{channelType}
-        </if>
-        <if test="channelOrigin != null">
-            and au.channel_origin = #{channelOrigin}
-        </if>
         <if test="bannedTimeBegin != null">
             and DATE_FORMAT(pb.banned_time,'%Y-%m-%d') <![CDATA[>=]]> DATE_FORMAT(#{bannedTimeBegin}, '%Y-%m-%d')
         </if>

+ 13 - 0
yt-risk/risk-manage/src/main/resources/mapper/RiskUserMapper.xml

@@ -6,6 +6,7 @@
         (
          banned_id,
          user_id,
+         app_id,
          channel_id,
          banned_time,
          banned_reason,
@@ -18,6 +19,7 @@
         (
             #{bannedId},
             #{userId},
+            #{appId},
             #{channelId},
             #{bannedTime},
             #{bannedReason},
@@ -130,4 +132,15 @@
     <select id="selectByWx" resultType="com.ytpm.agent.model.YtAppUser">
         select user_id, app_id, nick_name, registry_time, last_login_time, last_login_ip, login_days, channel_type, channel_origin, user_type, total_video, total_income, red_packet_balance, red_packet_amount, points_balance, points_total, withdraw_total, sign_days, user_status, lock_reason, wx_open_id, platform_id, channel_id from yt_app_user where wx_open_id = #{openid}
     </select>
+    <select id="selectByAppId" resultType="com.ytpm.risk.view.RiskAccessView">
+        select
+            a.app_id,
+            a.app_name,
+            pua.access_id,
+            pua.access_secret,
+            pua.user_id
+        from yt_app a
+        join yt_platform_user_access pua on a.user_id = pua.user_id and pua.enabled = 1
+        where a.app_id = #{appId}
+    </select>
 </mapper>