【技术派后端篇】技术派中的白名单机制:基于Redis的Set实现

在技术派社区中,为了保证文章的质量和社区的良性发展,所有发布的文章都需要经过审核。然而,并非所有作者的文章都需要审核,我们通过白名单机制来优化这一流程。本文将详细介绍技术派中白名单的实现方式,以及如何利用Redis的Set数据结构来管理白名单。

1 为什么要审核?

虽然大部分作者发布的文章都是高质量的,但也有一些作者只是为了体验发文流程而发布测试内容。如果不经过审核直接上线,可能会导致社区文章质量的下降。因此,审核机制是保证社区文章质量的重要手段。

2 白名单的实现方案

在技术派中,我们为部分作者设置了白名单,这些作者发布的文章无需审核即可直接上线。白名单的实现有多种方案,我们选择了基于Redis的Set数据结构来实现。以下是几种可选的方案及其优缺点:

方案优点缺点适用场景
配置文件写死(硬编码方式)简单不灵活,每次改动需改代码发版,不适用于实际生产项目对配置变动需求极低的简单测试场景
数据库配置白名单表灵活,适用性强实现有点重生产环境中对配置灵活性要求高,且能接受一定实现复杂度的场景
基于redis的set实现白名单实现简单,轻量依赖redis对性能要求较高、且项目中已使用redis,对配置管理有一定灵活性需求的场景

3 技术派中的白名单实现策略

技术派中的白名单就是基于Redis的Set来实现的。以下是详细的实现策略:

3.1 Redis Set的基本操作

以下是Redis Set的一些基本操作命令:

  • 添加成员SADD key val1 val2
  • 获取集合成员数量SCARD key
  • 判断成员是否存在SISMEMBER key val,返回1表示存在,0表示不存在
  • 获取所有成员SMEMBERS key
  • 随机移除成员SPOP key
  • 随机返回成员SRANDMEMBER key count
  • 删除成员SREM key val

此外,Set还支持多个集合之间的操作,如求差集、交集、并集等。

  • 返回第一个集合与其他集合之间的差异sdiff key1 key2 key3...
  • 返回所有给定集合的差值,并存储在destinationsdiffstore destination key1 key2 key3...
  • 返回给定集合的交集sinter key1 key2
  • 返回给定集合的交集,并存储在destination集合中sinterstore destination key1 key2...
  • 返回所有给定集合的并集sunion key1 key2...
  • 返回所有给定集合的并集,并存储在destination集合中sunionstore destination key1 key2...

3.2 Spring项目中使用RedisTemplate操作Set

在Spring项目中,我们可以使用RedisTemplate来操作Redis的Set。以下是一些常用的操作示例:

  • 新增成员
public void add(String key, String value) {redisTemplate.opsForSet().add(key, value);
}
  • 删除成员
public void remove(String key, String value) {redisTemplate.opsForSet().remove(key, value);
}
  • 判断成员是否存在
public void contains(String key, String value) {redisTemplate.opsForSet().isMember(key, value);
}
  • 获取所有成员
public Set<String> values(String key) {return redisTemplate.opsForSet().members(key);
}
  • 集合运算
public Set<String> union(String key1, String key2) {return redisTemplate.opsForSet().union(key1, key2);
}public Set<String> intersect(String key1, String key2) {return redisTemplate.opsForSet().intersect(key1, key2);
}public Set<String> diff(String key1, String key2) {return redisTemplate.opsForSet().difference(key1, key2);
}

3.3 白名单的使用实例

在技术派中,白名单的相关业务逻辑封装在com.github.paicoding.forum.service.user.service.AuthorWhiteListService中。以下是一些核心方法:

  • 判断作者是否在白名单中boolean authorInArticleWhiteList(Long authorId);

  • 获取所有白名单用户List<BaseUserInfoDTO> queryAllArticleWhiteListAuthors();

  • 添加用户到白名单void addAuthor2ArticleWhitList(Long userId);

  • 从白名单中移除用户void removeAuthorFromArticelWhiteList(Long userId);

实现代码如下:

@Service
public class AuthorWhiteListServiceImpl implements AuthorWhiteListService {/*** 实用 redis - set 来存储允许直接发文章的白名单*/private static final String ARTICLE_WHITE_LIST = "auth_article_white_list";@Autowiredprivate UserService userService;@Overridepublic boolean authorInArticleWhiteList(Long authorId) {return RedisClient.sIsMember(ARTICLE_WHITE_LIST, authorId);}/*** 获取所有的白名单用户** @return*/@Overridepublic List<BaseUserInfoDTO> queryAllArticleWhiteListAuthors() {Set<Long> users = RedisClient.sGetAll(ARTICLE_WHITE_LIST, Long.class);if (CollectionUtils.isEmpty(users)) {return Collections.emptyList();}List<BaseUserInfoDTO> userInfos = userService.batchQueryBasicUserInfo(users);return userInfos;}@Overridepublic void addAuthor2ArticleWhitList(Long userId) {RedisClient.sPut(ARTICLE_WHITE_LIST, userId);}@Overridepublic void removeAuthorFromArticleWhiteList(Long userId) {RedisClient.sDel(ARTICLE_WHITE_LIST, userId);}
}

核心封装的几个公共方法,位于com.github.paicoding.forum.core.cache.RedisClient#sIsMember

/*** 判断value是否再set中** @param key* @param value* @return*/
public static <T> Boolean sIsMember(String key, T value) {return template.execute(new RedisCallback<Boolean>() {@Overridepublic Boolean doInRedis(RedisConnection connection) throws DataAccessException {return connection.sIsMember(keyBytes(key), valBytes(value));}});
}/*** 获取set中的所有内容** @param key* @param clz* @param <T>* @return*/
public static <T> Set<T> sGetAll(String key, Class<T> clz) {return template.execute(new RedisCallback<Set<T>>() {@Overridepublic Set<T> doInRedis(RedisConnection connection) throws DataAccessException {Set<byte[]> set = connection.sMembers(keyBytes(key));if (CollectionUtils.isEmpty(set)) {return Collections.emptySet();}return set.stream().map(s -> toObj(s, clz)).collect(Collectors.toSet());}});
}/*** 往set中添加内容** @param key* @param val* @param <T>* @return*/
public static <T> boolean sPut(String key, T val) {return template.execute(new RedisCallback<Long>() {@Overridepublic Long doInRedis(RedisConnection connection) throws DataAccessException {return connection.sAdd(keyBytes(key), valBytes(val));}}) > 0;
}/*** 移除set中的内容** @param key* @param val* @param <T>*/
public static <T> void sDel(String key, T val) {template.execute(new RedisCallback<Void>() {@Overridepublic Void doInRedis(RedisConnection connection) throws DataAccessException {connection.sRem(keyBytes(key), valBytes(val));return null;}});
}

3.4 白名单的应用场景

在文章发布的核心服务中,我们通过白名单机制来决定文章是否需要审核。代码位于com.github.paicoding.forum.service.article.service.impl.ArticleWriteServiceImpl,以下是一些关键代码片段:

  • 判断是否需要审核
private boolean needToReview(ArticleDO article) {BaseUserInfoDTO user = ReqInfoContext.getReqInfo().getUser();if (user.getRole() != null && user.getRole().equalsIgnoreCase(UserRole.ADMIN.name())) {return false;}return article.getStatus() == PushStatusEnum.ONLINE.getCode() && !articleWhiteListService.authorInArticleWhiteList(article.getUserId());
}
  • 发布文章
private Long insertArticle(ArticleDO article, String content, Set<Long> tags) {if (needToReview(article)) {article.setStatus(PushStatusEnum.REVIEW.getCode());}// 保存文章、内容和标签// ...
}
  • 更新文章
private Long updateArticle(ArticleDO article, String content, Set<Long> tags) {boolean review = article.getStatus().equals(PushStatusEnum.REVIEW.getCode());if (needToReview(article)) {article.setStatus(PushStatusEnum.REVIEW.getCode());}// 更新文章、内容和标签// ...
}

3.5 管理员操作白名单

管理员可以通过com.github.paicoding.forum.web.admin.rest.AuthorWhiteListController来管理白名单用户:

@RestController
@Api(value = "发布文章作者白名单管理控制器", tags = "作者白名单")
@Permission(role = UserRole.ADMIN)
@RequestMapping(path = {"api/admin/author/whitelist"})
public class AuthorWhiteListController {@Autowiredprivate AuthorWhiteListService articleWhiteListService;@GetMapping(path = "get")@ApiOperation(value = "白名单列表", notes = "返回作者白名单列表")public ResVo<List<BaseUserInfoDTO>> whiteList() {return ResVo.ok(articleWhiteListService.queryAllArticleWhiteListAuthors());}@GetMapping(path = "add")@ApiOperation(value = "添加白名单", notes = "将指定作者加入作者白名单列表")@ApiImplicitParam(name = "authorId", value = "传入需要添加白名单的作者UserId", required = true, allowEmptyValue = false, example = "1")public ResVo<Boolean> addAuthor(@RequestParam("authorId") Long authorId) {articleWhiteListService.addAuthor2ArticleWhitList(authorId);return ResVo.ok(true);}@GetMapping(path = "remove")@ApiOperation(value = "删除白名单", notes = "将作者从白名单列表")@ApiImplicitParam(name = "authorId", value = "传入需要删除白名单的作者UserId", required = true, allowEmptyValue = false, example = "1")public ResVo<Boolean> rmAuthor(@RequestParam("authorId") Long authorId) {articleWhiteListService.removeAuthorFromArticleWhiteList(authorId);return ResVo.ok(true);}
}

4 总结

本文介绍了技术派中白名单机制的实现,重点讲解了如何利用Redis的Set数据结构来管理白名单用户。通过白名单机制,我们能够有效减少不必要的审核流程,提升用户体验。同时,本文也展示了如何在Spring项目中使用RedisTemplate来操作Redis的Set,希望对大家有所帮助。

Redis的五种基本数据结构(String、List、Set、ZSet、Hash)是每个开发者都应该掌握的知识点。然而,仅仅了解这些数据结构是不够的,更重要的是能够结合实际场景来选择合适的数据结构,这样才能真正发挥Redis的优势。

5 思维导图

6 参考链接

  1. 技术派Redis实现作者白名单
  2. 项目仓库(GitHub)
  3. 项目仓库(码云)

7 附录:Redis 五种数据结构的应用场景

Redis 提供了五种基本数据结构:字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)。每种数据结构都有其独特的特性和适用场景。以下是每种数据结构的应用场景详解:

7.1 字符串(String)

应用场景:

  • 缓存数据:将经常访问的数据缓存在 Redis 中,以加快访问速度。例如,缓存用户信息、商品信息等。
  • 计数器:记录某个事件发生的次数,例如网站的访问次数、文章的点赞次数等。可以使用 INCRDECR 命令来实现。
  • 分布式锁:使用字符串的 SETNX 命令来实现分布式锁。SETNX 命令在键不存在时设置键值,可以用来实现互斥锁。

示例代码:

// 缓存数据
redisTemplate.opsForValue().set("user:1", "John Doe");
String user = redisTemplate.opsForValue().get("user:1");// 计数器
redisTemplate.opsForValue().increment("page:view:count");
Long viewCount = redisTemplate.opsForValue().get("page:view:count");// 分布式锁
Boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent("lock:key", "lockValue");
if (lockAcquired) {try {// 执行业务逻辑} finally {redisTemplate.delete("lock:key");}
}

7.2 哈希(Hash)

应用场景:

  • 存储对象属性:将对象的属性存储在哈希中,方便对属性进行读写操作。例如,存储用户信息、商品信息等。
  • 缓存对象:将对象序列化后存储在哈希中,以便快速获取和更新对象。
  • 记录用户信息:存储用户的详细信息,如用户名、年龄、性别等。

示例代码:

// 存储对象属性
redisTemplate.opsForHash().put("user:1", "name", "John Doe");
redisTemplate.opsForHash().put("user:1", "age", 30);
String name = (String) redisTemplate.opsForHash().get("user:1", "name");
Integer age = (Integer) redisTemplate.opsForHash().get("user:1", "age");// 缓存对象
User user = new User("John Doe", 30);
redisTemplate.opsForHash().putAll("user:1", new ObjectMapper().convertValue(user, Map.class));
User cachedUser = new ObjectMapper().convertValue(redisTemplate.opsForHash().entries("user:1"), User.class);

7.3 列表(List)

应用场景:

  • 消息队列:用于实现消息队列,将生产者产生的消息存储在列表中,消费者从列表中获取消息进行处理。
  • 最新动态:存储用户的最新动态或消息,如微博的用户动态、新闻网站的最新消息等。
  • 实时排行榜:用于存储用户的分数或权重,并根据分数进行排序,实现实时排行榜功能。

示例代码:

// 消息队列
redisTemplate.opsForList().rightPush("message:queue", "message1");
String message = redisTemplate.opsForList().leftPop("message:queue");// 最新动态
redisTemplate.opsForList().rightPush("user:1:timeline", "动态1");
List<String> timeline = redisTemplate.opsForList().range("user:1:timeline", 0, -1);// 实时排行榜
redisTemplate.opsForList().rightPush("leaderboard", "user:1");
redisTemplate.opsForList().rightPush("leaderboard", "user:2");
List<String> leaderboard = redisTemplate.opsForList().range("leaderboard", 0, -1);

7.4 集合(Set)

应用场景:

  • 好友关系:存储用户的好友关系,利用集合的交集、并集、差集等操作来实现好友关系的管理。
  • 标签管理:将对象关联的标签存储在集合中,方便进行标签的添加、删除和检索。
  • 唯一值集合:用于存储唯一值,如去重、统计等场景。

示例代码:

// 好友关系
redisTemplate.opsForSet().add("user:1:friends", "user:2", "user:3");
Set<String> friends = redisTemplate.opsForSet().members("user:1:friends");// 标签管理
redisTemplate.opsForSet().add("article:1:tags", "技术", "Redis");
Set<String> tags = redisTemplate.opsForSet().members("article:1:tags");// 唯一值集合
redisTemplate.opsForSet().add("unique:values", "value1", "value2");
Set<String> uniqueValues = redisTemplate.opsForSet().members("unique:values");

7.5 有序集合(Sorted Set)

应用场景:

  • 排行榜:存储用户的分数,并根据分数进行排序,实现排行榜功能。例如,游戏中的积分排行榜、电商网站的销量排行榜等。
  • 实时热门数据:存储数据的热度值,并根据热度值进行排序,用于实时热门数据的展示。例如,新闻网站的热门新闻、社交媒体的热门话题等。
  • 计划任务:存储定时任务的执行时间,并根据时间戳进行排序,用于实现计划任务的调度。

示例代码:

// 排行榜
redisTemplate.opsForZSet().add("leaderboard", "user:1", 100);
redisTemplate.opsForZSet().add("leaderboard", "user:2", 200);
Set<String> topUsers = redisTemplate.opsForZSet().range("leaderboard", 0, 9);// 实时热门数据
redisTemplate.opsForZSet().add("hot:news", "新闻1", 10);
redisTemplate.opsForZSet().add("hot:news", "新闻2", 20);
Set<String> hotNews = redisTemplate.opsForZSet().range("hot:news", 0, -1);// 计划任务
redisTemplate.opsForZSet().add("schedule:tasks", "task1", System.currentTimeMillis() + 60000);
Set<String> tasks = redisTemplate.opsForZSet().rangeByScore("schedule:tasks", 0, System.currentTimeMillis());

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/902057.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TRAE.AI 国际版本

国际版下载地址&#xff1a; https://www.trae.ai/https://www.trae.ai/ 国际版本优势&#xff1a;提供更多高校的AI助手模型 Claude-3.5-Sonnet Claude-3.7-Sonnet Gemini-2.5-Pro GPT-4.1 GPT-40 DeepSeek-V3-0324DeepSeek-V3DeepSeek-Reasoner(R1)

关于支付宝网页提示非官方网页

关于支付宝网站提示 非官方网站 需要找官方添加白名单 下面可以直接用自己的邮箱去发送申请 支付宝提示“非支付宝官方网页&#xff0c;请确认是否继续访问”通常是因为支付宝的安全机制检测到您访问的页面不是支付宝官方页面&#xff0c;这可能是由于域名或页面内容不符合支…

【今日三题】打怪(模拟) / 字符串分类(字符串哈希) / 城市群数量(dfs)

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;每日两三题 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 打怪(模拟)字符串分类(字符串哈希)城市群数量(dfs) 打怪(模拟) 打怪 #include <iostream> using namespace std;int …

npm install 版本过高引发错误,请添加 --legacy-peer-deps

起因&#xff1a;由于使用"react": "^19.0.0", 第三方包要低版本react&#xff0c;错解决方法&#xff01; npm install --save emoji-mart emoji-mart/data emoji-mart/react npm install --save emoji-mart emoji-mart/data emoji-mart/react npm err…

Python基础总结(七)之条件语句

文章目录 条件语句if一、Python中的真假二、条件语句格式2.1 if语句格式2.2 if-else语句2.3 if-elif-else语句 三、if语句嵌套 条件语句if 条件语句其实就是if语句&#xff0c;在讲解if语句之前需要知道Python中对于真假的判断。 一、Python中的真假 在Python中非0的都为真&…

基于Ubuntu2504部署OpenStack E版

OpenStack 初始化环境安装数据库、memcahe、rabbitmq等服务安装keystone服务安装glance服务安装placement服务安装nova服务安装neutron服务安装horizon服务 官网 OpenStack Epoxy 巩固了作为 VMware 替代方案的地位&#xff0c;增强了安全性&#xff0c;并改进了硬件支持 第 3…

可发1区的超级创新思路(python 、MATLAB实现):基于多尺度注意力TCN-KAN与小波变换的时间序列预测模型

一、数学模型与原理 1.1 小波变换多尺度分解 输入功率序列 x(t) 经小波变换分解为近似系数 Aj​ 与细节系数 Dj​: 1.2 多尺度TCN特征提取 对每个尺度子序列 {A3​,D3​,D2​,D1​} 采用独立TCN: 式中 ∗d​ 为扩张率 d=2l 的扩张卷积,Wd​ 为可学习参数。 1.3 多尺度注…

YOLOv11改进有效涨点专栏:从理论到实战的深度优化指南

## YOLOv11的进化之路 在目标检测领域,YOLO系列算法始终保持着革命性的创新步伐。YOLOv11作为该系列的最新演进版本,在保持实时检测优势的同时,通过架构层面的深度优化实现了精度与速度的平衡。本文将从**七大核心模块**出发,系统性地解析针对YOLOv11的有效改进方案,涵盖从…

Cursor新版0.49.x发布

小子看到 Cursor 0.49.x 版本正式发布&#xff0c;截止今天已经有两个小patch版本&#xff01;本次更新聚焦于 自动化Rules生成、改进的 Agent Terminal 以及 MCP 图像支持&#xff0c;并带来了一系列旨在提升编码效率和协作能力的改进与修复。 以下是本次更新的详细内容&…

《手环表带保养全攻略:材质、清洁与化学品避坑指南》

系列文章目录 文章目录 系列文章目录前言一、表带材质特性与专属养护方案二、清洁剂使用红黑榜三、家庭清洁实验&#xff1a;化学反应警示录四、保养实践方法论总结 前言 手环作为现代生活的智能伴侣&#xff0c;表带材质选择丰富多样。从柔软亲肤的皮质到耐用耐磨的金属&…

实现批量图片文字识别(python+flask+EasyOCR)

话不多说,向上效果图 1)先说框架版本 为什么要先说框架版本呢,因为我在各种版本中尝试了两天,总算确定了如下版本适合我,至于其他的版本,各位自己去尝试 python 3.9.7 EasyOCR 1.7.2 flask 3.0.3 2)执行操作效果图 2.1)多选文件 2.2)图片预览 2.3)提取选中文件 2.4)提取所有文…

国产GPU生态现状评估:从寒武纪到壁仞的编程适配挑战

近年来&#xff0c;国产GPU厂商在硬件性能上持续突破&#xff0c;但软件生态的构建仍面临严峻挑战。本文以寒武纪、壁仞等代表性企业为例&#xff0c;对比分析其与CUDA生态的兼容性差异&#xff0c;并探讨技术突围路径。 一、编程适配的核心挑战 ‌编程模型差异与开发成本‌ …

YOLOv8 Bug 及解决方案汇总 【2024.1.24更新】【环境安装】【训练 断点续训】OMPError / KeyError

YOLOv8 Bug 及解决方案汇总&#xff1a;深入解析与应对 引言 YOLOv8作为一款高性能的目标检测算法&#xff0c;在实际应用中难免会遇到各种各样的问题。本文将对YOLOv8常见的Bug进行汇总&#xff0c;并提供相应的解决方案&#xff0c;旨在帮助开发者更好地使用和优化YOLOv8。…

面试算法高频08-动态规划-02

动态规划练习题 题目描述 给定两个字符串 text1 和 text2&#xff0c;要求返回这两个字符串的最长公共子序列。例如对于字符串 “ABAZDC” 和 “BACBAD”&#xff0c;需找出它们最长的公共子序列。子序列是指在不改变其余字符相对位置的情况下&#xff0c;从原始字符串中删除…

【人工智能学习-01-01】20250419《数字图像处理》复习材料的word合并PDF,添加页码

前情提要 20250419今天是上师大继续教育人工智能专升本第一学期的第一次线下课。 三位老师把视频课的内容提炼重点再面授。&#xff08;我先看了一遍视频&#xff0c;但是算法和图像都看不懂&#xff0c;后来就直接挂分刷满时间&#xff0c;不看了&#xff09; 今天是面对面授…

AI写代码工具分享:Cursor 高效使用攻略与实战秘籍

写在前面 在软件开发领域,效率和生产力是永恒的追求。集成开发环境(IDE)作为开发者的核心工具,其能力直接影响着开发速度和质量。近年来,人工智能(AI)的浪潮席卷了各个行业,编程领域也不例外。Cursor IDE 正是这股浪潮中的佼佼者,它以 AI-First 的理念,在广受欢迎的…

守护进程编程

守护进程编程 守护进程的含义 定义 守护进程&#xff08;Daemon Process&#xff09;是在后台运行的进程&#xff0c;它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程&#xff0c;它在系统后台运行&#xff0c;为系统或其他…

在复杂性的迷宫里寻找路标 —— 读《人月神话》有感

初读《人月神话》时&#xff0c;正值参与的第一个大型项目陷入泥潭&#xff1a;需求像不断膨胀的气球&#xff0c;团队规模从 10 人扩充到 30 人&#xff0c;进度却像被灌了铅的钟表&#xff0c;指针越来越沉重。布鲁克斯在书中写下的 "向进度落后的项目增加人力&#xff…

SpringCloud Alibaba微服务工程搭建

前言 在讲微服务工程的搭建之前&#xff0c;我们先分析下为什么要使用微服务呢&#xff1f; 1、单体应用的痛点 维护困难&#xff1a;代码臃肿&#xff0c;牵一发而动全身。扩展性差&#xff1a;无法按需扩展特定功能&#xff0c;只能整体扩容。技术栈僵化&#xff1a;难以引…

flutter json解析增强

依赖:xxf_json 反序列化兼容特征一览表 类型\是否兼容 int double num string bool int yes yes yes yes yes double yes yes yes yes yes num yes yes yes yes yes string yes yes yes yes yes bool yes yes yes yes yes 专业词语 .g…