技术派Redis实现作者白名单

通过技术派发文章的时候,发文章会先通过审核,只有通过审核在会在网站上进行展示。是不是所有的作者都要经过审核呢?

当然不是,在这里做了一个白名单,在白名单中的用户发文之后是不需要进入审核的,可以直接上线。

问题的产生的疑问?

为什么要进行审核?

如后台文章列表

文章参差不齐,有的值得点赞、收藏,有的可能有违规的内容,还有的文章不符合网站的主题要求等,若不经过审核直接上线,会导致网站的文章质量下滑。作为一个交流的学习型的网站社区,审核是必不可少的。

白名单如何实现的?

对作者添加白名单有很多可选方案

配置文件写死(相当于硬编码方式)

  • 优点:简单
  • 缺点:不灵活,每次改动都需要改代码发版,基本上不适用实际生产项目

数据库配置一个白名单

  • 优点:灵活,实用性强
  • 缺点:实现有点重、难

基于redis的set实现白名单

  • 优点:实现简单,轻量
  • 缺点:依赖于redis

本项目的白名单就是基于redis的set来实现的,下面来看一下详细实现策略。

redis实现白名单

对于使用redis来实现白名单,最容易想到的数据结构就是set。

set基本知识点

首先熟悉一下redis中的set的相关命令操作

添加

#向集合中添加多个成员

sadd key val1 val2

集合数量

scard key

判断集合是否包含元素val

sismember key val

返回1表示在里面  0表示不再里面

返回集合所有成员


smembers key

随机移除集合中的一个元素

spop key

随机返回集合中的几个元素

srandmember key count

删除集合中成员

srem key val

简单演示一下

集合除上述基本操作之外,还支持多集合之间的相互操作

差集

返回第一个集合以其他集合之间的差异

sdiff key1 key2 key3

返回所有给定集合的差值,并存储在destination

sdiffstore destination key1 key2 key3...

返回给定集合的交集

sinter key1 key2

返回给定集合的交集,并把它存储在destination集合中

sinterstore destination key1 key2...

返回所有给定集合的并集

sunion key1 key2

返回所有给定集合的并集,并将其存储在destination集合中

sunionstore destination key1 key2...

演示一下

RedisTemplate操作知识点

Spring项目中,借助RedisTemplate操作set也很简单

新增

/**
新增一个 sadd

*/
public void add(String key , String value){

redisTemplate.opsForSet().add(key ,value);
}

删除

  /**
     * 删除集合中的值  srem
     * @param key
     * @param value
     */
    public  void  remove(String key , String value){

        redisTemplate.opsForSet().remove(key ,value);
    }

判断是否存在

    /**
     * 判断是否包含 sismember
     * @param key
     * @param value
     */
    public  void  contains(String key , String value){

        redisTemplate.opsForSet().isMember(key ,value);
    }

获取所有的value、

    /**
     * 获取集合中所有的值 smembers
     * @param key
     * @return
     */
    public Set<String> values(String key){

        return redisTemplate.opsForSet().members(key);
    }

集合运算

    /**
     * 返回多个集合的并集
     * @param key1
     * @param key2
     * @return
     */
    public  Set<String> union(String key1 ,String key2){
        return redisTemplate.opsForSet().union(key1 ,key2);
    }


    /**
     * 返回多个集合的交集 sinter
     * @param key1
     * @param key2
     * @return
     */
    public  Set<String> intersect(String key1 ,String key2){
        return redisTemplate.opsForSet().intersect(key1 ,key2);
    }

    /**
     * 返回在key1 中而不在key2中的集合 sdiff
     * @param key1
     * @param key2
     * @return
     */
    public  Set<String> difference(String key1 ,String key2){
        return redisTemplate.opsForSet().difference(key1 ,key2);
    }

白名单使用实例

白名单的相关业务封装在ArticleWhileListService中


    /**
     * 判断作者是否再文章发布的白名单中;
     * 这个白名单主要是用于控制作者发文章之后是否需要进行审核
     *
     * @param authorId
     * @return
     */
    boolean authorInArticleWhiteList(Long authorId);

    /**
     * 获取所有的白名单用户
     *
     * @return
     */
    List<BaseUserInfoDTO> queryAllArticleWhiteListAuthors();

    /**
     * 将用户添加到白名单中
     *
     * @param userId
     */
    void addAuthor2ArticleWhitList(Long userId);

    /**
     * 从白名单中移除用户
     *
     * @param userId
     */
    void removeAuthorFromArticleWhiteList(Long userId);

核心主要使用就是第一个,判断作者是否是白名单用户;剩下的三个用于管理员后台维护白名单使用,具体实现如下

    /**
     * 实用 redis - set 来存储允许直接发文章的白名单
     */
    private static final String ARTICLE_WHITE_LIST = "auth_article_white_list";

    @Autowired
    private UserService userService;

    @Override
    public boolean authorInArticleWhiteList(Long authorId) {
        return RedisClient.sIsMember(ARTICLE_WHITE_LIST, authorId);
    }

对于set的操作我们进行了统一的封装,与上面介绍到的知识点差不多,不过这里选择另外一种实现策略。

核心的封装的几个公共方法。

 /**
     * 判断value是否再set中
     *
     * @param key
     * @param value
     * @return
     */
    public static <T> Boolean sIsMember(String key, T value) {
        return template.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.sIsMember(keyBytes(key), valBytes(value));
            }
        });
    }



    
该方法接受两个参数:key表示Redis集合的键名,value表示要判断的值。它使用了一个泛型类型T来表示值的类型,以便可以处理不同类型的值。

方法内部使用了template.execute方法来执行一个RedisCallback匿名内部类的实例。这个回调类实现了doInRedis方法,该方法接受一个RedisConnection对象作为参数,并调用其sIsMember方法来判断值是否存在于Redis集合中。

keyBytes(key)和valBytes(value)是两个辅助方法,用于将键名和值转换为字节数组表示形式,以便与Redis进行通信。

最后,如果值存在于集合中,则返回true,否则返回false。

    /**
     * 获取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>>() {
            @Override
            public 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());
            }
        });
    }




    
该方法接受两个参数:key表示Redis集合的键名,clz表示要转换的目标类型。它使用了一个泛型类型T来表示目标类型,以便可以处理不同类型的值。

方法内部使用了template.execute方法来执行一个RedisCallback匿名内部类的实例。这个回调类实现了doInRedis方法,该方法接受一个RedisConnection对象作为参数,并调用其sMembers方法来获取集合中的所有元素。

keyBytes(key)是一个辅助方法,用于将键名转换为字节数组表示形式,以便与Redis进行通信。

如果集合为空,则返回一个空的Set对象;否则,将集合中的每个元素转换为目标类型,并收集到一个新的Set对象中。最后,返回包含集合所有元素的Set对象。

    /**
     * 往set中添加内容
     *
     * @param key
     * @param val
     * @param <T>
     * @return
     */
    public static <T> boolean sPut(String key, T val) {
        return template.execute(new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.sAdd(keyBytes(key), valBytes(val));
            }
        }) > 0;
    }


该方法接受两个参数:key表示Redis集合的键名,val表示要添加的值。它使用了一个泛型类型T来表示值的类型,以便可以处理不同类型的值。

方法内部使用了template.execute方法来执行一个RedisCallback匿名内部类的实例。这个回调类实现了doInRedis方法,该方法接受一个RedisConnection对象作为参数,并调用其sAdd方法将值添加到集合中。

keyBytes(key)和valBytes(val)是两个辅助方法,用于将键名和值转换为字节数组表示形式,以便与Redis进行通信。

最后,根据sAdd方法的返回值判断是否成功添加了值。如果返回值大于0,则表示成功添加,返回true;否则返回false。

    /**
     * 移除set中的内容
     *
     * @param key
     * @param val
     * @param <T>
     */
    public static <T> void sDel(String key, T val) {
        template.execute(new RedisCallback<Void>() {
            @Override
            public Void doInRedis(RedisConnection connection) throws DataAccessException {
                connection.sRem(keyBytes(key), valBytes(val));
                return null;
            }
        });
    }

下面我们再看一下具体的使用场景。

对于非白名单的用户,若操作的是上线的文章,则需要进入审核

发布文章

以上是使用白名单的场景,当然对于管理员来说,还有操作白名单的入口,统一收拢在

AuthorWhiteListController

小结

核心思考就是基于白名单场景,使用redis中的set具体使用。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

终于找到你!数字化时代的秘密武器

在数字化时代&#xff0c;纸张依旧扮演着重要的角色&#xff0c;无论是平板的电子笔记背景纸张&#xff0c;还是纸质纸张&#xff0c;亦或者你想要一个美观的纸张背景图。一张合适的纸张能大大提升我们的工作和学习效率。今天&#xff0c;我们将探索三款网站&#xff0c;它们可…

libreoffice免费的office软件

https://mirrors.ustc.edu.cn/tdf/libreoffice/stable/24.2.1/win/x86_64/LibreOffice_24.2.1_Win_x86-64.msi

Jetson Xavier NX 开发板Ubuntu18.04 安装arduino IDE详细步骤

Jetson 平台是arch架构&#xff0c;官网上面几乎都是x86或者arm64的这两种错误版本都存在匹配问题无法使用&#xff0c;不要下载不要下载&#xff01; uname -a #版本查询1.正确下载打开方式 https://downloads.arduino.cc/arduino-1.8.19-linuxaarch64.tar.xz选择自己想要下…

Codeforces Round 930 (Div. 2)

substr时间复杂度O&#xff08;N&#xff09;&#xff0c;不能一遍遍找&#xff0c;会超时 #include<iostream> #include<algorithm> #include<vector> #include<map> using namespace std; const int N5e510; map<string,int>mp; vector<…

Vision Pro开发者学习路线

官方给到的Vision Pro开发者学习路线&#xff1a; 1. 学习基础知识&#xff1a; - 学习 Xcode、Swift 和 SwiftUI 的基础知识&#xff0c;包括语法、UI 设计等。 - 掌握 ARKit 和 SwiftUI 的使用&#xff0c;了解如何创建沉浸式增强现实体验。 2. 学习 3D 建模&#xf…

基于springboot+vue的网上服装商城

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

leetcode 热题 100_接雨水

题解一&#xff1a; 按列求&#xff1a;分别考虑每一列的雨水高度&#xff0c;某列的雨水高度只与其左侧最高墙和右侧最高墙有关&#xff0c;一种情况是该列比左右侧的墙都低&#xff0c;则根据木桶效应该列雨水高度为min(左侧墙高&#xff0c;右侧墙高)-列高&#xff0c;而其余…

Maven 学习与IDEA配置

(一) Maven 概述 [1]. 简介 Apache Maven 是一个项目管理和构建工具&#xff0c;它基于项目对象模型(POM)的概念&#xff0c;通过一小段描述信息来管理项目的构建、报告和文档 官网&#xff1a;http://maven.apache.org/ Maven是专门用于管理和构建Java项目的工具&#xff0…

算法43:动态规划专练(最长回文子串 力扣5题)---范围模型

之前写过一篇最长回文子序列的博客算法27&#xff1a;最长回文子序列长度&#xff08;力扣516题&#xff09;——样本模型 范围模型-CSDN博客 在那一篇博客中&#xff0c;回文是可以删除某些字符串组成的。比如&#xff1a; 字符串为&#xff1a;a1b3c4fdcdba&#xff0c; 那…

Typora旧版链接(Win+Mac+Linux版)

记得点赞本文&#xff01;&#xff01;&#xff01; 链接&#xff1a;https://pan.baidu.com/s/1IckUvQUBzQkfHNHXla0zkA?pwd8888 提取码&#xff1a;8888 –来自百度网盘超级会员V7的分享

JavaWeb—— SpringBootWeb综合案例(登录功能、登录校验、异常处理)

案例-登录认证 目录 案例-登录认证1. 登录功能1.1 需求1.2 接口文档1.3 思路分析1.4 功能开发1.5 测试 2. 登录校验2.1 问题分析2.2 会话技术2.2.1 会话技术介绍2.2.2 会话跟踪方案2.2.2.1 方案一 - Cookie2.2.2.2 方案二 - Session2.2.2.3 方案三 - 令牌技术 2.3 JWT令牌2.3.1…

JS 对象数组排序方法测试

输出 一.Array.prototype.sort() 1.默认排序 sort() sort() 方法就地对数组的元素进行排序&#xff0c;并返回对相同数组的引用。默认排序是将元素转换为字符串&#xff0c;然后按照它们的 UTF-16 码元值升序排序。 由于它取决于具体实现&#xff0c;因此无法保证排序的时…

Zookeeper基础入门-1【集群搭建】

Zookeeper基础入门-1【集群搭建】 一、Zookeeper 入门1.1.概述1.2.Zookeeper工作机制1.3.Zookeeper特点1.4.数据结构1.5.应用场景1.5.1.统一命名服务1.5.2.统一配置管理1.5.3.统一集群管理1.5.4.服务器动态上下线1.5.5.软负载均衡 1.6.Zookeeper官网1.6.1.Zookeeper下载1.6.2.历…

软考56-上午题-【数据库】-数据库设计步骤2

一、回顾&#xff1a;数据库设计的步骤 1、用户需求分析&#xff1a;手机用户需求&#xff0c;确定系统边界&#xff1b; 2、概念设计&#xff08;概念结构设计&#xff09;&#xff1a;是抽象概念模型&#xff0c;较理想的是采用E-R方法。 3、逻辑设计&#xff1a;E-R图——…

带你了解 JavaScript 中的对象

带你了解 JavaScript 中的对象 基本概念 对象指的就是一个具体的事物&#xff0c;在JavaScript中, 字符串, 数值, 数组, 函数都是对象 每个对象中包含若干的属性和方法 属性: 事物的特征 方法: 事物的行为 1.使用字面量创建对象 使用{ }创建对象 属性和方法使用键值对的形式…

linux高级编程:线程(二)、进程间的通信方式

线程&#xff1a; 回顾线程&#xff08;一&#xff09;&#xff1a; 1.线程间通信问题 线程间共享同一个资源&#xff08;临界资源&#xff09; 互斥&#xff1a; 排他性访问 linux系统 -- 提供了Posix标准的函数库 -- 互斥量&#xff08;互斥锁&#xff09; 原子操作&#x…

1.1 简述卷积的基本操作,卷积和全连接层的区别?

1.1 简述卷积的基本操作&#xff0c;卷积和全连接层的区别&#xff1f; 摘要&#xff1a; 全连接层的输出层每个节点与输入层的所有节点连接。 卷积层具有局部连接和权值共享的特性。 问题&#xff1a;简述卷积的基本操作&#xff0c;并分析其与全连接层的区别。 分析与解答&a…

【计算机网络】深度学习HTTPS协议

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录文章&#xff1a;【计算机网络】深度学习HTTPS协议 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 一:HTTPS是什么二:HTTPS的工作过程三:对称加密四:非对称加密五:中间人攻击1…

JAVA内存模型与JVM内存结构

注意区分Java内存模型&#xff08;Java Memory Model&#xff0c;简称JMM&#xff09;与Jvm内存结构&#xff0c;前者与多线程相关&#xff0c;后者与JVM内部存储相关。本文会对两者进行简单介绍。 一、JAVA内存模型(JMM) 1. 概念 说来话长&#xff0c;由于在不同硬件厂商和…

详解动态规划(算法村第十九关青铜挑战)

不同路径 62. 不同路径 - 力扣&#xff08;LeetCode&#xff09; 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finis…