RuoYi-Vue-Plus(基础知识点jackson、mybatisplus、redis)

一、JacksonConfig 全局序列化反序列化配置

1.1yml中配置

#时区
spring.jackson.time-zone=GMT+8
#日期格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
#默认转json的属性,这里设置为非空才转json
spring.jackson.default-property-inclusion=non_null
#设置属性命名策略,对应jackson下PropertyNamingStrategy中的常量值,SNAKE_CASE-返回的json驼峰式转下划线,json body下划线传到后端自动转驼峰式
spring.jackson.property-naming-strategy=SNAKE_CASE
#对象为空时是否报错,默认true
spring.jackson.serialization.fail-on-empty-beans=true
#返回的java.util.date转换成timestamp
spring.jackson.serialization.write-dates-as-timestamps=true
#json中含pojo不存在属性时是否失败报错,默认true
spring.jackson.deserialization.fail-on-unknown-properties=false
#是否允许出现单引号,默认false
spring.jackson.parser.allow-single-quotes=true
 

1.2配置文件中配置
光标定位置在builder后面,ALT + ENTER,选择 replace lambda with anonymous class

可以显示 lambda为普通方法。此处定义了一下常见类型的序列化方法

@Slf4j
@Configuration
public class JacksonConfig {

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer customizer() {
        return new Jackson2ObjectMapperBuilderCustomizer() {
            @Override
            public void customize(Jackson2ObjectMapperBuilder builder) {
                // 全局配置序列化返回 JSON 处理
                JavaTimeModule javaTimeModule = new JavaTimeModule();
                javaTimeModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE);
                javaTimeModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE);
                javaTimeModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE);
                javaTimeModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter));
                javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));
                builder.modules(javaTimeModule);
                builder.timeZone(TimeZone.getDefault());
                log.info("初始化 jackson 配置");
            }
        };
    }

}
ruoyi-admin/src/main/resources/application.yml 中配置jackon
jackson:
  # 日期格式化
  date-format: yyyy-MM-dd HH:mm:ss
  serialization:
    # 格式化输出
    indent_output: false
    # 忽略无法转换的对象
    fail_on_empty_beans: false
  deserialization:
    # 允许对象忽略json中不存在的属性
    fail_on_unknown_properties: false

点击Jackson2ObjectMapperBuilderCustomizer, 可以查看自动配置类:JacksonAutoConfiguration

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Jackson2ObjectMapperBuilder.class)
	static class JacksonObjectMapperBuilderConfiguration {

		@Bean
		@Scope("prototype")
		@ConditionalOnMissingBean
		Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder(ApplicationContext applicationContext,
				List<Jackson2ObjectMapperBuilderCustomizer> customizers) {
			Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
			builder.applicationContext(applicationContext);
			customize(builder, customizers);
			return builder;
		}

		private void customize(Jackson2ObjectMapperBuilder builder,
				List<Jackson2ObjectMapperBuilderCustomizer> customizers) {
			for (Jackson2ObjectMapperBuilderCustomizer customizer : customizers) {
				customizer.customize(builder);
			}
		}

	}
1.3常见jackon注解 
  • @JsonIgnore    忽略序列化,用于属性上
  • @JsonInclude(JsonInclude.Include.NON_EMPTY)  不为空时候才进行序列化和反序列化
  • @JsonSerialize(using = DictDataJsonSerializer.class)  序列化,如下DictDataJsonSerializer 是字典序列化的处理工具
    /**
     * 字典数据json序列化工具
     *
     * @author itino
     * @deprecated 建议使用通用翻译注解
     */
    @Deprecated
    @Slf4j
    public class DictDataJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {
    
        private String dictType;
    
        @Override
        public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            try {
                DictService dictService = SpringUtils.getBean(DictService.class);
                if (ObjectUtil.isNotNull(dictService)) {
                    String label = dictService.getDictLabel(dictType, value);
                    gen.writeString(StringUtils.isNotBlank(label) ? label : value);
                } else {
                    gen.writeString(value);
                }
            } catch (BeansException e) {
                log.error("字典数据未查到, 采用默认处理 => {}", e.getMessage());
                gen.writeString(value);
            }
        }
    
        @Override
        public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
            DictDataMapper anno = property.getAnnotation(DictDataMapper.class);
            if (Objects.nonNull(anno) && StrUtil.isNotBlank(anno.dictType())) {
                this.dictType = anno.dictType();
                return this;
            }
            return prov.findValueSerializer(property.getType(), property);
        }
    }
    

  • @JsonProperty( value = "pass")  接受和序列化都用 pass ,而不是 password
    @JsonIgnore
    @JsonProperty( value = "pass")
    public String getPassword() {
        return password;
    }

  • @JsonFormat(pattern = "yyyy-MM-dd")  系列化格式

1.4 若依jackson工具包

com.ruoyi.common.utils.JsonUtils   ,提供序列化和反序列化 一些常用方法

二、MybatisPlus

依赖

 <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus.version}</version>
            </dependency>

ruoyi-admin/src/main/resources/application.yml  配置文件:

  • 配置了Mapper 接口的扫描
  • 配置Mapper对应XML的扫描
  • 配置实体类domain扫描
  • 配字段驼峰规则
  • 以及 p6spy的日志分析
  • 配置主键生成规则,以及CRUD策略
# MyBatisPlus配置
# https://baomidou.com/config/
mybatis-plus:
  # 不支持多包, 如有需要可在注解配置 或 提升扫包等级
  # 例如 com.**.**.mapper  com.ruoyi.system.mapper
  mapperPackage: com.ruoyi.**.mapper
  # 对应的 XML 文件位置
  mapperLocations: classpath*:mapper/**/*Mapper.xml
  # 实体扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: com.ruoyi.**.domain
  # 启动时是否检查 MyBatis XML 文件的存在,默认不检查
  checkConfigLocation: false
  configuration:
    # 自动驼峰命名规则(camel case)映射
    mapUnderscoreToCamelCase: true
    # MyBatis 自动映射策略
    # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射
    autoMappingBehavior: PARTIAL
    # MyBatis 自动映射时未知列或未知属性处理策
    # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
    autoMappingUnknownColumnBehavior: NONE
    # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
    # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
    # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
    logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
  global-config:
    # 是否打印 Logo banner
    banner: true
    dbConfig:
      # 主键类型
      # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
      idType: ASSIGN_ID
      # 逻辑已删除值
      logicDeleteValue: 2
      # 逻辑未删除值
      logicNotDeleteValue: 0
      # 字段验证策略之 insert,在 insert 的时候的字段验证策略
      # IGNORED 忽略 NOT_NULL 非NULL NOT_EMPTY 非空 DEFAULT 默认 NEVER 不加入 SQL
      insertStrategy: NOT_NULL
      # 字段验证策略之 update,在 update 的时候的字段验证策略
      updateStrategy: NOT_NULL
      # 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件
      where-strategy: NOT_NULL

 com.ruoyi.framework.config.MybatisPlusConfig 配置文件,主要配置以下:自行查看

  • // 数据权限处理
  • // 分页插件
  • // 乐观锁插件
  • //   指定字段的填充策略
  •  使用网卡信息绑定雪花生成器,防止集群雪花ID重复
     
 1.1 常见注解

        

@TableName("sys_user")  标注数据库表名称
@TableId(value = "user_id")  主键
@Version   乐观锁(比如查询携带上 version字段,才回去更新版本)
@TableLogic    删除标志(0代表存在 2代表删除):上面 yml配置的逻辑删除, 标注该注解的字段,数据库要默认设置 0
@TableField
属性
fill

指定字段的填充策略,如自动填充创建时间、更新时间等。需要实现 MyBatis-Plus 提供的 MetaObjectHandler 接口,

并重写 insertFill 和 updateFill 方法。

若依具体实现类:com.ruoyi.framework.handler.CreateAndUpdateMetaObjectHandler

exist 

标记是否为数据库表字段,默认为 true。如果设置为 false,则表示该字段不是数据库表的字段,不会参与 SQL 语句的生成

示例:
@TableField(exist = false)
private List<SysRole> roles;
value
  • 数据库字段名,用于指定实体类字段对应的数据库字段名。当实体类字段名与数据库字段名不一致时使用。
  • 示例:@TableField("db_column_name")
update
  • 用于 SQL 的 SET 语句,设置字段更新的策略。通常与 @TableLogic 注解一起使用,实现逻辑删除。
  • 示例:@TableField(update = "deleted=1")
nsertStrategy 和 updateStrategy
  • 字段的插入和更新策略。FieldStrategy 是一个枚举类,包含以下值:IGNORED(忽略)、NOT_NULL(非 NULL 则更新)、NOT_EMPTY(非空则更新)、ALWAYS(总是更新)。
  • 示例:
  • @TableField( insertStrategy = FieldStrategy.NOT_EMPTY, updateStrategy = FieldStrategy.NOT_EMPTY, whereStrategy = FieldStrategy.NOT_EMPTY )
select
  • 是否进行 select 查询。默认为 true,表示该字段会参与查询。如果设置为 false,则查询时不会包含该字段。
  • 示例:@TableField(select = false)
jdbcType
  • 字段的 JDBC 类型。通常用于指定某些特殊类型的字段,如枚举类型。
    • 示例:
      @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
el
  • 支持 EL 表达式,用于复杂字段的映射处理。
  • 示例:@TableField(el = "column + '_suffix'")
condition
  • 用于 SQL WHERE 语句的条件,通常与 @Select 注解一起使用,实现动态 SQL。
  • 示例:@TableField(condition = "name != null and name = #{name}")
strategy
  • 字段验证策略,与 insertStrategy 和 updateStrategy 功能类似,但用于全局配置。
  • 示例:@TableField(strategy = FieldStrategy.NOT_EMPTY)
                                                                                     
1.2 BaseMapperPlus

若依继承了 mybatis-plus的BaseMapper<T> 接口 ,自定义了  BaseMapperPlus<M, T, V> Mapper接口:com.ruoyi.common.core.mapper.BaseMapperPlus

  • 提供泛型的转换
  • 提供BaseMapper原有接口的封装
  • 提供其他新增的查询方法

1.3分布式主键 雪花ID
1-yml中配置雪花:
dbConfig:
  # 主键类型
  # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
  idType: ASSIGN_ID

2-com.ruoyi.framework.config.MybatisPlusConfig 类中注入IdentifierGenerator ,具体实现自行查看

  /**
     * 使用网卡信息绑定雪花生成器
     * 防止集群雪花ID重复
     */
    @Bean
    public IdentifierGenerator idGenerator() {
        return new DefaultIdentifierGenerator(NetUtil.getLocalhost());
    }
1.4 wapper

关于条件构造器: wapper 学习文章可以参考

mybatis-plus中wrapper的用法(详细)_mybatisplus wrapper-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_39715000/article/details/120090033上文未提及一些常用函数

1-apply() 函数  :将要添加到 SQL 语句中的 SQL 片段作为参数传递给它即可
//简单查询
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.apply("id = 1 or name like '%test%'");
List<User> userList = userMapper.selectList(wrapper);

//日期
apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2020-10-08")

apply("date_format(dateColumn,{0}) = {1}", "%Y-%m-%d", "2020-10-08")
2-func 函数:可以添加if 等判断
 LambdaQueryWrapper<SysOperLog> lqw = new LambdaQueryWrapper<SysOperLog>()
            .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
            .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
                SysOperLog::getBusinessType, operLog.getBusinessType())
            .func(f -> {
                if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) {
                    f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));
                }
            })

3- nested 嵌套查询: nested函数中语句会加上()作为整体提升优先级

 public void complexQuery() {  
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();  
        queryWrapper.eq("status", 1)  
                .nested(i -> i.eq("name", "John").or().like("email", "example%"))  
                .orderByAsc("id");  
  
        List<User> userList = userMapper.selectList(queryWrapper);   
    }  

SELECT * FROM user WHERE status = 1 AND (name = 'John' OR email LIKE 'example%') ORDER BY id ASC 

三、BeanCopyUtils

com.ruoyi.common.utils.BeanCopyUtils 包中 ,提供:(基于 cglib 性能优异)

  • Bean to Bean
  • Bean to Map
  • Map to Bean
  • Map to Map
  • List copy

四、Redis 

1.1 Redisson
  1. 功能丰富:Redisson提供了Redis各种数据结构的Java实现,以及分布式锁、计数器等高级功能,满足复杂场景需求。

  2. 易于集成:友好的API和与多种Java框架的集成支持,使得开发者能够轻松地将Redis集成到Java应用中。

  3. 高性能与可扩展:基于Redis的内存存储和集群支持,Redisson实现了高读写速度和水平扩展能力,适用于高并发和大规模应用。

依赖

 <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-data-27</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>lock4j-redisson-spring-boot-starter</artifactId>
        </dependency>
1.2 Redisson 配置文件和配置类 
配置文件 yml中,com.ruoyi.framework.config.properties.RedissonProperties 是其配置类。

下面分别是单机 和集群配置类。

/**
 * 单机服务配置
 */
private SingleServerConfig singleServerConfig;

/**
 * 集群服务配置
 */
private ClusterServersConfig clusterServersConfig;
redisson:
  # redis key前缀
  keyPrefix: ruoyi-vue-plus
  # 线程池数量
  threads: 4
  # Netty线程池数量
  nettyThreads: 8
  # 单节点配置
  singleServerConfig:
    # 客户端名称
    clientName: ${ruoyi.name}
    # 最小空闲连接数
    connectionMinimumIdleSize: 8
    # 连接池大小
    connectionPoolSize: 32
    # 连接空闲超时,单位:毫秒
    idleConnectionTimeout: 10000
    # 命令等待超时,单位:毫秒
    timeout: 3000
    # 发布和订阅连接池大小
    subscriptionConnectionPoolSize: 50

com.ruoyi.framework.config.RedisConfig 类,是redisson的配置类。

 @Bean
    public RedissonAutoConfigurationCustomizer redissonCustomizer() {
        return config -> {
            config.setThreads(redissonProperties.getThreads())
                .setNettyThreads(redissonProperties.getNettyThreads())
                .setCodec(new JsonJacksonCodec(objectMapper));
            RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
            if (ObjectUtil.isNotNull(singleServerConfig)) {
                // 使用单机模式
                config.useSingleServer()
                    //设置redis key前缀
                    .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()))
                    .setTimeout(singleServerConfig.getTimeout())
                    .setClientName(singleServerConfig.getClientName())
                    .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout())
                    .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize())
                    .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize())
                    .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize());
            }
            // 集群配置方式 参考下方注释
            RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig();
            if (ObjectUtil.isNotNull(clusterServersConfig)) {
                config.useClusterServers()
                    //设置redis key前缀
                    .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()))
                    .setTimeout(clusterServersConfig.getTimeout())
                    .setClientName(clusterServersConfig.getClientName())
                    .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout())
                    .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize())
                    .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize())
                    .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize())
                    .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize())
                    .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize())
                    .setReadMode(clusterServersConfig.getReadMode())
                    .setSubscriptionMode(clusterServersConfig.getSubscriptionMode());
            }
            log.info("初始化 redis 配置");
         };
    }
1.3  redis 和redisson集群配置文件
/**
     * redis集群配置 yml
     *
     * --- # redis 集群配置(单机与集群只能开启一个另一个需要注释掉)
     * spring:
     *   redis:
     *     cluster:
     *       nodes:
     *         - 192.168.0.100:6379
     *         - 192.168.0.101:6379
     *         - 192.168.0.102:6379
     *     # 密码
     *     password:
     *     # 连接超时时间
     *     timeout: 10s
     *     # 是否开启ssl
     *     ssl: false
     *
     * redisson:
     *   # 线程池数量
     *   threads: 16
     *   # Netty线程池数量
     *   nettyThreads: 32
     *   # 集群配置
     *   clusterServersConfig:
     *     # 客户端名称
     *     clientName: ${ruoyi.name}
     *     # master最小空闲连接数
     *     masterConnectionMinimumIdleSize: 32
     *     # master连接池大小
     *     masterConnectionPoolSize: 64
     *     # slave最小空闲连接数
     *     slaveConnectionMinimumIdleSize: 32
     *     # slave连接池大小
     *     slaveConnectionPoolSize: 64
     *     # 连接空闲超时,单位:毫秒
     *     idleConnectionTimeout: 10000
     *     # 命令等待超时,单位:毫秒
     *     timeout: 3000
     *     # 发布和订阅连接池大小
     *     subscriptionConnectionPoolSize: 50
     *     # 读取模式
     *     readMode: "SLAVE"
     *     # 订阅模式
     *     subscriptionMode: "MASTER"
     */
1.4 RedisUtils 工具类

所在包 :com.ruoyi.common.utils.redis.RedisUtils

1、 订阅发布测试类以及结果如下;
    @Test
    void subPub(){
        String key = "key";
        //模拟订阅消息 启动后会一直监听消息
        RedisUtils.subscribe(key, String.class, consumer -> {
            Console.log("key:{}", key);
            Console.log("consumer:{}", consumer);
        });

        //模拟发布
        RedisUtils.publish(key,"发布一则消息1!");
        RedisUtils.publish(key,"发布一则消息2!");
        RedisUtils.publish(key,"ok", conumer->{
            Console.log("consumer3:{}", conumer);
        });
    }

key:key
consumer:发布一则消息1!
key:key
consumer:发布一则消息2!
consumer3:ok
key:key
consumer:ok
 

 2、设置缓存
  @Test
    void setCacheObject(){
        //ttl = -1 ,永久有效印版不用
        RedisUtils.setCacheObject("java", "helloWord");
        //ttl 自定义, 60秒有效期
        RedisUtils.setCacheObject("java", "helloWord", Duration.ofSeconds(60));
        //是否保留TTL有效期(例如: set之前ttl剩余60 set之后还是为60),false 表示永久
        RedisUtils.setCacheObject("java", "helloWord", true);
        //果不存在则设置 并返回 true 如果存在则返回 false
        boolean ifAbsent = RedisUtils.setObjectIfAbsent("java", "helloWord", Duration.ofSeconds(60));
    }
3、设置监听 

redis中配置 ,key 监听器配置  : notify-keyspace-event  ,如下:(接口中红线标注要包含的 字母,其他接口自行查看

# Redis服务器配置 

# 绑定IP地址
#解除本地限制 注释bind 127.0.0.1  
#bind 127.0.0.1  

# 服务器端口号  
port 6379 

#配置密码,不要可以删掉
#requirepass 
  
#key 监听器配置
notify-keyspace-events Exg
 

# 服务器运行模式,Redis以守护进程方式运行,默认为no,改为yes意为以守护进程方式启动,可后台运行,除非kill进程,改为yes会使配置文件方式启动redis失败,如果后面redis启动失败,就将这个注释掉
daemonize no

#当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定(自定义)
#pidfile /data/dockerData/redis/run/redis6379.pid  

#默认为no,redis持久化,可以改为yes
appendonly yes

 监听测试类:

package com.ruoyi.demo.listener;

import cn.hutool.core.lang.Console;
import com.ruoyi.common.utils.redis.RedisUtils;
import org.redisson.api.DeletedObjectListener;
import org.redisson.api.ExpiredObjectListener;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * <简述>
 * <详细描述>
 *
 * @author syf
 * @date 2024年03月18日 22:38
 */
@Component
public class ExpiredListener {

    @PostConstruct
    public void expireListener(){
        Console.log("启动监听器。。。。");
        //用于监听 Redisson 分布式缓存中对象的过期事件
        RedisUtils.addObjectListener("java", new ExpiredObjectListener() {
            @Override
            public void onExpired(String name) {
                Console.log("ExpiredObjectListener:{}", name);
            }
        });

        //监听删除
        RedisUtils.addObjectListener("java", new DeletedObjectListener() {
            @Override
            public void onDeleted(String name) {
                Console.log("DeletedObjectListener:{}", name);
            }

        });
    }
}

结果:监听到删除

4-对象操作

常用操作

@Test
    void getObject(){
        RedisUtils.setCacheObject("java", "helloWord");
        //6-校验对象是否存在
        RedisUtils.isExistsObject("java");
        //1-设置过期时间
        RedisUtils.expire("java", Duration.ofSeconds(10));
        //2-获取对象
        Object name = RedisUtils.getCacheObject("name");
        Console.log("name:{}", name);
        //3-获取剩余存活时间
        long time = RedisUtils.getTimeToLive("name");
        Console.log("time:{}", time);
        //4-删除
        RedisUtils.deleteObject("name");
        //5-删除集合
        List<String> list = new ArrayList<>();
        list.add("java1");
        list.add("java2");
        RedisUtils.setCacheObject("java1", "helloWord1");
        RedisUtils.setCacheObject("java2", "helloWord2");
        RedisUtils.deleteObject(list);

    }
5-数组操作

数组操作是拼接,不会覆盖,对象操作则是覆盖,注意使用场景

提供集合的操作下:

@Test
    void saveList(){
        //这个实际保存是对象 (覆盖之前 list1)
        List<String> list = Arrays.asList("java1", "java2");
        RedisUtils.setCacheObject("list1", list, Duration.ofSeconds(60));

        //保存是数组 (不会覆盖之前的数据 list2)
        RedisUtils.setCacheList("list2", list);
        //取
        List<String> list2 = RedisUtils.getCacheList("list2");

        //set集合 值不重复
        Set<String> set = new HashSet<>();
        set.add("java1");
        set.add("java2");
        RedisUtils.setCacheSet("set", set);
        RedisUtils.getCacheSet("set");

        //Map
        Map<String, Object> map = new HashMap<>();
        map.put("java1", "String");
        map.put("java2", "Integer");
        //存
        RedisUtils.setCacheMap("map", map);
        //取
        Object value = RedisUtils.getCacheMapValue("map", "java1");
        //修改map 里面值
        RedisUtils.setCacheMapValue("java1", "map", "null");
        //取map 里面值(自定义map 用得少)
        Set<String> objects = new HashSet<>();
        objects.add("java1");
        objects.add("java2");
        Map<String, Object> map2 = RedisUtils.getMultiCacheMapValue("map", objects);
        //取
        Map<String, Object> cacheMap = RedisUtils.getCacheMap("map");
        //遍历key
        Set<String> map1 = RedisUtils.getCacheMapKeySet("map");

    }
6-原子操作

原子操作,创建后,利用 增加 减少方法去修改

 @Test
    void  steAtom(){
        //原子操作
        RedisUtils.setAtomicValue("count" ,1);
        //增加
        RedisUtils.incrAtomicValue("count");
        //减少
        RedisUtils.decrAtomicValue("count");
        //获取
        long atomicValue = RedisUtils.getAtomicValue(":count");
    }
7-根据前缀获取

@Test
    void getKeys() {
        //get
        String prefix = "ruoyi-vue-plus:sys";
        Collection<String> keys = RedisUtils.keys(prefix + "*");
        List<String> list = new ArrayList<>(keys);
        for (String s : list) {
            Console.log("value:{}", s);
        }
        //删除
        String prefix1 = "list1";
        RedisUtils.deleteKeys(prefix1 + "*");
    }

结果:

value:sys_config
value:sys_oss_config
value:sys_oss:default_config
value:sys_dict
 

8-是否存在

 @Test
    void getExists() {
        //是否存在
        boolean hasKey = RedisUtils.hasKey("list2");
        
        boolean existsObjectis = RedisUtils.isExistsObject("list2");

    }

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

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

相关文章

数据库级别的刷新和数据表级别的刷新结果不一样吗

这个刷新和这个刷新有啥区别 我发现点左边的刷新没有办法刷新出新注册成功的用户&#xff0c;但是下一张图片就能刷新出来 我也知不道是不是&#xff0c;还是我navicat有问题 是的&#xff0c;数据库级别的刷新和数据表级别的刷新的结果是不同的&#xff1a; 数据库级别的刷新…

JavaSE(简介)

1. Java语言特性 简单 Java语法是C语法的一个“纯净版本”&#xff0c;相当于对C做了一个减法。这里没有头文件、指针运算&#xff08;甚至指针 语法&#xff09;、结构、联合、操作符重载、虚基类等等。不仅如此&#xff0c;Java开发环境远远超出大多数其他编程语言的开 发环…

ttkbootstrap界面美化系列之按钮Button(三)

目录 一&#xff1a;Button接口 二&#xff1a;Button创建 三&#xff1a;Button主题 四&#xff1a;Button样式 五&#xff1a;Button状态 从本章开始将详细介绍ttkbootstrap中支持的常用组件&#xff0c;从按钮BUTTON开始&#xff0c;在各类界面设计中按钮几乎是必不可少…

解锁AI生成模型的无限可能:Stability-AI 带你领略前沿科技

厌倦了千篇一律的图片和视频&#xff1f;想要创作独一无二的艺术作品&#xff1f;Stability-AI 横空出世&#xff0c;为你打开通往 AI 生成模型的大门&#xff0c;带你领略前沿科技的无限可能&#xff01; 神奇的功能&#xff0c;尽在掌握 Stability-AI 拥有众多令人惊叹的功能…

第2讲-Memory(4)拓展

存储器芯片结构 存储器扩展 地址总线:这决定了处理器将从内存中读取数据或写入数据的内存位置。 数据总线:它包含已从内存位置读取或将写入内存位置的数据内容。 控制总线:它管理组件之间的信息流,指示操作是读取还是写入,并确保操作在正确的时间发生。

聊一下大模型的函数调用-Function call

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

Springboot 利用自定义注解+切面,实现 查询数据集合时主动加序列字段

利用自定义注解切面,实现 查询数据集合时主动加序列字段, 只需要在Dao接口&#xff0c;方法上引入注解即可 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotat…

数据结构 - 链表

一.链表的概念 链表是一个在物理存储单元中不连续&#xff0c;没有顺序的的存储结构&#xff0c;关于它的顺序是由链表中的指针链接实现的&#xff0c;是一种递归的数据结构&#xff0c;链表有一系列节点组成&#xff0c;而这些节点会在运行时动态生成。 节点包括两个部分&am…

【docker】查看并拷贝容器内文件

一、查询容器 查询所有容器 docker ps查询名为os11的容器 docker ps | grep os11查询名为os11的容器&#xff08;包含不运行的&#xff09; docker ps -a| grep os11 docker ps [option] 显示结果介绍如下&#xff1a; 参考&#xff1a;[https://blog.51cto.com/u_15009374/31…

工厂投产、电池装车,广汽能上动力电池行业的“餐桌”吗?

文 | 智能相对论 作者 | 沈浪 “如果你不在餐桌上&#xff0c;你就会出现在菜单上。”在某种程度上&#xff0c;追逐效益的动力电池行业正在上演着布林肯的“餐桌菜单论”。 于是&#xff0c;我们可以看到&#xff0c;尽管整体的动力电池市场被宁德时代、比亚迪、LG新能源、…

怿星科技Neptune CHT-S测试系统,让智能座舱测试更加高效便捷

随着汽车“智能化”浪潮的推进&#xff0c;汽车的智能化水平正在持续刷新行业认知。在这股智能化潮流中&#xff0c;智能座舱作为客户体验最为直观的部分&#xff0c;其重要性不言而喻。倘若座舱设备出现死机、黑屏、卡顿等现象&#xff0c;都将对客户的使用体验产生非常大的影…

领军量子时代!逾九成机构加盟「英伟达」生态系统

在2024年3月17日至21日举行的GTC大会上&#xff0c;芯片制造领军企业英伟达&#xff08;NVIDIA&#xff09;发布了一项革命性的云服务&#xff0c;专为推动量子计算研究而设计。这一新服务&#xff0c;名为英伟达量子云&#xff08;NVIDIA Quantum Cloud&#xff09;&#xff0…

外包干了15天,技术退步明显。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;2019年我通过校招踏入了南京一家软件公司&#xff0c;开始了我的职业生涯。那时的我&#xff0c;满怀热血和憧憬&#xff0c;期待着在这个行业中闯出一片天地。然而&#xff0c;随着时间的推移&#xff0c;我发现自己逐渐陷入…

C# winform修改背景图 控件双向绑定 拖拽打开图片

修改背景图 说明 这里我准备基于百度飞桨PaddleSeg项目的人像分割模块做一个人像抠图&#xff0c;这里顺便用上了双向绑定和图片拖拽打开。 下面就是示例&#xff1a; 用颜色替换 用背景图替换 保存成功后的图片 一、使用百度飞桨PaddleSeg //初始化 引擎engine new Padd…

掌握未来技术:国产openEuler 操作系统学习网站指南!

介绍&#xff1a;openEuler是一个开源的操作系统平台&#xff0c;由华为技术有限公司发起并维护。 首先&#xff0c;openEuler支持多种处理器架构&#xff0c;包括但不限于AArch64&#xff08;鲲鹏&#xff09;和x86-64&#xff0c;这使得它可以在多种硬件平台上运行&#xff0…

滴水逆向PE结构

1.操作系统是只能打开可执行文件 以4D 5A开头MZ 其他的txt都是什么wrod 都是在exe程序中打开的 txt啥的不是可执行文件 PE结构是分节的 一节一节 节省硬盘空间 32位中任何一个exe都有4g的虚拟内存 占内存空间大 给磁盘空间小 在硬盘空间紧密 在内存空间大 &#xff08…

设计模式 --4:工厂方法模式

总结 &#xff1a; 个人理解&#xff1a; 工厂方法模式就是在简单工程模式的基础下将工厂类抽象出来。如果不抽象工厂类 &#xff0c;每一次创建一个新的算法&#xff0c;都要修改原来的工厂类&#xff0c;这不符合 开放–封闭原则 将工厂类给抽象出来&#xff0c;让具体的算法…

appium自动化框架综合实践

结合前面的元素寻找、操作、unittest测试框架&#xff0c;搭建一个完整的自动化框架。本篇旨在框架设计、单机用例执行、输出报告&#xff0c;下篇继续实践Bat批处理执行测试、多设备并发测试。 框架功能 数据配置日志输出截图处理基础功能封装&#xff08;公共方法&#xff…

Java学习笔记NO.24

T1.完成理工超市系统的商品类及其子类的定义&#xff0c;实现“浏览商品”及“查看商品详情”功能 &#xff08;1&#xff09;商品类 public class Goods {public String name;public double price;public int count;public String desc;public Goods(String name, double p…

敏捷开发——第二次作业JS/服务器的部署

部署 Web 服务器 1. 安装 Apache HTTP 服务器并部署静态网页应用 ⭐⭐ 默认情况下&#xff0c;Apache 在 /var/www/html 目录下寻找要提供服务的文件。可以将静态网页文件放置在这个目录下 2.安装 Nginx 并部署静态页面应用 3. 实践部分 1. 2. 3. 在 /var/www/html 目录下…