Redis的BitMap实现分布式布隆过滤器

news2025/1/15 6:27:42

布隆过滤器(Bloom Filter)是一种高效的概率型数据结构,用于判断一个元素是否属于一个集合。它通过使用哈希函数和位数组来存储和查询数据,具有较快的插入和查询速度,并且占用空间相对较少。

引入依赖

<!--切面-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
 <!-- 数据库-->
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>${mysql.version}</version>
</dependency>
<dependency>
   <groupId>com.baomidou</groupId>
   <artifactId>mybatis-plus-boot-starter</artifactId>
   <version>3.5.1</version>
</dependency>

properties配置

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/itcast?serverTimezone=GMT%2B8&useUnicode=true&logger=Slf4JLogger&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=root123
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.pool-name=HikariCPDatasource
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.idle-timeout=180000
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.connection-test-query=SELECT 1
mybatis-plus.configuration.log-impl= org.apache.ibatis.logging.stdout.StdOutImpl
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.timeout=10s
spring.redis.password=123

自定义注解


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 此注解可作用于控制器方法,或者服务类方法
 *
 * 使用示例,在目标方法上添加如下注解
 * <pre>
 *     BitMap(key = "user", id = "#id")
 * </pre>
 **/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface BitMap {
    /**
     * <p>同一类集合的唯一标识符 商品表、订单表分别设置不同key</p>
     */
    String key();

    /**
     * 支持{@code SPEL}表达式
     * 含义是以被调用方法参数<code>id</code>的值作为主键ID
     */
    String id() default "#id";
}

切面

import com.example.demo.annotation.BitMap;
import com.example.demo.util.ParserUtils;
import com.example.demo.util.RedisBitMapUtils;
import com.example.demo.util.ResponseResult;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.TreeMap;

/**
 * Redis BitMap AOP
 **/
@Aspect
@Component
public class BitMapAspect {
    private static final Logger logger = LoggerFactory.getLogger(BitMapAspect.class);

    @Resource
    private RedisBitMapUtils redisBitMapUtils;

    @Pointcut("@annotation(com.example.demo.annotation.BitMap)")
    public void aspect() {

    }

    @Around("aspect()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        // 通过 point 对象获取方法签名信息。
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 通过方法签名获取当前方法对象。
        Method method = signature.getMethod();
        // 获取当前方法上的 BitMap 注解。
        BitMap annotation = method.getAnnotation(BitMap.class);
        // 获取方法参数名和参数值的映射关系,并将结果保存到TreeMap中。
        TreeMap<String, Object> map = ParserUtils.createTreeMap(point, signature);
        // 从参数映射中获取 id 参数对应的值。
        String idString = ParserUtils.parse(annotation.id(), map);
        if (idString != null) {
            long id = Long.parseLong(idString);

            if (redisBitMapUtils.isPresent(annotation.key(), id)) {
                return point.proceed();
            } else {
                logger.info(String.format("当前主键ID{%d}不存在", id));
                return method.getReturnType().equals(ResponseResult.class) ? ResponseResult.okResult() : null;
            }
        }
        throw new RuntimeException("主键ID解析不正确,请按照参考格式书写");
    }

}

RedisBitMap工具类

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * {@link RedisBitMapUtils}工具类
 */
@Component
public class RedisBitMapUtils {
    private static final Logger logger = LoggerFactory.getLogger(RedisBitMapUtils.class);
    @Resource
    private   StringRedisTemplate stringRedisTemplate ;
    ValueOperations<String, String> opsForValue;

    @PostConstruct
    public  void init() {
        opsForValue= stringRedisTemplate.opsForValue();
    }


    /**
     * 该方法可以方便地将一个集合中的每个元素根据给定的映射函数进行转换,
     * 并返回一个新的列表。如果集合为空或为null,则返回一个空列表。
     * @param list
     * @param action
     * @return
     * @param <T>
     * @param <R>
     */
    public  <T, R> List<R> toList(final Collection<T> list, final Function<? super T, ? extends R> action) {
        Objects.requireNonNull(action);
        if (Objects.nonNull(list)) {
            return list.stream().map(action).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }
    /**
     * <p>本方法在首次初始化以{@code key}为参数的BitMap时执行</p>
     * <p>首先删除Key 然后重新构建BitMap</p>
     *
     * @param <T> 主键类型
     * @param key 每种业务分别对应不同的Key名称
     * @param ids 主键ID
     */
    public  <T extends Serializable> void init(String key, Collection<T> ids) {
        remove(key);
        setBit(key, ids);
    }

    /**
     * <p>本方法在首次初始化以{@code key}为参数的BitMap时执行</p>
     * <p>首先删除Key 然后重新构建BitMap</p>
     *
     * @param key    每种业务分别对应不同的Key名称
     * @param list   实体类对象集合
     * @param action 主键列(方法引用表示)
     * @param <T>    实体类泛型
     * @param <R>    主键列泛型
     */
    public  <T, R extends Serializable> void init(String key, Collection<T> list, Function<T, R> action) {
        List<R> ids = toList(list, action);
        init(key, ids);
    }

    /**
     * 检查当前主键ID在Redis BitMap中是否存在 如果存在则执行函数式回调
     *
     * @param key 每种业务分别对应不同的Key名称
     * @param id  主键ID
     * @return {@code R}实例
     */
    public  <T extends Serializable, R> R ifPresent(String key, T id, Function<T, R> action) {
        if (getBit(key, id)) {
            return action.apply(id);
        }
        return null;
    }

    /**
     * 检查当前主键ID在Redis BitMap中是否存在 如果存在则执行函数式回调
     *
     * @param key 每种业务分别对应不同的Key名称
     * @param id  主键ID
     * @return {@code R}实例
     */
    public  <T extends Serializable, R> R ifPresent(String key, T id, Supplier<R> supplier) {
        if (getBit(key, id)) {
            return supplier.get();
        }
        return null;
    }

    /**
     * 检查当前主键ID在Redis BitMap中是否存在 如果存在则返回<code>true</code>
     *
     * @param key 每种业务分别对应不同的Key名称
     * @param id  主键ID
     * @return 如果存在则返回<code>true</code>
     */
    public  <T extends Serializable> boolean isPresent(String key, T id) {
        return getBit(key, id);
    }

    /**
     * 检查当前主键ID在Redis BitMap中是否存在 如果存在则返回<code>true</code>
     * 本方法是{@link RedisBitMapUtils#getBit(String, Serializable)}的别名方法 方便对外调用
     *
     * @param key 每种业务分别对应不同的Key名称
     * @param id  主键ID
     * @return 如果存在则返回<code>true</code>
     */
    public  <T extends Serializable> boolean checkId(String key, T id) {
        return getBit(key, id);
    }


    /**
     * 检查当前主键ID(集合)在Redis BitMap中是否存在 只返回存在的主键ID
     * 本方法是{@link RedisBitMapUtils#getBit(String, Serializable)}的别名方法 方便对外调用
     *
     * @param key 每种业务分别对应不同的Key名称
     * @param ids 主键ID
     * @return 返回存在的主键ID
     */
    public  <T extends Serializable> List<T> checkIds(String key, Collection<T> ids) {
        return ids.stream().filter(e -> checkId(key, e)).collect(Collectors.toList());
    }

    /**
     * 向Redis BitMap中保存主键ID
     *
     * @param key 每种业务分别对应不同的Key名称
     * @param id  主键ID
     */
    public  <T extends Serializable> void setBit(String key, T id) {
        ifOffsetValid(Objects.hash(id), e -> opsForValue.setBit(key, e, true));
    }

    /**
     * 向Redis BitMap中批量保存主键ID
     *
     * @param <T> 主键类型
     * @param key 每种业务分别对应不同的Key名称
     * @param ids 主键ID
     */
    public  <T extends Serializable> void setBit(String key, Collection<T> ids) {
        ids.forEach(id -> ifOffsetValid(Objects.hash(id), e -> opsForValue.setBit(key, e, true)));
    }

    /**
     * 检查当前主键ID在Redis BitMap中是否存在 如果存在则返回<code>true</code>
     *
     * @param key 每种业务分别对应不同的Key名称
     * @param id  主键ID
     * @return 如果存在则返回<code>true</code>
     */
    public  <T extends Serializable> boolean getBit(String key, T id) {
        return ifOffsetValid(Objects.hash(id), e -> opsForValue.getBit(key, e));
    }


    /**
     * 从Redis BitMap中删除当前主键ID
     *
     * @param key 每种业务分别对应不同的Key名称
     * @param id  主键ID
     */
    public  <T extends Serializable> void removeBit(String key, T id) {
        ifOffsetValid(Objects.hash(id), e -> opsForValue.setBit(key, e, false));
    }

    /**
     * 从Redis BitMap中批量删除主键ID
     *
     * @param key 每种业务分别对应不同的Key名称
     * @param ids 主键ID
     * @param <T> 主键类型
     */
    public  <T extends Serializable> void removeBit(String key, Collection<T> ids) {
        ids.forEach(id -> ifOffsetValid(Objects.hash(id), e -> opsForValue.setBit(key, e, false)));
    }


    /**
     * 将当前分类下的BitMap Key删除
     * 清空该Key下所有数据
     */
    public  void remove(String key) {
        stringRedisTemplate.delete(key);

    }

    /**
     * <p>检查偏移量是否合法</p>
     * <p>Redis字符串支持字符串最大长度512M,因此支持offset的最大值为(2^32)-1</p>
     *
     * @param offset 偏移量
     * @param action 映射规则
     */
    private static <N extends Number> Boolean ifOffsetValid(N offset, Function<N, Boolean> action) {
        Objects.requireNonNull(action);

        //如果ID用整型表示 那么正整数范围内所有的ID均有效 最大正整数值为2147483647 约为20亿
        long max = (1L << 32) - 1;
        if (offset.intValue() >= 0 && offset.intValue() < Integer.MAX_VALUE) {
            return action.apply(offset);
        } else {
            // 如果偏移量类型为长整型,或者整型范围内的最大值小于0且 offset 的值小于等于 max
            if (Integer.MAX_VALUE >= 0 && offset.longValue() <= max) {
                return action.apply(offset);
            } else {
                logger.info(String.format("偏移量{%d}越界[0,%s],本次操作不成功!", offset.longValue(), max));
                return false;
            }
        }

    }
}

response工具类


import lombok.Data;

import java.io.Serializable;
@Data
public class ResponseResult<T> implements Serializable {
    private Boolean success;
    private Integer code;
    private String msg;
    private T data;

    public ResponseResult() {
        this.success=true;
        this.code = HttpCodeEnum.SUCCESS.getCode();
        this.msg = HttpCodeEnum.SUCCESS.getMsg();
    }

    public ResponseResult(Integer code, T data) {
        this.code = code;
        this.data = data;
    }

    public ResponseResult(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public ResponseResult(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public static ResponseResult errorResult(int code, String msg) {
        ResponseResult result = new ResponseResult();
        return result.error(code, msg);
    }

    public static ResponseResult okResult() {
        ResponseResult result = new ResponseResult();
        return result;
    }

    public static ResponseResult okResult(int code, String msg) {
        ResponseResult result = new ResponseResult();
        return result.ok(code, null, msg);
    }




    public static ResponseResult setHttpCodeEnum(HttpCodeEnum enums) {
        return okResult(enums.getCode(), enums.getMsg());
    }

    public static <T> ResponseResult<T> error(String message) {
        return new ResponseResult<T>(HttpCodeEnum.SYSTEM_ERROR.getCode(),  message);
    }

    public ResponseResult<?> error(Integer code, String msg) {
        this.success=false;
        this.code = code;
        this.msg = msg;
        return this;
    }

    public ResponseResult<?> ok(Integer code, T data) {
        this.success=true;
        this.code = code;
        this.data = data;
        return this;
    }

    public ResponseResult<?> ok(Integer code, T data, String msg) {
        this.success=true;
        this.code = code;
        this.data = data;
        this.msg = msg;
        return this;
    }

    public static ResponseResult ok(Object data) {
        ResponseResult result = new ResponseResult();
        result.setData(data);
        return result;
    }


}

controller


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.annotation.BitMap;
import com.example.demo.annotation.PreventRepeatSubmit;
import com.example.demo.mapper.StuMapper;
import com.example.demo.model.ResponseResult;
import com.example.demo.model.Student;
import com.example.demo.util.RedisBitMapUtils;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@RestController
@RequestMapping("/test")
@Validated
public class TestController {

    @Resource
    private StuMapper stuMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private static final String BITMAP_STU="bitmap_stu";

    @Resource
    private RedisBitMapUtils redisBitMapUtils;


    @GetMapping("init")
    public com.example.demo.util.ResponseResult init(){
        List<Student> studentList = stuMapper.selectList(new QueryWrapper<Student>());

        redisBitMapUtils.init(BITMAP_STU,studentList,Student::getId);
        return com.example.demo.util.ResponseResult.okResult();
    }
    /**
     * 编程式
     */
    @GetMapping("selectStu1/{id}")
    @BitMap(key = BITMAP_STU,id = "#id")
    public com.example.demo.util.ResponseResult selectStu1(@PathVariable Integer id){

        return com.example.demo.util.ResponseResult.ok(stuMapper.selectById(id));
    }
     /**
     * 注解式
     */
    @GetMapping("selectStu2/{id}")
    public com.example.demo.util.ResponseResult selectStu2(@PathVariable Integer id){
        if (redisBitMapUtils.getBit(BITMAP_STU,id)){
            return com.example.demo.util.ResponseResult.ok(stuMapper.selectById(id));
        }
        return com.example.demo.util.ResponseResult.okResult();
    }


}

测试

初始化biemap数据,从数据库种获取所有id并导入redis的key为bitmap_stu的数据

测试数据库存在的数据id:1,走数据库获取数据 

测试数据库的数据id:200,因为id为200不存在在数据库中,所以没有走数据库,减少了数据库压力 

 注解式也生效

达到了使用redis的bitmap实现分布式的布隆过滤器,过滤掉bitmap不存在的数据 

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

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

相关文章

Spring Cloud 之 Feign 简介及简单DEMO的搭建

Feign简介&#xff1a; Feign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用Feign, 我们可以做到使用HTTP请求远程服务时能与调用本地方法一样的编码体验。 Feign是在RestTemplate基础上封装的&#xff0c;使用注解的方式来声明一组与服务提供者Rest接口所对应的本地…

黑豹程序员-架构师学习路线图-百科:Maven

文章目录 1、什么是maven官网下载地址 2、发展历史3、Maven的伟大发明 1、什么是maven Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project’s build, reporting and…

微信小程序3

一、flex布局 布局的传统解决方案&#xff0c;基于[盒状模型]&#xff0c;依赖display属性 position属性 float属性 1、什么是flex布局&#xff1f; Flex是Flexible Box的缩写&#xff0c;意为”弹性布局”&#xff0c;用来为盒状模型提供最大的灵活性。 任何一个容器都可以…

同为科技(TOWE)工业用插头插座与连接器产品大全

TOWE IPS系列工业标准插头插座、连接器系列产品 随着国内经济快速的发展&#xff0c;人们生活水平的不断提高&#xff0c;基础设施的建设是发展的基础&#xff0c;完善的基础设施对加速经济的发展起到至关重要的作用。其中&#xff0c;基础建设中机场、港口、电力、通讯等公共…

GLEIF携手TrustAsia,共促数字邮件证书的信任与透明度升级

TrustAsia首次发布嵌入LEI的S/MIME证书&#xff0c;用于验证法定实体相关的电子邮件账户的真实与完整性 2023年10月&#xff0c;全球法人识别编码基金会&#xff08;GLEIF&#xff09;与证书颁发机构&#xff08;CA&#xff09;TrustAsia通力合作&#xff0c;双方就促进LEI在数…

基础课5——语音合成技术

TTS是语音合成技术的简称&#xff0c;也称为文语转换或语音到文本。它是指将文本转换为语音信号&#xff0c;并通过语音合成器生成可听的语音。TTS技术可以用于多种应用&#xff0c;例如智能语音助手、语音邮件、语音新闻、有声读物等。 TTS技术通常包括以下步骤&#xff1a; …

医学大数据分析 - 心血管疾病分析 计算机竞赛

文章目录 1 前言1 课题背景2 数据处理3 数据可视化4 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据的心血管疾病分析 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9…

什么牌子的电容笔性价比高?电容笔牌子排行

在科技进步的同时&#xff0c;各种类型的电容笔也在国内的市场上涌现。一支好用的电容笔&#xff0c;不仅能让我们在学习上有很大的提高&#xff0c;而且还能让我们的工作效率大大提高。国产平替电容笔&#xff0c;在技术和品质上&#xff0c;都有很大的改进余地&#xff0c;起…

如何才能拥有大量的虾皮印尼买家号?

注册虾皮印尼买家号还是比较简单的&#xff0c;直接打开shopee印尼官网&#xff0c;点击注册&#xff0c;输入手机号&#xff0c;接收短信&#xff0c;然后再设置一个密码就可以了。 如果想要注册多个虾皮买家号&#xff0c;那么要借助软件操作才可以&#xff0c;比如shopee买家…

本地项目打jar包依赖并上传到maven仓库

一、 打jar包依赖 先去掉启动类pom中添加如下的maven打包插件 <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.0</version><c…

RN:报错info Opening flipper://null/React?device=React%20Native

背景 在 ios 上使用 debug 模式的时候&#xff0c;报错&#xff1a;info Opening flipper://null/React?deviceReact%20Native&#xff0c;我找到了这个 issue 其实也可以看到现在打开 debug&#xff0c;是 open debug&#xff0c;也不是之前的 debug for chrome 了&#xf…

【Arduino TFT】 记录使用DMA优化TFT屏帧率

忘记过去&#xff0c;超越自己 ❤️ 博客主页 单片机菜鸟哥&#xff0c;一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2023-10-18 ❤️❤️ 本篇更新记录 2023-10-18 ❤️&#x1f389; 欢迎关注 &#x1f50e;点赞 &#x1f44d;收藏 ⭐️留言&#x1f4dd;&#x1f64…

软件外包开发设计文档

编写软件设计文档是项目开发过程中的关键步骤&#xff0c;它有助于明确系统的设计和架构&#xff0c;并为开发人员提供指导。以下是编写软件设计文档的一般步骤和建议&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;…

Python中Scrapy框架搭建ip代理池教程

在网络爬虫开发中&#xff0c;使用代理IP池可以提高爬取效率和匿名性&#xff0c;避免被目标网站封禁IP。本文将介绍如何使用Python中的Scrapy框架搭建IP代理池&#xff0c;并提供代码实例&#xff0c;帮助您快速搭建一个稳定可靠的代理池。 Python中Scrapy框架搭建ip代理池教程…

Excel·VBA制作工资条

看到一篇博客《excel表头_Excel工资表怎么做&#xff1f;3分钟学会利用函数生成工资表》&#xff0c;使用排序功能、函数制作工资条。但如果需要经常制作工资条&#xff0c;显然使用VBA更加方便 VBA制作工资条 Sub 制作工资条()Dim title_row&, blank_row&, ws_new$,…

变电站数字孪生3D可视化运维系统,实现电力行业智慧化数字化信息化转型升级

变电站数字孪生3D可视化运维系统&#xff0c;实现电力行业智慧化数字化信息化转型升级。近年来&#xff0c;随着科技不断发展与进步&#xff0c;我国在智慧电网国网电力建设方面取得了长足进展。目前已经在多个地区和国家建立起了智慧电网电力项目并投入运行&#xff0c;这些项…

Ask Milvus Anything!聊聊被社区反复@的那些事儿ⅠⅠ

在上月的 “Ask Milvus” 专题直播中&#xff0c;我们为大家带来了 Backup 的技术解读&#xff0c;收到了社区成员很多积极的反馈。本期直播&#xff0c;我们将继续为大家带来社区呼声很高的 “Birdwatcher” 和 “Range Search” 两项功能的技术解读。 BirdWatcher 作为 Milvu…

Go语言入门心法(八): mysql驱动安装报错onnection failed

一: go语言安装mysql驱动报错 安装最新版mysql驱动&#xff1a; PS D:\program_file\go_workspace> go install github.com/go-sql-driver/mysqllatest 报错信息&#xff1a; go: github.com/go-sql-driver/mysqllatest: module github.com/go-sql-driver/mysql: Get "…

如何转换Corona和Vray材质?cr材质转vr材质的方法

cr材质转vr材质的方法一&#xff1a;使用CG Magic插件&#xff0c;一键转换 CG Magic是一款基于3ds Max深度开发的智能化辅助插件&#xff0c;上千项实用功能&#xff0c;降低渲染时长&#xff0c;节省时间和精力&#xff0c;大幅简化工作流程&#xff0c;助力高效完成创作。 …

Nessus已激活,New Scan按钮不可点击

刷新后会给出下面的提示 Plugins are compiling. Nessus will be limited until compilation is complete. 因为插件编译中&#xff0c;所以扫描功能被禁用了。 查看编辑进度&#xff0c;鼠标放到两个循环箭头上即可查看。