yaodaoseng 2 weeks ago
parent
commit
38f9c19366

+ 296 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/dao/mapper/QywxBlacklistUserMapper.java

@@ -0,0 +1,296 @@
+package com.tzld.piaoquan.risk.control.dao.mapper;
+
+import com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUser;
+import com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUserExample;
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 企业微信黑名单用户数据访问接口
+ * 
+ * 该接口定义了对qywx_blacklist_user表的所有数据库操作方法。
+ * 遵循MyBatis的标准模式,提供完整的CRUD操作支持。
+ * 
+ * 主要功能:
+ * 1. 基础CRUD操作:增删改查
+ * 2. 条件查询:支持复杂查询条件
+ * 3. 统计功能:记录数量统计
+ * 4. 批量操作:批量删除和更新
+ * 
+ * 业务应用场景:
+ * - 黑名单用户的增删改查
+ * - 风控系统中的黑名单检查
+ * - 管理后台的黑名单管理
+ * - 数据统计和报表生成
+ * 
+ * 注意事项:
+ * 1. 所有方法都会被MyBatis代理实现
+ * 2. 参数校验在Service层进行
+ * 3. 事务管理在Service层控制
+ * 4. 异常处理在上层业务逻辑中处理
+ * 
+ * @author MyBatis Generator
+ * @since 1.0.0
+ */
+public interface QywxBlacklistUserMapper {
+    
+    /**
+     * 根据查询条件统计记录数量
+     * 
+     * 该方法用于统计满足特定条件的黑名单用户数量,主要应用场景:
+     * 1. 分页查询前的总数统计
+     * 2. 数据报表中的统计信息
+     * 3. 业务逻辑中的数量判断
+     * 4. 性能监控中的数据量评估
+     * 
+     * SQL逻辑:
+     * - 基础SQL:SELECT COUNT(*) FROM qywx_blacklist_user
+     * - 根据example中的条件动态拼接WHERE子句
+     * - 支持复杂的AND/OR条件组合
+     * 
+     * 性能考虑:
+     * - 利用数据库索引优化COUNT查询
+     * - 避免在大数据量时频繁调用
+     * 
+     * @param example 查询条件对象,包含WHERE条件、排序等信息
+     *                如果为null或无条件,则统计全表记录数
+     * @return 满足条件的记录数量,类型为long以支持大数据量
+     */
+    long countByExample(QywxBlacklistUserExample example);
+
+    /**
+     * 根据查询条件批量删除记录
+     * 
+     * 该方法用于批量删除满足特定条件的黑名单记录,主要应用场景:
+     * 1. 管理员批量清理过期的黑名单记录
+     * 2. 数据维护中的批量删除操作
+     * 3. 业务规则变更时的数据清理
+     * 
+     * SQL逻辑:
+     * - 基础SQL:DELETE FROM qywx_blacklist_user
+     * - 根据example中的条件动态拼接WHERE子句
+     * - 支持复杂的删除条件组合
+     * 
+     * 安全考虑:
+     * - 必须有WHERE条件,避免误删全表数据
+     * - 建议在Service层添加额外的安全检查
+     * - 重要操作前应该先备份数据
+     * 
+     * 事务处理:
+     * - 该操作应该在事务中执行
+     * - 删除失败时能够回滚
+     * 
+     * @param example 删除条件对象,定义要删除的记录范围
+     *                不能为null且必须包含有效的WHERE条件
+     * @return 实际删除的记录数量
+     */
+    int deleteByExample(QywxBlacklistUserExample example);
+
+    /**
+     * 根据主键删除单条记录
+     * 
+     * 该方法用于删除指定主键的黑名单记录,主要应用场景:
+     * 1. 管理界面中的单个记录删除
+     * 2. 业务逻辑中的精确删除操作
+     * 3. 数据清理中的逐个删除
+     * 
+     * SQL逻辑:
+     * - 执行SQL:DELETE FROM qywx_blacklist_user WHERE id = #{id}
+     * - 基于主键的精确删除,性能最优
+     * 
+     * 返回值说明:
+     * - 1:删除成功
+     * - 0:记录不存在或删除失败
+     * 
+     * @param id 要删除记录的主键ID,不能为null
+     * @return 删除的记录数量(0或1)
+     */
+    int deleteByPrimaryKey(Long id);
+
+    /**
+     * 插入完整记录
+     * 
+     * 该方法插入一条完整的黑名单记录,所有字段都会被设置。
+     * 主要应用场景:
+     * 1. 新增黑名单用户时的完整数据插入
+     * 2. 数据迁移时的批量插入
+     * 
+     * SQL逻辑:
+     * - 插入所有字段的值,包括null值
+     * - 主键ID由数据库自动生成
+     * - create_time和update_time由数据库默认值设置
+     * 
+     * 注意事项:
+     * - 插入后会自动设置生成的主键ID到对象中
+     * - vid字段必须唯一,重复插入会失败
+     * 
+     * @param record 要插入的黑名单用户对象,不能为null
+     * @return 插入的记录数量(通常为1)
+     */
+    int insert(QywxBlacklistUser record);
+
+    /**
+     * 选择性插入记录
+     * 
+     * 该方法只插入非null字段的值,null字段会使用数据库默认值。
+     * 这是推荐的插入方式,主要应用场景:
+     * 1. 业务代码中的常规插入操作
+     * 2. 只设置必要字段,其他字段使用默认值
+     * 3. 避免覆盖数据库的自动设置字段
+     * 
+     * SQL逻辑:
+     * - 动态构建INSERT语句,只包含非null字段
+     * - 利用MyBatis的动态SQL特性
+     * - 数据库默认值字段(如时间戳)会自动设置
+     * 
+     * 优势:
+     * - 更灵活的插入方式
+     * - 避免不必要的字段设置
+     * - 更好地利用数据库特性
+     * 
+     * @param record 要插入的黑名单用户对象,只有非null字段会被插入
+     * @return 插入的记录数量(通常为1)
+     */
+    int insertSelective(QywxBlacklistUser record);
+
+    /**
+     * 根据查询条件查询记录列表
+     * 
+     * 该方法是最核心的查询方法,支持各种复杂查询条件。
+     * 主要应用场景:
+     * 1. 黑名单检查:判断用户是否在黑名单中
+     * 2. 分页查询:管理界面的分页展示
+     * 3. 条件查询:按时间、VID等条件筛选
+     * 4. 数据导出:获取符合条件的所有记录
+     * 
+     * SQL逻辑:
+     * - 基础SQL:SELECT * FROM qywx_blacklist_user
+     * - 根据example动态拼接WHERE、ORDER BY等子句
+     * - 支持分页、排序、去重等功能
+     * 
+     * 性能优化:
+     * - 合理使用索引提高查询性能
+     * - 避免查询大量数据,建议使用分页
+     * - 复杂查询条件应该经过性能测试
+     * 
+     * @param example 查询条件对象,包含WHERE条件、排序、分页等信息
+     *                如果为null,则查询所有记录(不推荐)
+     * @return 满足条件的黑名单用户列表,可能为空但不会为null
+     */
+    List<QywxBlacklistUser> selectByExample(QywxBlacklistUserExample example);
+
+    /**
+     * 根据主键查询单条记录
+     * 
+     * 该方法用于精确查询指定主键的记录,性能最优。
+     * 主要应用场景:
+     * 1. 根据ID获取完整的记录信息
+     * 2. 更新操作前的数据获取
+     * 3. 详情页面的数据展示
+     * 
+     * SQL逻辑:
+     * - 执行SQL:SELECT * FROM qywx_blacklist_user WHERE id = #{id}
+     * - 基于主键索引,查询性能最优
+     * 
+     * 返回值说明:
+     * - 找到记录:返回完整的对象
+     * - 未找到:返回null
+     * 
+     * @param id 主键ID,不能为null
+     * @return 对应的黑名单用户对象,如果不存在则返回null
+     */
+    QywxBlacklistUser selectByPrimaryKey(Long id);
+
+    /**
+     * 根据条件选择性更新记录
+     * 
+     * 该方法根据查询条件批量更新记录,只更新非null字段。
+     * 主要应用场景:
+     * 1. 批量更新操作
+     * 2. 条件性的字段更新
+     * 3. 数据维护中的批量修改
+     * 
+     * SQL逻辑:
+     * - 基础SQL:UPDATE qywx_blacklist_user SET ...
+     * - 只更新record中非null的字段
+     * - 根据example中的条件确定更新范围
+     * 
+     * 安全考虑:
+     * - 必须有WHERE条件,避免误更新全表
+     * - 建议在Service层添加更新范围检查
+     * 
+     * @param record 包含要更新字段值的对象,只有非null字段会被更新
+     * @param example 更新条件对象,定义要更新的记录范围
+     * @return 实际更新的记录数量
+     */
+    int updateByExampleSelective(@Param("record") QywxBlacklistUser record, 
+                                @Param("example") QywxBlacklistUserExample example);
+
+    /**
+     * 根据条件完整更新记录
+     * 
+     * 该方法根据查询条件批量更新记录,更新所有字段(包括null值)。
+     * 主要应用场景:
+     * 1. 需要清空某些字段的批量更新
+     * 2. 完整替换记录内容的操作
+     * 
+     * SQL逻辑:
+     * - 更新record中的所有字段,包括null值
+     * - 根据example中的条件确定更新范围
+     * 
+     * 注意事项:
+     * - 会覆盖所有字段,包括设置为null
+     * - 通常不推荐使用,建议使用选择性更新
+     * 
+     * @param record 包含完整字段值的对象
+     * @param example 更新条件对象,定义要更新的记录范围
+     * @return 实际更新的记录数量
+     */
+    int updateByExample(@Param("record") QywxBlacklistUser record, 
+                       @Param("example") QywxBlacklistUserExample example);
+
+    /**
+     * 根据主键选择性更新记录
+     * 
+     * 该方法根据主键更新单条记录,只更新非null字段。
+     * 这是最常用的更新方法,主要应用场景:
+     * 1. 管理界面中的记录编辑
+     * 2. 业务逻辑中的字段更新
+     * 3. 状态变更等部分字段更新
+     * 
+     * SQL逻辑:
+     * - 基础SQL:UPDATE qywx_blacklist_user SET ... WHERE id = #{id}
+     * - 只更新非null字段,保持其他字段不变
+     * - update_time字段会自动更新为当前时间
+     * 
+     * 优势:
+     * - 精确更新,性能最优
+     * - 灵活的字段更新策略
+     * - 自动维护更新时间
+     * 
+     * @param record 包含要更新字段值的对象,必须包含有效的主键ID
+     * @return 更新的记录数量(0或1)
+     */
+    int updateByPrimaryKeySelective(QywxBlacklistUser record);
+
+    /**
+     * 根据主键完整更新记录
+     * 
+     * 该方法根据主键更新单条记录的所有字段。
+     * 主要应用场景:
+     * 1. 完整替换记录内容
+     * 2. 需要清空某些字段的更新操作
+     * 
+     * SQL逻辑:
+     * - 更新所有字段,包括null值
+     * - 基于主键的精确更新
+     * 
+     * 注意事项:
+     * - 会覆盖所有字段,使用时需谨慎
+     * - 通常推荐使用选择性更新方法
+     * 
+     * @param record 包含完整字段值的对象,必须包含有效的主键ID
+     * @return 更新的记录数量(0或1)
+     */
+    int updateByPrimaryKey(QywxBlacklistUser record);
+}

+ 64 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/model/po/QywxBlacklistUser.java

@@ -0,0 +1,64 @@
+package com.tzld.piaoquan.risk.control.model.po;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 企业微信黑名单用户实体类
+ *
+ * 对应数据库表: qywx_blacklist_user
+ *
+ * @author 系统生成
+ * @since 1.0.0
+ */
+@Data
+public class QywxBlacklistUser {
+    
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 企业微信用户VID
+     */
+    private Long vid;
+
+    /**
+     * 记录创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 记录更新时间
+     */
+    private Date updateTime;
+
+    @Override
+    public String toString() {
+        return "QywxBlacklistUser{" +
+                "id=" + id +
+                ", vid=" + vid +
+                ", createTime=" + createTime +
+                ", updateTime=" + updateTime +
+                '}';
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        QywxBlacklistUser that = (QywxBlacklistUser) obj;
+        return vid != null && vid.equals(that.vid);
+    }
+
+    @Override
+    public int hashCode() {
+        return vid != null ? vid.hashCode() : 0;
+    }
+}

+ 432 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/model/po/QywxBlacklistUserExample.java

@@ -0,0 +1,432 @@
+package com.tzld.piaoquan.risk.control.model.po;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 企业微信黑名单用户查询条件构建类
+ * 
+ * 该类用于构建复杂的数据库查询条件,支持MyBatis的动态SQL功能。
+ * 通过链式调用的方式,可以灵活组合各种查询条件,支持:
+ * 1. 等值查询、范围查询、模糊查询等多种条件类型
+ * 2. AND、OR逻辑组合
+ * 3. 排序、去重等查询选项
+ * 
+ * 主要应用场景:
+ * - 分页查询黑名单用户
+ * - 按VID精确查找用户
+ * - 按时间范围查询记录
+ * - 复合条件的复杂查询
+ * 
+ * 使用示例:
+ * QywxBlacklistUserExample example = new QywxBlacklistUserExample();
+ * example.createCriteria().andVidEqualTo(123456L);
+ * example.setOrderByClause("create_time DESC");
+ * 
+ * @author MyBatis Generator (手动创建基础版本)
+ * @since 1.0.0
+ */
+public class QywxBlacklistUserExample {
+    
+    /**
+     * 排序子句
+     * 
+     * 用于指定查询结果的排序方式,直接拼接到SQL的ORDER BY子句中。
+     * 常用排序:
+     * - "create_time DESC" : 按创建时间倒序
+     * - "vid ASC" : 按VID升序
+     * - "id DESC" : 按主键倒序
+     */
+    protected String orderByClause;
+
+    /**
+     * 是否去重
+     * 
+     * 设置为true时,会在SELECT语句中添加DISTINCT关键字。
+     * 在黑名单查询中通常不需要去重,因为vid字段本身就是唯一的。
+     */
+    protected boolean distinct;
+
+    /**
+     * 查询条件列表
+     * 
+     * 存储所有的查询条件组合,支持多个条件组之间的OR逻辑。
+     * 每个Criteria对象代表一组AND条件,多个Criteria之间是OR关系。
+     */
+    protected List<Criteria> oredCriteria;
+
+    /**
+     * 构造函数
+     * 
+     * 初始化查询条件列表,为后续的条件构建做准备。
+     */
+    public QywxBlacklistUserExample() {
+        oredCriteria = new ArrayList<>();
+    }
+
+    /**
+     * 设置排序子句
+     * 
+     * @param orderByClause 排序子句,如 "create_time DESC, vid ASC"
+     */
+    public void setOrderByClause(String orderByClause) {
+        this.orderByClause = orderByClause;
+    }
+
+    /**
+     * 获取排序子句
+     * 
+     * @return 当前设置的排序子句
+     */
+    public String getOrderByClause() {
+        return orderByClause;
+    }
+
+    /**
+     * 设置是否去重
+     * 
+     * @param distinct true表示去重,false表示不去重
+     */
+    public void setDistinct(boolean distinct) {
+        this.distinct = distinct;
+    }
+
+    /**
+     * 获取是否去重设置
+     * 
+     * @return 当前的去重设置
+     */
+    public boolean isDistinct() {
+        return distinct;
+    }
+
+    /**
+     * 获取所有查询条件组
+     * 
+     * @return 查询条件组列表
+     */
+    public List<Criteria> getOredCriteria() {
+        return oredCriteria;
+    }
+
+    /**
+     * 添加OR条件组
+     * 
+     * 用于添加一个新的条件组,与现有条件组之间是OR关系。
+     * 
+     * @param criteria 要添加的条件组
+     */
+    public void or(Criteria criteria) {
+        oredCriteria.add(criteria);
+    }
+
+    /**
+     * 创建新的条件组
+     * 
+     * 创建一个新的Criteria对象并添加到条件列表中。
+     * 这是最常用的方法,用于开始构建查询条件。
+     * 
+     * @return 新创建的条件组对象
+     */
+    public Criteria or() {
+        Criteria criteria = createCriteriaInternal();
+        oredCriteria.add(criteria);
+        return criteria;
+    }
+
+    /**
+     * 创建默认条件组
+     * 
+     * 如果还没有任何条件组,则创建第一个条件组。
+     * 这是最常用的入口方法。
+     * 
+     * @return 条件组对象,用于链式调用
+     */
+    public Criteria createCriteria() {
+        Criteria criteria = createCriteriaInternal();
+        if (oredCriteria.size() == 0) {
+            oredCriteria.add(criteria);
+        }
+        return criteria;
+    }
+
+    /**
+     * 内部方法:创建条件组实例
+     * 
+     * @return 新的条件组实例
+     */
+    protected Criteria createCriteriaInternal() {
+        Criteria criteria = new Criteria();
+        return criteria;
+    }
+
+    /**
+     * 清空所有查询条件
+     * 
+     * 重置Example对象到初始状态,清除所有已设置的查询条件。
+     */
+    public void clear() {
+        oredCriteria.clear();
+        orderByClause = null;
+        distinct = false;
+    }
+
+    /**
+     * 查询条件构建器
+     * 
+     * 用于构建具体的查询条件,支持各种比较操作符和逻辑组合。
+     * 每个条件方法都返回当前对象,支持链式调用。
+     * 
+     * 条件类型说明:
+     * - EqualTo: 等于 (=)
+     * - NotEqualTo: 不等于 (!=)
+     * - GreaterThan: 大于 (>)
+     * - GreaterThanOrEqualTo: 大于等于 (>=)
+     * - LessThan: 小于 (<)
+     * - LessThanOrEqualTo: 小于等于 (<=)
+     * - In: 在列表中 (IN)
+     * - NotIn: 不在列表中 (NOT IN)
+     * - Between: 在范围内 (BETWEEN)
+     * - NotBetween: 不在范围内 (NOT BETWEEN)
+     * - Like: 模糊匹配 (LIKE)
+     * - NotLike: 不匹配 (NOT LIKE)
+     * - IsNull: 为空 (IS NULL)
+     * - IsNotNull: 不为空 (IS NOT NULL)
+     */
+    protected abstract static class GeneratedCriteria {
+        protected List<Criterion> criteria;
+
+        protected GeneratedCriteria() {
+            super();
+            criteria = new ArrayList<>();
+        }
+
+        public boolean isValid() {
+            return criteria.size() > 0;
+        }
+
+        public List<Criterion> getAllCriteria() {
+            return criteria;
+        }
+
+        public List<Criterion> getCriteria() {
+            return criteria;
+        }
+
+        protected void addCriterion(String condition) {
+            if (condition == null) {
+                throw new RuntimeException("Value for condition cannot be null");
+            }
+            criteria.add(new Criterion(condition));
+        }
+
+        protected void addCriterion(String condition, Object value, String property) {
+            if (value == null) {
+                throw new RuntimeException("Value for " + property + " cannot be null");
+            }
+            criteria.add(new Criterion(condition, value));
+        }
+
+        protected void addCriterion(String condition, Object value1, Object value2, String property) {
+            if (value1 == null || value2 == null) {
+                throw new RuntimeException("Between values for " + property + " cannot be null");
+            }
+            criteria.add(new Criterion(condition, value1, value2));
+        }
+
+        /**
+         * 主键ID等于条件
+         * 
+         * @param value 主键ID值
+         * @return 当前条件构建器,支持链式调用
+         */
+        public Criteria andIdEqualTo(Long value) {
+            addCriterion("id =", value, "id");
+            return (Criteria) this;
+        }
+
+        /**
+         * 主键ID不等于条件
+         * 
+         * @param value 主键ID值
+         * @return 当前条件构建器,支持链式调用
+         */
+        public Criteria andIdNotEqualTo(Long value) {
+            addCriterion("id <>", value, "id");
+            return (Criteria) this;
+        }
+
+        /**
+         * VID等于条件
+         * 
+         * 这是最常用的查询条件,用于精确查找特定用户是否在黑名单中。
+         * 
+         * @param value 企业微信用户VID
+         * @return 当前条件构建器,支持链式调用
+         */
+        public Criteria andVidEqualTo(Long value) {
+            addCriterion("vid =", value, "vid");
+            return (Criteria) this;
+        }
+
+        /**
+         * VID不等于条件
+         * 
+         * @param value 企业微信用户VID
+         * @return 当前条件构建器,支持链式调用
+         */
+        public Criteria andVidNotEqualTo(Long value) {
+            addCriterion("vid <>", value, "vid");
+            return (Criteria) this;
+        }
+
+        /**
+         * VID在列表中条件
+         * 
+         * 用于批量查询多个用户的黑名单状态。
+         * 
+         * @param values VID列表
+         * @return 当前条件构建器,支持链式调用
+         */
+        public Criteria andVidIn(List<Long> values) {
+            addCriterion("vid in", values, "vid");
+            return (Criteria) this;
+        }
+
+        /**
+         * 创建时间大于等于条件
+         * 
+         * 用于查询指定时间之后创建的黑名单记录。
+         * 
+         * @param value 时间值
+         * @return 当前条件构建器,支持链式调用
+         */
+        public Criteria andCreateTimeGreaterThanOrEqualTo(Date value) {
+            addCriterion("create_time >=", value, "createTime");
+            return (Criteria) this;
+        }
+
+        /**
+         * 创建时间小于等于条件
+         * 
+         * 用于查询指定时间之前创建的黑名单记录。
+         * 
+         * @param value 时间值
+         * @return 当前条件构建器,支持链式调用
+         */
+        public Criteria andCreateTimeLessThanOrEqualTo(Date value) {
+            addCriterion("create_time <=", value, "createTime");
+            return (Criteria) this;
+        }
+
+        /**
+         * 创建时间在范围内条件
+         * 
+         * 用于查询指定时间范围内创建的黑名单记录。
+         * 
+         * @param value1 开始时间
+         * @param value2 结束时间
+         * @return 当前条件构建器,支持链式调用
+         */
+        public Criteria andCreateTimeBetween(Date value1, Date value2) {
+            addCriterion("create_time between", value1, value2, "createTime");
+            return (Criteria) this;
+        }
+    }
+
+    /**
+     * 具体的条件构建器实现
+     * 
+     * 继承自GeneratedCriteria,提供完整的条件构建功能。
+     */
+    public static class Criteria extends GeneratedCriteria {
+        protected Criteria() {
+            super();
+        }
+    }
+
+    /**
+     * 单个查询条件
+     * 
+     * 表示一个具体的查询条件,包含条件字符串和参数值。
+     */
+    public static class Criterion {
+        private String condition;
+        private Object value;
+        private Object secondValue;
+        private boolean noValue;
+        private boolean singleValue;
+        private boolean betweenValue;
+        private boolean listValue;
+        private String typeHandler;
+
+        public String getCondition() {
+            return condition;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+
+        public Object getSecondValue() {
+            return secondValue;
+        }
+
+        public boolean isNoValue() {
+            return noValue;
+        }
+
+        public boolean isSingleValue() {
+            return singleValue;
+        }
+
+        public boolean isBetweenValue() {
+            return betweenValue;
+        }
+
+        public boolean isListValue() {
+            return listValue;
+        }
+
+        public String getTypeHandler() {
+            return typeHandler;
+        }
+
+        protected Criterion(String condition) {
+            super();
+            this.condition = condition;
+            this.typeHandler = null;
+            this.noValue = true;
+        }
+
+        protected Criterion(String condition, Object value, String typeHandler) {
+            super();
+            this.condition = condition;
+            this.value = value;
+            this.typeHandler = typeHandler;
+            if (value instanceof List<?>) {
+                this.listValue = true;
+            } else {
+                this.singleValue = true;
+            }
+        }
+
+        protected Criterion(String condition, Object value) {
+            this(condition, value, null);
+        }
+
+        protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
+            super();
+            this.condition = condition;
+            this.value = value;
+            this.secondValue = secondValue;
+            this.typeHandler = typeHandler;
+            this.betweenValue = true;
+        }
+
+        protected Criterion(String condition, Object value, Object secondValue) {
+            this(condition, value, secondValue, null);
+        }
+    }
+}

+ 62 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/service/BlacklistService.java

@@ -0,0 +1,62 @@
+package com.tzld.piaoquan.risk.control.service;
+
+import com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUser;
+import com.github.pagehelper.PageInfo;
+import java.util.List;
+
+/**
+ * 黑名单管理服务接口
+ *
+ * @author 风控系统开发团队
+ * @since 1.0.0
+ */
+public interface BlacklistService {
+    
+    /**
+     * 检查用户是否在黑名单中
+     *
+     * @param vid 企业微信用户VID,不能为null
+     * @return true表示用户在黑名单中,false表示不在黑名单中
+     */
+    boolean isInBlacklist(Long vid);
+    
+    /**
+     * 添加用户到黑名单
+     *
+     * @param vid 企业微信用户VID,不能为null且必须是有效的用户ID
+     */
+    void addToBlacklist(Long vid);
+    
+    /**
+     * 从黑名单中移除用户
+     *
+     * @param vid 企业微信用户VID,不能为null
+     * @return true表示移除成功,false表示用户不在黑名单中
+     */
+    boolean removeFromBlacklist(Long vid);
+    
+    /**
+     * 获取所有黑名单用户(不分页)
+     *
+     * @return 所有黑名单用户的列表,按创建时间倒序排列
+     */
+    List<QywxBlacklistUser> getAllBlacklistUsers();
+    
+    /**
+     * 分页查询黑名单用户
+     *
+     * @param pageNum 页码,从1开始,必须大于0
+     * @param pageSize 每页大小,建议10-100之间
+     * @param keyword 搜索关键词,支持VID搜索,可以为null或空字符串
+     * @return 分页查询结果,包含数据列表和分页信息
+     */
+    PageInfo<QywxBlacklistUser> getBlacklistPage(int pageNum, int pageSize, String keyword);
+
+    
+    /**
+     * 获取黑名单用户总数
+     *
+     * @return 黑名单用户的总数量,类型为long以支持大数据量
+     */
+    long getBlacklistCount();
+}

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

@@ -0,0 +1,281 @@
+package com.tzld.piaoquan.risk.control.service.impl;
+
+import com.tzld.piaoquan.risk.control.dao.mapper.QywxBlacklistUserMapper;
+import com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUser;
+import com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUserExample;
+import com.tzld.piaoquan.risk.control.service.BlacklistService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 企业微信黑名单管理服务实现类
+ * @author 风控系统开发团队
+ * @since 1.0.0
+ */
+@Service
+public class BlacklistServiceImpl implements BlacklistService {
+    
+    /**
+     * 日志记录器
+     */
+    private static final Logger log = LoggerFactory.getLogger(BlacklistServiceImpl.class);
+    
+    /**
+     * 黑名单用户数据访问对象
+     */
+    @Autowired
+    private QywxBlacklistUserMapper blacklistUserMapper;
+    
+    /**
+     * 检查用户是否在黑名单中
+     *
+     * @param vid 企业微信用户VID
+     * @return true表示在黑名单中,false表示不在黑名单中
+     */
+    @Override
+    public boolean isInBlacklist(Long vid) {
+        if (vid == null) {
+            log.error("isInBlacklist called with null vid, returning false");
+            return false;
+        }
+
+        try {
+            QywxBlacklistUserExample example = new QywxBlacklistUserExample();
+            example.createCriteria().andVidEqualTo(vid);
+            long count = blacklistUserMapper.countByExample(example);
+
+            log.info("Blacklist check for vid: {}, result: {}", vid, count > 0);
+            return count > 0;
+
+        } catch (Exception e) {
+            log.error("Failed to check blacklist for vid: {}", vid, e);
+            throw new RuntimeException("黑名单检查失败,VID: " + vid, e);
+        }
+    }
+    
+    /**
+     * 添加用户到黑名单
+     *
+     * @param vid 企业微信用户VID
+     * @throws IllegalArgumentException 当vid为null或无效时
+     * @throws RuntimeException 当用户已在黑名单中或插入失败时
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void addToBlacklist(Long vid) {
+        // 参数校验:确保vid不为null
+        if (vid == null) {
+            log.error("addToBlacklist called with null vid");
+            throw new IllegalArgumentException("用户VID不能为空");
+        }
+        
+        // 业务校验:确保vid是有效的正数
+        if (vid <= 0) {
+            log.error("addToBlacklist called with invalid vid: {}", vid);
+            throw new IllegalArgumentException("用户VID必须是有效的正数");
+        }
+        
+        try {
+            // 重复检查:避免重复添加
+            if (isInBlacklist(vid)) {
+                log.warn("Attempt to add existing blacklist user, vid: {}", vid);
+                throw new RuntimeException("用户已在黑名单中,VID: " + vid);
+            }
+            
+            // 创建黑名单记录
+            QywxBlacklistUser blacklistUser = new QywxBlacklistUser();
+            blacklistUser.setVid(vid);
+            blacklistUser.setCreateTime(new Date());
+            blacklistUser.setUpdateTime(new Date());
+            
+            // 执行数据库插入:使用选择性插入,利用数据库默认值
+            int result = blacklistUserMapper.insertSelective(blacklistUser);
+            
+            // 验证插入结果
+            if (result > 0) {
+                log.info("Successfully added user to blacklist, vid: {}, id: {}", vid, blacklistUser.getId());
+            } else {
+                log.error("Failed to add user to blacklist, insert returned 0, vid: {}", vid);
+                throw new RuntimeException("添加用户到黑名单失败,数据库操作无效,VID: " + vid);
+            }
+            
+        } catch (Exception e) {
+            // 系统异常包装后抛出
+            log.error("Unexpected error while adding user to blacklist, vid: {}", vid, e);
+            throw new RuntimeException("添加用户到黑名单时发生系统异常,VID: " + vid, e);
+        }
+    }
+    
+    /**
+     * 从黑名单中移除用户
+     *
+     * @param vid 企业微信用户VID
+     * @return true表示删除成功,false表示用户不在黑名单中
+     * @throws IllegalArgumentException 当vid为null时
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean removeFromBlacklist(Long vid) {
+        // 参数校验:确保vid不为null
+        if (vid == null) {
+            log.error("removeFromBlacklist called with null vid");
+            throw new IllegalArgumentException("用户VID不能为空");
+        }
+        
+        try {
+            // 构建删除条件:按vid精确匹配
+            QywxBlacklistUserExample example = new QywxBlacklistUserExample();
+            example.createCriteria().andVidEqualTo(vid);
+            
+            // 执行删除操作
+            int result = blacklistUserMapper.deleteByExample(example);
+            
+            // 根据删除结果记录日志并返回
+            if (result > 0) {
+                log.info("Successfully removed user from blacklist, vid: {}, deleted count: {}", vid, result);
+                return true;
+            } else {
+                log.info("User not found in blacklist, no removal needed, vid: {}", vid);
+                return false;
+            }
+            
+        } catch (Exception e) {
+            // 记录异常并重新抛出
+            log.error("Failed to remove user from blacklist, vid: {}", vid, e);
+            throw new RuntimeException("从黑名单移除用户失败,VID: " + vid, e);
+        }
+    }
+
+    /**
+     * 获取所有黑名单用户(不分页)
+     *
+     * @return 所有黑名单用户列表,按创建时间倒序
+     */
+    @Override
+    public List<QywxBlacklistUser> getAllBlacklistUsers() {
+        try {
+            // 构建查询条件:查询所有记录
+            QywxBlacklistUserExample example = new QywxBlacklistUserExample();
+            // 设置排序:按创建时间倒序,最新的在前面
+            example.setOrderByClause("id DESC");
+
+            // 执行查询
+            List<QywxBlacklistUser> users = blacklistUserMapper.selectByExample(example);
+
+            // 记录查询结果
+            log.info("Retrieved all blacklist users, total count: {}", users.size());
+
+            // 如果数据量过大,记录警告
+            if (users.size() > 1000) {
+                log.warn("Large blacklist dataset retrieved: {} records, consider using pagination", users.size());
+            }
+
+            return users;
+
+        } catch (Exception e) {
+            log.error("Failed to retrieve all blacklist users", e);
+            throw new RuntimeException("获取所有黑名单用户失败", e);
+        }
+    }
+
+    /**
+     * 分页查询黑名单用户
+     *
+     * @param pageNum 页码,从1开始
+     * @param pageSize 每页大小
+     * @param keyword 搜索关键词,支持VID搜索
+     * @return 分页查询结果
+     */
+    @Override
+    public PageInfo<QywxBlacklistUser> getBlacklistPage(int pageNum, int pageSize, String keyword) {
+        // 参数校验:确保分页参数有效
+        if (pageNum <= 0) {
+            throw new IllegalArgumentException("页码必须大于0");
+        }
+        if (pageSize <= 0) {
+            throw new IllegalArgumentException("每页大小必须大于0");
+        }
+        if (pageSize > 1000) {
+            log.warn("Large page size requested: {}, consider reducing for better performance", pageSize);
+        }
+
+        try {
+            // 启动分页:设置页码和每页大小
+            PageHelper.startPage(pageNum, pageSize);
+
+            // 构建查询条件
+            QywxBlacklistUserExample example = new QywxBlacklistUserExample();
+            QywxBlacklistUserExample.Criteria criteria = example.createCriteria();
+
+            // 处理搜索关键词:支持VID搜索
+            if (StringUtils.hasText(keyword)) {
+                try {
+                    // 尝试将关键词解析为VID(Long类型)
+                    Long vidKeyword = Long.parseLong(keyword.trim());
+                    criteria.andVidEqualTo(vidKeyword);
+                    log.debug("Searching blacklist by VID: {}", vidKeyword);
+                } catch (NumberFormatException e) {
+                    // 关键词不是有效的数字,记录警告并返回空结果
+                    log.warn("Invalid VID keyword for blacklist search: {}", keyword);
+                    // 设置一个不可能存在的VID,确保返回空结果
+                    criteria.andVidEqualTo(-1L);
+                }
+            }
+
+            // 设置排序:按创建时间倒序
+            example.setOrderByClause("id DESC");
+
+            // 执行查询:PageHelper会自动添加分页条件
+            List<QywxBlacklistUser> users = blacklistUserMapper.selectByExample(example);
+
+            // 构建分页结果:PageInfo包含数据和分页信息
+            PageInfo<QywxBlacklistUser> pageInfo = new PageInfo<>(users);
+
+            // 记录查询结果
+            log.info("Paginated blacklist query completed - page: {}, size: {}, total: {}, keyword: '{}'",
+                    pageNum, pageSize, pageInfo.getTotal(), keyword);
+
+            return pageInfo;
+
+        } catch (Exception e) {
+            log.error("Failed to query blacklist page - page: {}, size: {}, keyword: '{}'",
+                    pageNum, pageSize, keyword, e);
+            throw new RuntimeException("分页查询黑名单用户失败", e);
+        }
+    }
+
+
+    /**
+     * 获取黑名单用户总数
+     *
+     * @return 黑名单用户总数
+     */
+    @Override
+    public long getBlacklistCount() {
+        try {
+            // 构建查询条件:统计所有记录
+            QywxBlacklistUserExample example = new QywxBlacklistUserExample();
+
+            // 执行COUNT查询
+            long count = blacklistUserMapper.countByExample(example);
+
+            // 记录统计结果
+            log.debug("Blacklist user count: {}", count);
+
+            return count;
+
+        } catch (Exception e) {
+            log.error("Failed to get blacklist user count", e);
+            throw new RuntimeException("获取黑名单用户总数失败", e);
+        }
+    }
+}

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

@@ -7,6 +7,7 @@ import com.tzld.piaoquan.risk.control.model.po.UserBase;
 import com.tzld.piaoquan.risk.control.model.po.WorkWechatRoomInfo;
 import com.tzld.piaoquan.risk.control.model.po.WorkWechatRoomInfoExample;
 import com.tzld.piaoquan.risk.control.model.qywx.*;
+import com.tzld.piaoquan.risk.control.service.BlacklistService;
 import com.tzld.piaoquan.risk.control.util.HttpClientUtil;
 import com.tzld.piaoquan.risk.control.util.HttpPoolClient;
 import lombok.extern.slf4j.Slf4j;
@@ -26,79 +27,40 @@ public class RiskUserOperateService {
     private QywxConfig qywxConfig; // 注入配置类
     @Autowired
     private WorkWechatRoomInfoMapper workWechatRoomInfoMapper;
+
+    /**
+     * 黑名单管理服务,用于替换硬编码的黑名单检查逻辑
+     */
+    @Autowired
+    private BlacklistService blacklistService;
     @Value("${qywx.corpid}")
     private long corpid;
     private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(10000, 10000, 2000, 5000, 5, 10000);
-    private static final Logger LOGGER = LoggerFactory.getLogger(RiskUserHandleService.class);
-//    private static final List<Long> BLACKLIST_VID = Collections.unmodifiableList(Arrays.asList(7881302926289574L,7881299753025521L));
-    // 初始化不可变黑名单(合并现有值和JSON中的新值)
-    private static final List<Long> BLACKLIST_VID = Collections.unmodifiableList(
-        Arrays.asList(
-                // 原始值
-                7881302926289574L,
-                7881299753025521L,
-                // 从JSON数据中提取的所有blacklist_vid(已去重)
-                7881300466122683L, 7881300229048031L, 7881302316912185L,
-                7881301869028248L, 7881301211163085L, 7881302796091767L,
-                7881301324066702L, 7881300281998722L, 7881301967034720L,
-                7881301678337366L, 7881300378068659L, 7881302223127319L,
-                7881299679315751L, 7881302327344543L, 7881303556905502L,
-                7881300420063544L, 7881303114007258L, 7881299609215302L,
-                7881303411344664L, 7881300499073181L, 7881302121982115L,
-                7881301622998984L, 7881302715121782L, 7881301469189163L,
-                7881301825004114L, 7881303480126257L, 7881303502084260L,
-                7881300158073529L, 7881300519959317L, 7881301866079037L,
-                7881303096191474L, 7881303368954132L, 7881302764132335L,
-                7881302001968032L, 7881302064983891L, 7881303276328299L,
-                7881302018273598L, 7881303641326502L, 7881301501262524L,
-                7881301460217143L, 7881299789313131L, 7881300854349663L,
-                7881301505271795L, 7881300193294802L, 7881300949997575L,
-                7881302066324600L, 7881301257978308L, 7881303083154066L,
-                7881300846203333L, 7881301661295267L, 7881300149063751L,
-                7881303421311587L, 7881300317046467L, 7881301426914509L,
-                7881301034118168L, 7881303360258534L, 7881300540110306L,
-                7881303335206573L, 7881301178336419L, 7881299476125798L,
-                7881302710301946L, 7881301346342921L, 7881300543276102L,
-                7881302549156012L, 7881300984974896L, 7881300905339945L,
-                7881300014351503L, 7881299626065317L, 1688858033727935L,
-                7881303486038982L, 7881301946106537L, 7881303093341615L,
-                7881300064125930L, 7881301841001514L, 7881303046088935L,
-                7881302404997826L, 7881302075019397L, 7881300148942179L,
-                7881299647166280L, 7881299915041354L, 7881300444249607L,
-                7881300767993441L, 7881302633972298L, 7881300416188902L,
-                7881303513904106L, 7881300749032748L, 7881300268925255L,
-                7881303315067789L, 7881300808351909L, 7881300791125480L,
-                7881302408161558L, 7881302137137423L, 7881301119340365L,
-                7881302367951032L, 7881301267044221L, 7881301416981370L,
-                7881300843989486L, 7881302471324028L, 7881301871965471L,
-                7881301393187836L, 7881301698289157L, 7881303388311144L,
-                7881300820304366L, 7881299665950989L, 7881301992001273L,
-                7881302286953152L, 7881299836040719L, 7881300144150372L,
-                7881302832139110L, 7881302260054092L, 7881300488072079L,
-                7881299606154483L, 7881302132328341L, 7881301177020994L,
-                7881299603349260L, 7881301200004722L, 7881300437123751L,
-                7881301055969437L, 7881301654914877L, 7881300090992802L,
-                7881300090924829L, 7881300095962888L, 7881301643139014L,
-                7881303024343207L, 7881302048307942L, 7881303218068450L,
-                7881301852350459L, 7881301482317014L, 7881301843321743L,
-                7881302927306074L, 7881302900372515L, 7881302628314176L,
-                7881302733026214L, 7881303417300674L, 7881301797041258L,
-                7881302328298167L, 7881299771077377L, 7881301278033375L,
-                7881299963273148L, 7881299551165243L, 7881302964181882L,
-                7881300960043108L, 7881303282925921L, 7881301679355925L,
-                7881303320029350L, 7881299472340204L, 7881303594961434L,
-                7881300778933287L, 7881303467988227L, 7881299452963981L,
-                7881301668344400L, 7881303357010444L, 7881303133173876L,
-                7881303227934766L, 7881300066348945L, 7881301311983065L,
-                7881302496352111L, 7881299632359909L, 7881303344140343L,
-                7881301136317724L, 7881301988332126L, 7881300283335703L,
-                7881301475333555L, 7881301678333870L
-        )
-);
+    private static final Logger logger = LoggerFactory.getLogger(RiskUserHandleService.class);
+
+    /*
+     * 原硬编码黑名单常量已移除,改为使用数据库动态管理
+     *
+     * 迁移说明:
+     * 1. 原BLACKLIST_VID常量包含约120个用户VID
+     * 2. 这些VID已通过管理界面手动迁移到qywx_blacklist_user表中
+     * 3. 现在通过BlacklistService.isInBlacklist()方法进行黑名单检查
+     * 4. 支持动态添加、删除黑名单用户,无需重启服务
+     *
+     * 原硬编码数据备份(仅供参考,已迁移到数据库):
+     * private static final List<Long> BLACKLIST_VID = Collections.unmodifiableList(
+     *     Arrays.asList(
+     *         7881302926289574L, 7881299753025521L, 7881300466122683L, ...
+     *         // 共约120个VID,完整列表见数据迁移文档
+     *     )
+     * );
+     */
 
     /**
      * 快速踢人功能 - 当检测到新成员加入群聊时,立即执行踢人操作
      *
+     * 重构说明:使用数据库查询替换硬编码的黑名单检查
+     *
      * @param message 群聊新增成员消息,包含新加入的成员信息
      * @param uuid 企业微信用户的唯一标识符
      * @return true-踢人成功,false-踢人失败或不满足踢人条件
@@ -113,20 +75,26 @@ public class RiskUserOperateService {
 
             // 检查成员列表是否为空
             if(message.getMemberList().isEmpty()) {
+                logger.warn("quickKick: member list is empty, skipping operation");
                 return false;
             }
 
             // 获取第一个新加入的成员VID(企业微信内部用户ID)
             long vid = message.getMemberList().get(0);
 
-            // 黑名单检查 - 如果用户不在黑名单中,则跳过踢人操作(保护重要用户)
-            if(!BLACKLIST_VID.contains(vid)) {
-                LOGGER.info("quickKick, vid: {} is in blacklist, skip kick", vid);
+            // 黑名单检查 - 使用数据库查询替换硬编码检查
+            try {
+                if( !blacklistService.isInBlacklist(vid)) {
+                    logger.info("quickKick: vid {} is not in blacklist, skip kick operation", vid);
+                    return false;
+                }
+            } catch (Exception e) {
+                logger.error("quickKick: failed to check blacklist for vid {}, skipping kick for safety", vid, e);
                 return false;
             }
 
-            // 如果是群聊,直接踢出
-            LOGGER.info("quickKick, message: {}, uuid: {}", message, uuid);
+            // 群聊,直接踢出
+            logger.info("quickKick, message: {}, uuid: {}", message, uuid);
 
             // 设置要踢出的用户VID列表
             requestBody.put("blacklist_vid",Arrays.asList(message.getMemberList().get(0)));
@@ -144,15 +112,15 @@ public class RiskUserOperateService {
 
                 // 检查操作是否成功(errcode=0表示成功)
                 if (roomInfo.getErrcode() == 0) {
-                    LOGGER.info("quick Kick external user {} from room {} successfully", vid);
+                    logger.info("quick Kick external user {} from room {} successfully", vid);
                     return true;
                 } else {
                     // 踢人失败,记录错误信息
-                    LOGGER.error("Failed to kick external user {} f: {}", vid, roomInfo.getErrmsg());
+                    logger.error("Failed to kick external user {} f: {}", vid, roomInfo.getErrmsg());
                 }
             } else {
                 // API调用失败,没有收到响应
-                LOGGER.error("Failed to kick external user {} from : No response", vid);
+                logger.error("Failed to kick external user {} from : No response", vid);
             }
 
             // 默认返回失败
@@ -163,41 +131,44 @@ public class RiskUserOperateService {
         return false;
     }
 
-    public boolean checkAndKickExternalUser(UserBase staff,RiskUserInfo riskUserInfo,long vid,long roomId) {
-        LOGGER.info("checkAndKickExternalUser, staff: {}, riskUserInfo: {}, vid: {}, roomId: {}", staff, riskUserInfo, vid, roomId);
-        boolean inRoom = isInRoom(staff, roomId, vid);
-        if (!inRoom) {
-            LOGGER.info("User {} is not in room {}", vid, roomId);
-            return false;
-        }
-        LOGGER.info("User {} is in room {}", vid, roomId);
-        kick(staff, roomId, vid);
-
-        return true;
-    }
-
+    /**
+     * 踢人功能 - 将指定用户从指定群聊中踢出
+     *
+     * 重构说明:使用数据库查询替换硬编码的黑名单检查
+     *
+     * @param staff 执行踢人操作的员工信息
+     * @param roomId 群聊ID
+     * @param vid 要踢出的用户VID
+     * @return true-踢人成功或跳过,false-踢人失败
+     */
     public boolean kick(UserBase staff, long roomId, long vid) {
-        if(BLACKLIST_VID.contains(vid)) {
-            LOGGER.info("kick, vid: {} is in blacklist, skip normal kick", vid);
-            return true;
+        // 黑名单检查 - 使用数据库查询替换硬编码检查
+        try {
+            if(blacklistService.isInBlacklist(vid)) {
+                logger.info("kick: vid {} is in blacklist, skip normal kick operation", vid);
+                return true;
+            }
+            logger.debug("kick: vid {} is not in blacklist, proceeding with kick operation", vid);
+        } catch (Exception e) {
+            logger.error("kick: failed to check blacklist for vid {}", vid, e);
         }
         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);
-        LOGGER.info("kick, staff: {}, params: {}", staff, params);
+        logger.info("kick, staff: {}, params: {}", staff, params);
         Optional<String> response = httpPoolClientDefault.postJson(qywxConfig.getDomain() + qywxConfig.getPath("kick-external"), params);
         if (response.isPresent()) {
             QwCommonResModel<RoomListResponse> roomInfo = QwCommonResModel.parseResponse(response.get(), RoomListResponse.class);
             if (roomInfo.getErrcode() == 0) {
-                LOGGER.info("Kick external user {} from room {} successfully", vid, roomId);
+                logger.info("Kick external user {} from room {} successfully", vid, roomId);
                 return true;
             } else {
-                LOGGER.error("Failed to kick external user {} from room {}: {}", vid, roomId, roomInfo.getErrmsg());
+                logger.error("Failed to kick external user {} from room {}: {}", vid, roomId, roomInfo.getErrmsg());
             }
         } else {
-            LOGGER.error("Failed to kick external user {} from room {}: No response", vid, roomId);
+            logger.error("Failed to kick external user {} from room {}: No response", vid, roomId);
         }
         return false;
     }
@@ -206,12 +177,12 @@ public class RiskUserOperateService {
     public boolean isInRoom(UserBase staff, long roomId,long vid) {
         List<RoomMemberListInfo.Member> memberList = getRoomMemberList(staff, roomId);
         if (memberList == null || memberList.isEmpty()) {
-            LOGGER.info("isInRoom, memberList is empty");
+            logger.info("isInRoom, memberList is empty");
             return false;
         }
-        LOGGER.info("isInRoom, memberList: {}", memberList);
+        logger.info("isInRoom, memberList: {}", memberList);
         for (RoomMemberListInfo.Member member : memberList) {
-            LOGGER.info("isInRoom, member: {}", member);
+            logger.info("isInRoom, member: {}", member);
             if (member.getUin() == vid && member.getJoinScene() == 3) {
                 return true;
             }
@@ -226,7 +197,7 @@ public class RiskUserOperateService {
         String params = JSON.toJSONString(requestBody);
         String url = qywxConfig.getDomain() + qywxConfig.getPath("get-roomMembers");
         Optional<String> response = httpPoolClientDefault.postJson(url, params);
-        LOGGER.info("getRoomMemberList, params: {}, response: {},url: {}", params, response, url);
+        logger.info("getRoomMemberList, params: {}, response: {},url: {}", params, response, url);
         List<RoomMemberListInfo.Member> memberList = new ArrayList<>();
         if (response.isPresent()) {
             QwCommonResModel<RoomMemberListInfo> memberInfo = QwCommonResModel.parseResponse(response.get(), RoomMemberListInfo.class);

+ 187 - 0
risk-control-core/src/main/resources/mapper/QywxBlacklistUserMapper.xml

@@ -0,0 +1,187 @@
+<?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.tzld.piaoquan.risk.control.dao.mapper.QywxBlacklistUserMapper">
+  
+  <!-- 基础结果映射 -->
+  <resultMap id="BaseResultMap" type="com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUser">
+    <id column="id" jdbcType="BIGINT" property="id" />
+    <result column="vid" jdbcType="BIGINT" property="vid" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
+  </resultMap>
+
+  <sql id="Example_Where_Clause">
+    <where>
+      <foreach collection="oredCriteria" item="criteria" separator="or">
+        <if test="criteria.valid">
+          <trim prefix="(" prefixOverrides="and" suffix=")">
+            <foreach collection="criteria.criteria" item="criterion">
+              <choose>
+                <when test="criterion.noValue">
+                  and ${criterion.condition}
+                </when>
+                <when test="criterion.singleValue">
+                  and ${criterion.condition} #{criterion.value}
+                </when>
+                <when test="criterion.betweenValue">
+                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+                </when>
+                <when test="criterion.listValue">
+                  and ${criterion.condition}
+                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
+                    #{listItem}
+                  </foreach>
+                </when>
+              </choose>
+            </foreach>
+          </trim>
+        </if>
+      </foreach>
+    </where>
+  </sql>
+  
+  <sql id="Base_Column_List">
+    id, vid, create_time, update_time
+  </sql>
+
+  <select id="selectByExample" parameterType="com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUserExample" resultMap="BaseResultMap">
+    select
+    <if test="distinct">
+      distinct
+    </if>
+    <include refid="Base_Column_List" />
+    from qywx_blacklist_user
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+    <if test="orderByClause != null">
+      order by ${orderByClause}
+    </if>
+  </select>
+
+  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+    select 
+    <include refid="Base_Column_List" />
+    from qywx_blacklist_user
+    where id = #{id,jdbcType=BIGINT}
+  </select>
+
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
+    delete from qywx_blacklist_user
+    where id = #{id,jdbcType=BIGINT}
+  </delete>
+
+  <delete id="deleteByExample" parameterType="com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUserExample">
+    delete from qywx_blacklist_user
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+  </delete>
+
+  <insert id="insert" parameterType="com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUser">
+    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
+      SELECT LAST_INSERT_ID()
+    </selectKey>
+    insert into qywx_blacklist_user (vid, create_time, update_time)
+    values (#{vid,jdbcType=BIGINT}, #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP})
+  </insert>
+
+  <insert id="insertSelective" parameterType="com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUser">
+    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
+      SELECT LAST_INSERT_ID()
+    </selectKey>
+    insert into qywx_blacklist_user
+    <trim prefix="(" suffix=")" suffixOverrides=",">
+      <if test="vid != null">
+        vid,
+      </if>
+      <if test="createTime != null">
+        create_time,
+      </if>
+      <if test="updateTime != null">
+        update_time,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides=",">
+      <if test="vid != null">
+        #{vid,jdbcType=BIGINT},
+      </if>
+      <if test="createTime != null">
+        #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="updateTime != null">
+        #{updateTime,jdbcType=TIMESTAMP},
+      </if>
+    </trim>
+  </insert>
+  
+
+  <select id="countByExample" parameterType="com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUserExample" resultType="java.lang.Long">
+    select count(*) from qywx_blacklist_user
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+  </select>
+
+
+  <update id="updateByExampleSelective" parameterType="map">
+    update qywx_blacklist_user
+    <set>
+      <if test="record.id != null">
+        id = #{record.id,jdbcType=BIGINT},
+      </if>
+      <if test="record.vid != null">
+        vid = #{record.vid,jdbcType=BIGINT},
+      </if>
+      <if test="record.createTime != null">
+        create_time = #{record.createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="record.updateTime != null">
+        update_time = #{record.updateTime,jdbcType=TIMESTAMP},
+      </if>
+    </set>
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+  </update>
+
+
+  <update id="updateByExample" parameterType="map">
+    update qywx_blacklist_user
+    set id = #{record.id,jdbcType=BIGINT},
+      vid = #{record.vid,jdbcType=BIGINT},
+      create_time = #{record.createTime,jdbcType=TIMESTAMP},
+      update_time = #{record.updateTime,jdbcType=TIMESTAMP}
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+  </update>
+
+
+  <update id="updateByPrimaryKeySelective" parameterType="com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUser">
+    update qywx_blacklist_user
+    <set>
+      <if test="vid != null">
+        vid = #{vid,jdbcType=BIGINT},
+      </if>
+      <if test="createTime != null">
+        create_time = #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="updateTime != null">
+        update_time = #{updateTime,jdbcType=TIMESTAMP},
+      </if>
+    </set>
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+
+
+  <update id="updateByPrimaryKey" parameterType="com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUser">
+    update qywx_blacklist_user
+    set vid = #{vid,jdbcType=BIGINT},
+      create_time = #{createTime,jdbcType=TIMESTAMP},
+      update_time = #{updateTime,jdbcType=TIMESTAMP}
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+
+</mapper>

+ 244 - 0
risk-control-server/src/main/java/com/tzld/piaoquan/risk/control/controller/BlacklistController.java

@@ -0,0 +1,244 @@
+package com.tzld.piaoquan.risk.control.controller;
+
+import com.tzld.piaoquan.risk.control.common.base.CommonResponse;
+import com.tzld.piaoquan.risk.control.model.po.QywxBlacklistUser;
+import com.tzld.piaoquan.risk.control.service.BlacklistService;
+import com.github.pagehelper.PageInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 企业微信黑名单管理控制器
+ * @author 风控系统开发团队
+ * @since 1.0.0
+ */
+@RestController
+@RequestMapping("/blacklist")
+public class BlacklistController {
+    
+    private static final Logger log = LoggerFactory.getLogger(BlacklistController.class);
+
+    @Autowired
+    private BlacklistService blacklistService;
+
+    /**
+     * 分页查询黑名单用户
+     *
+     * @param pageNum 页码,从1开始
+     * @param pageSize 每页大小
+     * @param keyword 搜索关键词,支持VID搜索
+     * @return 分页查询结果,包含数据列表和分页信息
+     */
+    @GetMapping("/page")
+    public CommonResponse<PageInfo<QywxBlacklistUser>> getBlacklistPage(
+            @RequestParam(defaultValue = "1") int pageNum,
+            @RequestParam(defaultValue = "20") int pageSize,
+            @RequestParam(required = false) String keyword) {
+        
+        try {
+            // 记录API调用日志
+            log.info("Blacklist page query request - pageNum: {}, pageSize: {}, keyword: '{}'", 
+                    pageNum, pageSize, keyword);
+            
+            // 基础参数校验
+            if (pageNum <= 0) {
+                log.warn("Invalid pageNum parameter: {}", pageNum);
+                return CommonResponse.create(-1, "页码必须大于0");
+            }
+            if (pageSize <= 0 || pageSize > 1000) {
+                log.warn("Invalid pageSize parameter: {}", pageSize);
+                return CommonResponse.create(-1, "每页大小必须在1-1000之间");
+            }
+            
+            // 调用业务服务进行分页查询
+            PageInfo<QywxBlacklistUser> result = blacklistService.getBlacklistPage(pageNum, pageSize, keyword);
+            
+            // 记录查询结果
+            log.info("Blacklist page query completed - total: {}, pages: {}", 
+                    result.getTotal(), result.getPages());
+            
+            return CommonResponse.success(result);
+            
+        } catch (Exception e) {
+            // 系统异常处理
+            log.error("Failed to query blacklist page", e);
+            return CommonResponse.create(-1, "查询失败,请稍后重试");
+        }
+    }
+    
+    /**
+     * 获取所有黑名单用户(不分页)
+     * @return 所有黑名单用户列表
+     */
+    @GetMapping("/all")
+    public CommonResponse<List<QywxBlacklistUser>> getAllBlacklistUsers() {
+        try {
+            // 记录API调用日志
+            log.info("Request to get all blacklist users");
+            
+            // 调用业务服务获取所有黑名单用户
+            List<QywxBlacklistUser> users = blacklistService.getAllBlacklistUsers();
+            
+            // 记录查询结果
+            log.info("Retrieved all blacklist users, count: {}", users.size());
+            
+            // 数据量警告
+            if (users.size() > 1000) {
+                log.warn("Large blacklist dataset returned: {} records", users.size());
+            }
+            
+            return CommonResponse.success(users);
+            
+        } catch (Exception e) {
+            // 异常处理
+            log.error("Failed to get all blacklist users", e);
+            return CommonResponse.create(-1, "获取黑名单用户失败,请稍后重试");
+        }
+    }
+    
+    /**
+     * 添加用户到黑名单
+     * @param vid 企业微信用户VID
+     * @return 操作结果,成功时返回success,失败时返回错误信息
+     */
+    @PostMapping("/add")
+    public CommonResponse<Void> addBlacklistUser(@RequestParam Long vid) {
+        try {
+            // 记录API调用日志
+            log.info("Request to add user to blacklist, vid: {}", vid);
+            
+            // 基础参数校验
+            if (vid == null) {
+                log.warn("Add blacklist request with null vid");
+                return CommonResponse.create(-1, "用户VID不能为空");
+            }
+            if (vid <= 0) {
+                log.warn("Add blacklist request with invalid vid: {}", vid);
+                return CommonResponse.create(-1, "用户VID必须是有效的正数");
+            }
+            
+            // 调用业务服务添加黑名单用户
+            blacklistService.addToBlacklist(vid);
+            
+            // 记录成功日志
+            log.info("Successfully added user to blacklist, vid: {}", vid);
+            
+            return CommonResponse.success();
+            
+        } catch (Exception e) {
+            // 系统异常处理
+            log.error("Failed to add user to blacklist, vid: {}", vid, e);
+            return CommonResponse.create(-1, "添加失败,请稍后重试");
+        }
+    }
+
+    /**
+     * 从黑名单中移除用户
+     * @param vid 企业微信用户VID
+     * @return 操作结果,成功时返回success,失败时返回错误信息
+     */
+    @DeleteMapping("/{vid}")
+    public CommonResponse<Void> removeBlacklistUser(@PathVariable Long vid) {
+        try {
+            // 记录API调用日志
+            log.info("Request to remove user from blacklist, vid: {}", vid);
+
+            // 基础参数校验
+            if (vid == null) {
+                log.warn("Remove blacklist request with null vid");
+                return CommonResponse.create(-1, "用户VID不能为空");
+            }
+            if (vid <= 0) {
+                log.warn("Remove blacklist request with invalid vid: {}", vid);
+                return CommonResponse.create(-1, "用户VID必须是有效的正数");
+            }
+
+            // 调用业务服务移除黑名单用户
+            boolean removed = blacklistService.removeFromBlacklist(vid);
+
+            if (removed) {
+                // 移除成功
+                log.info("Successfully removed user from blacklist, vid: {}", vid);
+                return CommonResponse.success();
+            } else {
+                // 用户不在黑名单中
+                log.info("User not found in blacklist, vid: {}", vid);
+                return CommonResponse.create(-1, "用户不在黑名单中");
+            }
+
+        }catch (Exception e) {
+            // 系统异常处理
+            log.error("Failed to remove user from blacklist, vid: {}", vid, e);
+            return CommonResponse.create(-1, "移除失败,请稍后重试");
+        }
+    }
+
+    /**
+     * 检查用户是否在黑名单中
+     *
+     * @param vid 企业微信用户VID
+     * @return 检查结果,true表示在黑名单中,false表示不在黑名单中
+     */
+    @GetMapping("/check/{vid}")
+    public CommonResponse<Boolean> checkBlacklist(@PathVariable Long vid) {
+        try {
+            // 记录API调用日志(DEBUG级别,避免日志过多)
+            if (log.isDebugEnabled()) {
+                log.debug("Request to check blacklist status, vid: {}", vid);
+            }
+
+            // 基础参数校验
+            if (vid == null) {
+                log.warn("Check blacklist request with null vid");
+                return CommonResponse.create(-1, "用户VID不能为空");
+            }
+            if (vid <= 0) {
+                log.warn("Check blacklist request with invalid vid: {}", vid);
+                return CommonResponse.create(-1, "用户VID必须是有效的正数");
+            }
+
+            // 调用业务服务检查黑名单状态
+            boolean inBlacklist = blacklistService.isInBlacklist(vid);
+
+
+            return CommonResponse.success(inBlacklist);
+
+        } catch (Exception e) {
+            // 系统异常处理
+            log.error("Failed to check blacklist status, vid: {}", vid, e);
+            return CommonResponse.create(-1, "检查失败,请稍后重试");
+        }
+    }
+
+    /**
+     * 获取黑名单统计信息
+     * HTTP方法:
+     * 使用GET方法,符合查询操作的语义
+     *
+     * @return 黑名单用户总数
+     */
+    @GetMapping("/stats")
+    public CommonResponse<Long> getBlacklistStats() {
+        try {
+            // 记录API调用日志
+            log.info("Request to get blacklist statistics");
+
+            // 调用业务服务获取统计信息
+            long count = blacklistService.getBlacklistCount();
+
+            // 记录统计结果
+            log.info("Blacklist statistics retrieved, total count: {}", count);
+
+            return CommonResponse.success(count);
+
+        } catch (Exception e) {
+            // 异常处理
+            log.error("Failed to get blacklist statistics", e);
+            return CommonResponse.create(-1, "获取统计信息失败,请稍后重试");
+        }
+    }
+}