Bläddra i källkod

踢出群聊功能,主要链路流程

刘立冬 1 månad sedan
förälder
incheckning
e61448630f

+ 17 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/model/qywx/OpenUserInfo.java

@@ -0,0 +1,17 @@
+package com.tzld.piaoquan.risk.control.model.qywx;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class OpenUserInfo {
+    @JSONField(name = "user_id")
+    private Long userId;
+
+    @JSONField(name = "openid")
+    private String openid;
+}

+ 4 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/model/qywx/QwCommonResModel.java

@@ -14,6 +14,10 @@ public class QwCommonResModel<T> {
                 new TypeReference<QwCommonResModel<T>>(dataType) {}
         );
     }
+    // 在QwCommonResModel中修改parseResponse方法
+    public static <T> QwCommonResModel<T> parseResponse(String json, TypeReference<QwCommonResModel<T>> typeRef) {
+        return JSON.parseObject(json, typeRef.getType());
+    }
     public QwCommonResModel() {
     }
 

+ 23 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/model/qywx/RiskUserInfo.java

@@ -0,0 +1,23 @@
+package com.tzld.piaoquan.risk.control.model.qywx;
+
+import lombok.Data;
+import java.util.List;
+
+@Data
+public class RiskUserInfo {
+    private String chatId;
+    private String groupName;
+    private String corpId;
+    private List<Admin> adminList;
+    private String externalId;
+    private String externalNickname;
+    private long joinTime;
+    private int joinScene;
+    private int riskLevel;
+
+    @Data
+    public static class Admin {
+        private String userId;
+        private String nickname;
+    }
+}

+ 50 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/model/qywx/RoomListResponse.java

@@ -0,0 +1,50 @@
+package com.tzld.piaoquan.risk.control.model.qywx;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class RoomListResponse {
+    private Integer total;
+
+    @JSONField(name = "next_start")
+    private Integer nextStart;
+
+    @JSONField(name = "roomList")
+    private List<RoomInfo> roomList;
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @Builder
+    public static class RoomInfo {
+        @JSONField(name = "room_id")
+        private String roomId;
+
+        @JSONField(name = "create_user_id")
+        private Long createUserId;
+
+        private String infoticket;
+
+        @JSONField(name = "update_time")
+        private Long updateTime;
+
+        private Integer total;
+        private Integer flag;
+
+        @JSONField(name = "create_time")
+        private Long createTime;
+
+        private String nickname;
+
+        @JSONField(name = "roomurl")
+        private String roomUrl;
+    }
+}

+ 119 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/model/qywx/RoomMemberListInfo.java

@@ -0,0 +1,119 @@
+package com.tzld.piaoquan.risk.control.model.qywx;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class RoomMemberListInfo {
+    @JSONField(name = "room_id")
+    private String roomId;
+
+    @JSONField(name = "create_user_id")
+    private Long createUserId;
+
+    @JSONField(name = "flag")
+    private Long flag;
+
+    @JSONField(name = "verdata")
+    private String verdata;
+
+    @JSONField(name = "create_time")
+    private Long createTime;
+
+    @JSONField(name = "notice_content")
+    private String noticeContent;
+
+    @JSONField(name = "total")
+    private Integer total;
+
+    @JSONField(name = "notice_sendervid")
+    private Long noticeSendervid;
+
+    @JSONField(name = "anti_spam_rules")
+    private List<?> antiSpamRules; // 根据实际规则类型替换
+
+    @JSONField(name = "nickname")
+    private String nickname;
+
+    @JSONField(name = "member_list")
+    private List<Member> memberList;
+
+    @JSONField(name = "new_flag")
+    private Integer newFlag;
+
+    @JSONField(name = "notice_time")
+    private Long noticeTime;
+
+    @JSONField(name = "managers")
+    private List<?> managers; // 根据实际管理员类型替换
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Member {
+        @JSONField(name = "unionid")
+        private String unionid;
+
+        @JSONField(name = "flag")
+        private Long flag;
+
+        @JSONField(name = "create_time")
+        private Long createTime;
+
+        @JSONField(name = "sex")
+        private Integer sex;
+
+        @JSONField(name = "mobile")
+        private String mobile;
+
+        @JSONField(name = "acctid")
+        private String acctid;
+
+        @JSONField(name = "member_flag")
+        private Integer memberFlag;
+
+        @JSONField(name = "join_scene")
+        private Integer joinScene;
+
+        @JSONField(name = "avatar")
+        private String avatar;
+
+        @JSONField(name = "english_name")
+        private String englishName;
+
+        @JSONField(name = "realname")
+        private String realname;
+
+        @JSONField(name = "room_notes")
+        private String roomNotes;
+
+        @JSONField(name = "jointime")
+        private Long jointime;
+
+        @JSONField(name = "nickname")
+        private String nickname;
+
+        @JSONField(name = "room_nickname")
+        private String roomNickname;
+
+        @JSONField(name = "new_flag")
+        private Long newFlag;
+
+        @JSONField(name = "position")
+        private String position;
+
+        @JSONField(name = "uin")
+        private Long uin;
+
+        @JSONField(name = "invite_user_id")
+        private Long inviteUserId;
+
+        @JSONField(name = "corp_id")
+        private Long corpId;
+    }
+}

+ 7 - 2
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/service/impl/QywxUserDataService.java

@@ -18,10 +18,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
 
-import javax.annotation.Resource;
 import java.util.Date;
 import java.util.List;
-import java.util.Optional;
 
 @Slf4j
 @Service
@@ -220,4 +218,11 @@ public class QywxUserDataService {
         List<UserBase> users = userBaseMapper.selectByExample(example);
         return users.isEmpty() ? null : users.get(0);
     }
+    //根据名称查询用户
+    public List<UserBase> getUserByNickName(String nickname) {
+        UserBaseExample example = new UserBaseExample();
+        example.createCriteria().andRealnameEqualTo(nickname);
+        List<UserBase> users = userBaseMapper.selectByExample(example);
+        return users.isEmpty() ? null : users;
+    }
 }

+ 12 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/service/impl/RiskRuleConfigService.java

@@ -0,0 +1,12 @@
+package com.tzld.piaoquan.risk.control.service.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+public class RiskRuleConfigService {
+
+
+
+}

+ 199 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/service/impl/RiskUserHandleService.java

@@ -0,0 +1,199 @@
+package com.tzld.piaoquan.risk.control.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.TypeReference;
+import com.tzld.piaoquan.risk.control.config.QywxConfig;
+import com.tzld.piaoquan.risk.control.model.po.UserBase;
+import com.tzld.piaoquan.risk.control.model.qywx.*;
+import com.tzld.piaoquan.risk.control.util.HttpClientUtil;
+import com.tzld.piaoquan.risk.control.util.HttpPoolClient;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Slf4j
+@Service
+public class RiskUserHandleService {
+    @Autowired
+    private QywxConfig qywxConfig; // 注入配置类
+    @Autowired
+    private QywxUserDataService qwUserService;
+    @Autowired
+    private RiskUserOperateService riskUserOperateService;
+    @Value("${qywx.corpid}")
+    private String corpid;
+    @Value("${qywx.scorpid}")
+    private String scorpid;
+    private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(10000, 10000, 2000, 5000, 5, 10000);
+    private static final Logger LOGGER = LoggerFactory.getLogger(RiskUserHandleService.class);
+
+
+    public void handleRiskUser(RiskUserInfo riskUserInfo){
+        log.info("handleRiskUser, riskUserInfo: {}", riskUserInfo);
+        //根据名称找到人
+        List<UserBase> staffList = findStaffByName(riskUserInfo);
+        if (staffList.isEmpty()) return;
+        //根据群名匹配到:人-群:哪个员工哪个群
+        Map<String, List<RoomListResponse.RoomInfo>> toBeOperate = matchUserAndRoom(staffList, riskUserInfo);
+        if (toBeOperate.isEmpty()) return;
+        log.info("handleRiskUser, toBeOperate: {}", toBeOperate);
+        //TODO:检查过滤规则是否配置
+        //找到待踢的人,找到终止
+        for (Map.Entry<String, List<RoomListResponse.RoomInfo>> entry : toBeOperate.entrySet()) {
+            String staffVid = entry.getKey(); // Key: staff vid内部员工
+            UserBase staff = findStaffByVid(staffList, staffVid);
+            List<RoomListResponse.RoomInfo> roomInfoList = entry.getValue(); // Value: List of RoomInfo
+            // Process each room in the list
+            long externalVid =  externalId2Vid(staff, riskUserInfo);
+            if (externalVid == -1) {
+                log.info("handleRiskUser, externalId2Vid error, staff: {}, riskUserInfo: {}", staff, riskUserInfo);
+                continue;
+            }
+            for (RoomListResponse.RoomInfo roomInfo : roomInfoList) {
+                boolean success = riskUserOperateService.checkAndKickExternalUser(staff, riskUserInfo, externalVid,Long.parseLong(roomInfo.getRoomId()));
+                if (success) {
+                    log.info("handleRiskUser to be kick user, vid: {},name: {}", externalVid,riskUserInfo.getExternalNickname());
+                    return;
+                    //kick(staff, Long.parseLong(roomInfo.getRoomId()), externalVid);
+                }
+            }
+        }
+    }
+
+    private UserBase findStaffByVid(List<UserBase> staffList, String vid) {
+        for (UserBase userBase : staffList) {
+            if (userBase.getVid().equals(vid)) {
+                return userBase;
+            }
+        }
+        return null;
+    }
+
+    private Map<String, List<RoomListResponse.RoomInfo>> matchUserAndRoom(List<UserBase> staffList, RiskUserInfo userInfo) {
+        Map<String, List<RoomListResponse.RoomInfo>> toBeOperate = new HashMap<>();
+        if (staffList != null && !staffList.isEmpty()) {
+            log.info("handleRiskUser hits, userInfo: {}", userInfo);
+            for (UserBase userBase : staffList) {
+                //获取匹配到每个人的群信息
+                List<RoomListResponse.RoomInfo> chatRoomList = getChatList(userBase);
+                if (chatRoomList != null && !chatRoomList.isEmpty()) {
+                    log.info("handleRiskUserList hits, userInfo: {}", userBase);
+                    for (RoomListResponse.RoomInfo roomInfo : chatRoomList) {
+                        List<RoomListResponse.RoomInfo> matched = findRoomByChatRoomName(chatRoomList, userInfo);
+                        if (matched != null && !matched.isEmpty()) {
+                            log.info("handleRiskUserList hits, userInfo: {}", userBase);
+                            toBeOperate.put(userBase.getVid(), matched);
+                        } else {
+                            log.info("handleRiskUserList, roomInfo: {}", roomInfo);
+                        }
+                    }
+                }
+            }
+        }
+        return toBeOperate;
+    }
+
+    //每个人有几个匹配到的群
+    public List<RoomListResponse.RoomInfo> findRoomByChatRoomName(List<RoomListResponse.RoomInfo> roomInfoList, RiskUserInfo riskInfo) {
+        List<RoomListResponse.RoomInfo> matchedRoomList = new ArrayList<>();
+        for (RoomListResponse.RoomInfo roomInfo : roomInfoList) {
+            if (riskInfo != null && riskInfo.getGroupName().equals(roomInfo.getNickname())) {
+                matchedRoomList.add(roomInfo);
+            }
+        }
+        return matchedRoomList;
+    }
+
+    public List<RoomListResponse.RoomInfo> getChatList(UserBase userBase) {
+        List<RoomListResponse.RoomInfo> chatRoomList = new ArrayList<>();
+        Map<String, Object> requestBody = new HashMap<>();
+        requestBody.put("uuid", userBase.getUuid());
+        requestBody.put("limit", 100);
+        requestBody.put("star_index", 0);
+        LOGGER.info("getChatList, userBase: {}", userBase);
+        String params = JSON.toJSONString(requestBody);
+        Optional<String> response = httpPoolClientDefault.postJson(qywxConfig.getDomain() + qywxConfig.getPath("get-chatList"), params);
+        QwCommonResModel<RoomListResponse> roomList = null;
+        if (response.isPresent()) {
+            roomList = QwCommonResModel.parseResponse(response.get(), RoomListResponse.class);
+        }
+        if (roomList != null && roomList.getErrcode() == 0) {
+            if (roomList.getData().getRoomList() != null && !roomList.getData().getRoomList().isEmpty()) {
+                chatRoomList = roomList.getData().getRoomList();
+                log.info("handleRiskUserList hits, userInfo: {}", userBase);
+            } else {
+                log.info("handleRiskUserList not hits, userInfo: {}", userBase);
+            }
+            log.info("handleRiskUserList, roomList size: {}", roomList.getData().getRoomList().size());
+        }
+        return chatRoomList;
+    }
+
+    public List<UserBase> findStaffByName(RiskUserInfo userInfo) {
+        List<UserBase> userBaseList = new ArrayList<>();
+        if (userInfo != null ) {
+            List<RiskUserInfo.Admin> adminList = userInfo.getAdminList();
+            if (adminList != null && !adminList.isEmpty()) {
+                for (RiskUserInfo.Admin admin : adminList) {
+                    String name = admin.getNickname();
+                    if (name != null && !name.isEmpty()) {
+                        userBaseList.addAll(qwUserService.getUserByNickName(name));
+                    }
+                }
+            }
+        }
+        if (!userBaseList.isEmpty()) {
+            log.info("handleRiskUserList hits, userInfo: {}", userInfo);
+        }
+        return userBaseList;
+    }
+
+    private List<RoomMemberListInfo.Member> getRoomMemberList(UserBase staff,long roomId) {
+        Map<String, Object> requestBody = new HashMap<>();
+        requestBody.put("uuid", staff.getUuid());
+        requestBody.put("roomId", roomId);
+        LOGGER.info("getRoomMemberList, staff: {}", staff);
+        String params = JSON.toJSONString(requestBody);
+        Optional<String> response = httpPoolClientDefault.postJson(qywxConfig.getDomain() + qywxConfig.getPath("get-roomMembers"), params);
+        List<RoomMemberListInfo.Member> memberList = new ArrayList<>();
+        if (response.isPresent()) {
+            QwCommonResModel<RoomMemberListInfo> memberInfo = QwCommonResModel.parseResponse(response.get(), RoomMemberListInfo.class);
+            if (memberInfo.getErrcode() == 0) {
+                memberList = memberInfo.getData().getMemberList();
+            }
+        }
+        return memberList;
+    }
+
+    private long externalId2Vid(UserBase staff,RiskUserInfo riskinfo) {
+        log.info("externalId2Vid, staff: {}, riskinfo: {}", staff, riskinfo);
+        Map<String, Object> requestBody = new HashMap<>();
+        requestBody.put("uuid", staff.getUuid());
+        requestBody.put("corpid", corpid);
+        requestBody.put("scorpid", scorpid);
+        requestBody.put("openid",Arrays.asList(riskinfo.getExternalId()));
+        String params = JSON.toJSONString(requestBody);
+        Optional<String> response = httpPoolClientDefault.postJson(qywxConfig.getDomain() + qywxConfig.getPath("userId2Vid"), params);
+        log.info("externalId2Vid, response: {}", response);
+        if (response.isPresent()) {
+            QwCommonResModel<List<OpenUserInfo>> result = JSON.parseObject(
+                    response.get(),
+                    new TypeReference<QwCommonResModel<List<OpenUserInfo>>>() {}.getType()
+            );
+            if (result.getErrcode() == 0 && result.getData() != null && !result.getData().isEmpty()) {
+                return result.getData().get(0).getUserId();
+            } else {
+                log.error("externalId2Vid error, response: {}", response.get());
+            }
+        } else {
+            log.error("externalId2Vid error, no response");
+        }
+        return -1;
+    }
+
+}

+ 74 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/service/impl/RiskUserOperateService.java

@@ -0,0 +1,74 @@
+package com.tzld.piaoquan.risk.control.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.tzld.piaoquan.risk.control.config.QywxConfig;
+import com.tzld.piaoquan.risk.control.model.po.UserBase;
+import com.tzld.piaoquan.risk.control.model.qywx.QwCommonResModel;
+import com.tzld.piaoquan.risk.control.model.qywx.RiskUserInfo;
+import com.tzld.piaoquan.risk.control.model.qywx.RoomListResponse;
+import com.tzld.piaoquan.risk.control.model.qywx.RoomMemberListInfo;
+import com.tzld.piaoquan.risk.control.util.HttpClientUtil;
+import com.tzld.piaoquan.risk.control.util.HttpPoolClient;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.lang.reflect.Array;
+import java.util.*;
+
+@Slf4j
+@Service
+public class RiskUserOperateService {
+    @Autowired
+    private QywxConfig qywxConfig; // 注入配置类
+    @Autowired
+    private QywxUserDataService qwUserService;
+    private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(10000, 10000, 2000, 5000, 5, 10000);
+    private static final Logger LOGGER = LoggerFactory.getLogger(RiskUserHandleService.class);
+
+    public boolean checkAndKickExternalUser(UserBase staff,RiskUserInfo riskUserInfo,long vid,long roomId) {
+        boolean inRoom = isInRoom(staff, roomId, vid);
+
+        return true;
+    }
+
+    private void kick(UserBase staff, long roomId, long vid) {
+        Map<String, Object> requestBody = new HashMap<>();
+        requestBody.put("uuid", staff.getUuid());
+        requestBody.put("oprType", 1);
+        requestBody.put("blacklist_vid",Arrays.asList(vid));
+        String params = JSON.toJSONString(requestBody);
+        Optional<String> response = httpPoolClientDefault.postJson(qywxConfig.getDomain() + qywxConfig.getPath("get-chatList"), params);
+    }
+
+    //增加校验,是否在群内
+    public boolean isInRoom(UserBase staff, long roomId,long vid) {
+        List<RoomMemberListInfo.Member> memberList = getRoomMemberList(staff, roomId);
+        for (RoomMemberListInfo.Member member : memberList) {
+            if (member.getUin() == vid) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private List<RoomMemberListInfo.Member> getRoomMemberList(UserBase staff, long roomId) {
+        Map<String, Object> requestBody = new HashMap<>();
+        requestBody.put("uuid", staff.getUuid());
+        requestBody.put("roomId", roomId);
+        LOGGER.info("getRoomMemberList, staff: {}", staff);
+        String params = JSON.toJSONString(requestBody);
+        Optional<String> response = httpPoolClientDefault.postJson(qywxConfig.getDomain() + qywxConfig.getPath("get-roomMembers"), params);
+        List<RoomMemberListInfo.Member> memberList = new ArrayList<>();
+        if (response.isPresent()) {
+            QwCommonResModel<RoomMemberListInfo> memberInfo = QwCommonResModel.parseResponse(response.get(), RoomMemberListInfo.class);
+            if (memberInfo.getErrcode() == 0) {
+                memberList = memberInfo.getData().getMemberList();
+            }
+        }
+        return memberList;
+    }
+}

+ 30 - 0
risk-control-server/src/main/java/com/tzld/piaoquan/risk/control/controller/ReceiveRiskInfoController.java

@@ -1,5 +1,35 @@
 package com.tzld.piaoquan.risk.control.controller;
 
+import com.tzld.piaoquan.risk.control.common.base.CommonResponse;
+import com.tzld.piaoquan.risk.control.config.QywxConfig;
+import com.tzld.piaoquan.risk.control.model.qywx.QwLoginCheckCode;
+import com.tzld.piaoquan.risk.control.model.qywx.RiskUserInfo;
+import com.tzld.piaoquan.risk.control.service.impl.RiskUserHandleService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+@RestController
+@RequestMapping("/qw")
+@Slf4j
 public class ReceiveRiskInfoController {
+    @Autowired
+    private QywxConfig qywxConfig; // 注入配置类
+    @Autowired
+    private RiskUserHandleService riskUserHandleService;
 
+    /**
+     * 接收风控用户信息
+     * @param userInfo 风控用户信息
+     * @return CommonResponse
+     */
+    @PostMapping("/push/riskuser")
+    public CommonResponse<String> receiveRiskUser(@RequestBody RiskUserInfo userInfo) {
+        log.info("receiveRiskUser, userInfo: {}", userInfo);
+        riskUserHandleService.handleRiskUser(userInfo);
+        return CommonResponse.success();
+    }
 }

+ 8 - 0
risk-control-server/src/main/resources/application.yml

@@ -26,6 +26,8 @@ pagehelper:
   helper-dialect: mysql
 qywx:
   domain: http://47.110.132.222:8083
+  corpid: 1970325203990889
+  scorpid: ww2c0a198821e1869f
   paths:
     init-uuid: /wxwork/init
     login-qrcode: /wxwork/getQrCode
@@ -34,6 +36,12 @@ qywx:
     auto-login: wxwork/automaticLogin
     quit-login: wxwork/LoginOut
     get-clients: /wxwork/getClients
+    chatIdToRoomId: /wxwork/ChatIdToRoomId
+    userId2Vid: /wxwork/UserId2Vid
+    get-chatList: /wxwork/GetChatroomMembers
+    get-roomMembers: /wxwork/GetRoomUserList
+    kick-external: /wxwork/addOrSubRoomBlackList
+
     # 其他路径可继续添加,例如:
     # login: /login
     # send-msg: /send-msg