概述

SpringBoot 整合 Redis 是使用 SpringData 实现的。

SpringData 是与 SpringBoot 齐名的顶级项目,整合了对常用数据库的模板型操作。

在 SpringBoot 2.x 之后,Jedis 被 Lettuce 替代了。

Jedis

采用的直连,多个线程操作的话,是不安全的。

如果想要避免不安全,就要使用 Jedis pool 连接池解决。

这样是有一些弊端的,比如线程数量太多了,Redis 服务就比较庞大,而且它是阻塞的。

Lettuce

底层采用 Netty,实例可以在多个线程中进行共享。

不存在线程不安全的情况,可以减少线程数量。

使用

导入依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

yaml 配置

spring:
redis:
host: 47.100.222.85
port: 6379
jedis:
pool:
max-active: 8
max-wait: -1ms
max-idle: 500
min-idle: 0
lettuce:
shutdown-timeout: 0ms

测试

@Resource
private RedisTemplate redisTemplate; @Test
void contextLoads() {
redisTemplate.opsForValue().set("myKey", "myValue");
System.out.println(redisTemplate.opsForValue().get("myKey"));
}

输出为:myValue,连接成功。

源码分析

RedisAutoConfiguration

@AutoConfiguration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
public RedisAutoConfiguration() {
} @Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 默认的 RedisTemplate 没有过多的设置,Redis 对象都是需要序列化的
// 两个泛型都是 Object 的类型,我们使用需要强制转换,很不方便,预期是 <String, Object>
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
} @Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
// 由于 String 是 Redis 最常使用的类型,所以说单独提出来了一个 Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
}

通过源码可以看出,SpringBoot 自动帮我们在容器中生成了一个 RedisTemplate 和一个 StringRedisTemplate。

但是,这个 RedisTemplate 的泛型是 <Object, Object>,写代码不方便,需要写好多类型转换的代码。

我们需要一个泛型为 <String, Object> 形式的 RedisTemplate。

并且,这个 RedisTemplate 没有设置数据存在 Redis 时,key 及 value 的序列化方式。

由 @ConditionalOnMissingBean 可以看出,如果 Spring 容器中有了自定义的 RedisTemplate 对象,自动配置的 RedisTemplate 不会实例化。

因此我们可以直接自己写个配置类,配置 RedisTemplate。

集成

Redis 配置类

import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter; /**
* Redis 配置类
*/
@Configuration
@EnableCaching
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class RedisConfig extends CachingConfigurerSupport { @Value("${spring.redis.database}")
private int database; @Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 设置数据库
connectionFactory.setDatabase(database);
// 刷新配置
connectionFactory.afterPropertiesSet();
// 重置连接
connectionFactory.resetConnection();
// 设置连接
template.setConnectionFactory(connectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.activateDefaultTyping(
om.getPolymorphicTypeValidator(),
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.PROPERTY);
om.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.registerLocalDateTime(om);
serializer.setObjectMapper(om);
// key采用String的序列化方式
template.setKeySerializer(new StringRedisSerializer());
// value序列化方式采用jackson
template.setValueSerializer(serializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(new StringRedisSerializer());
// hash的value序列化方式采用jackson
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
// 添加对事务的支持
template.setEnableTransactionSupport(true);
return template;
} /**
* 处理时间类型
*
* @param objectMapper 待序列化对象
*/
private void registerLocalDateTime(ObjectMapper objectMapper) {
// 设置java.util.Date时间类的序列化以及反序列化的格式
objectMapper.setDateFormat(new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN)); JavaTimeModule timeModule = new JavaTimeModule();
// LocalDateTime
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);
timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(dateTimeFormatter));
timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTimeFormatter));
// LocalDate
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN);
timeModule.addSerializer(LocalDate.class, new LocalDateSerializer(dateFormatter));
timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormatter));
// LocalTime
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN);
timeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter));
timeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter));
objectMapper.registerModule(timeModule); } }

直接用 RedisTemplate 操作 Redis,比较繁琐。

因此直接封装好一个 RedisUtils,这样写代码更方便点。

这个 RedisUtils 交给Spring容器实例化,使用时直接注解注入。

Redis 工具类

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnectionCommands;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit; /**
* Redis 工具类
*/
@Component
public class RedisUtils { private static RedisTemplate<String, Object> redisTemplate; @Autowired
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
RedisUtils.redisTemplate = redisTemplate;
} /**
* 连接测试
*
* @return 测试结果
*/
public static String ping() {
return redisTemplate.execute(RedisConnectionCommands::ping);
} /**
* 切换数据库
*
* @param dbIndex 数据库编号(默认有16个数据库,编号在0-15之间)
*/
public static void select(int dbIndex) {
// 获取连接工厂
LettuceConnectionFactory connectionFactory = (LettuceConnectionFactory) redisTemplate.getConnectionFactory();
if (ObjUtil.isNull(connectionFactory)) {
return;
}
// 设置数据库
connectionFactory.setDatabase(dbIndex);
// 刷新配置
connectionFactory.afterPropertiesSet();
redisTemplate.setConnectionFactory(connectionFactory);
} /**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒),指定为-1代表永久有效
*/
public static boolean expire(String key, long time) {
return Boolean.TRUE.equals(redisTemplate.expire(key, time, TimeUnit.SECONDS));
} /**
* 根据key获取过期时间
*
* @param key 键
* @return 时间(秒)。-1:永久有效;-2:该键已过期或不存在
*/
public static long getExpire(String key) {
Long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS);
return ObjUtil.isNull(expire) ? 0 : expire;
} /**
* 判断key是否存在
*
* @param key 键
* @return 结果
*/
public static boolean has(String key) {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
} /**
* 删除缓存
*
* @param key 键,可以传一个或多个值
*/
public static void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollUtil.toList(key));
}
}
} /**
* 字符串缓存取值(不能获取token值,因为其自带加密,无法解析)
*
* @param key 键
* @return 值
*/
public static Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
} /**
* 字符串缓存设值
*
* @param key 键
* @param value 值
*/
public static void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
} /**
* 只有在 key 不存在时设置 key 的值
*
* @param key 键
* @param value 值
*/
public static void setIfAbsent(String key, String value) {
redisTemplate.opsForValue().setIfAbsent(key, value);
} /**
* 字符串缓存设值并设置生效时间
*
* @param key 键
* @param value 值
* @param time 时间(秒),time要大于0,如果time小于等于0,将设置无限期
*/
public static void set(String key, Object value, long time) {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
} /**
* 递增
*
* @param key 键
* @param num 要增加几
*/
public static long inc(String key, long num) {
Long increment = redisTemplate.opsForValue().increment(key, num);
return increment == null ? 0 : increment;
} /**
* 递减
*
* @param key 键
* @param num 要减少几
*/
public static long dec(String key, long num) {
Long decrement = redisTemplate.opsForValue().decrement(key, num);
return decrement == null ? 0 : decrement;
} /**
* 获取list缓存的内容
*
* @param key 键
* @return 列表
*/
public static List<Object> getList(String key) {
return redisTemplate.opsForList().range(key, 0, -1);
} /**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束。0到-1代表所有值
*/
public static List<Object> getList(String key, long start, long end) {
return redisTemplate.opsForList().range(key, start, end);
} /**
* 获取list缓存的长度
*
* @param key 键
*/
public static long getListSize(String key) {
Long size = redisTemplate.opsForList().size(key);
return size == null ? 0 : size;
} /**
* 获取list中的值
*
* @param key 键
* @param index 索引index>=0时,0:表头,1:第二个元素,依次类推;<br>
* 索引index<0时,-1:表尾,-2:倒数第二个元素,依次类推
*/
public static Object getList(String key, long index) {
return redisTemplate.opsForList().index(key, index);
} /**
* 将list放入缓存
*
* @param key 键
* @param value 值
*/
public static void setList(String key, Object value) {
redisTemplate.opsForList().rightPush(key, value);
} /**
* 将list放入缓存并设置生效时间
*
* @param key 键
* @param value 值
* @param time 时间(秒)
*/
public static void setList(String key, Object value, long time) {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
} /**
* 将list放入列表缓存
*
* @param key 键
* @param value 值
*/
public static void setList(String key, List<Object> value) {
redisTemplate.opsForList().rightPushAll(key, value);
} /**
* 将list放入列表缓存并设置生效时间
*
* @param key 键
* @param value 值
* @param time 时间(秒)
*/
public static void setList(String key, List<Object> value, long time) {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
} /**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
*/
public static void setList(String key, long index, Object value) {
redisTemplate.opsForList().set(key, index, value);
} /**
* 移除n个值为value的
*
* @param key 键
* @param count 移除多少个
* @param value 值
*/
public static void delList(String key, long count, Object value) {
redisTemplate.opsForList().remove(key, count, value);
} /**
* 左弹出list缓存的内容
*
* @param key 键
*/
public static void popList(String key) {
redisTemplate.opsForList().leftPop(key);
} /**
* 根据key获取Set中的所有值
*
* @param key 键
*/
public static Set<Object> getSet(String key) {
return redisTemplate.opsForSet().members(key);
} /**
* 随机获取变量中的元素
*
* @param key 键
* @return value值
*/
public static Object randomSet(String key) {
return redisTemplate.opsForSet().randomMember(key);
} /**
* 获取set缓存的长度
*
* @param key 键
*/
public static long getSetSize(String key) {
Long size = redisTemplate.opsForSet().size(key);
return size == null ? 0 : size;
} /**
* 将数据放入set缓存
*
* @param key 键
* @param values 值,可以是多个
*/
public static void setSet(String key, Object... values) {
redisTemplate.opsForSet().add(key, values);
} /**
* 将set数据放入缓存并设置生效时间
*
* @param key 键
* @param time 时间(秒)
* @param values 值,可以是多个
*/
public static void setSetTime(String key, long time, Object... values) {
redisTemplate.opsForSet().add(key, values);
if (time > 0) {
expire(key, time);
}
} /**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return 结果
*/
public static boolean hasSet(String key, Object value) {
return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, value)); } /**
* 移除值为value的
*
* @param key 键
* @param values 值,可以是多个
*/
public static void delSet(String key, Object... values) {
redisTemplate.opsForSet().remove(key, values);
} /**
* 添加元素,有序集合是按照元素的score值由小到大排列
*
* @param key 键
* @param value 对象名称
* @param score 数据值
*/
public static void setZset(String key, TypedTuple<Object> value, double score) {
redisTemplate.opsForZSet().add(key, value, score);
} /**
* 添加元素,向集合中插入多个元素
*
* @param key 键
* @param values set集合
*/
public static void setZset(String key, Set<TypedTuple<Object>> values) {
redisTemplate.opsForZSet().add(key, values);
} /*
* 获取元素集合,从小到大排序
* @param key
* @param start 开始位置
* @param end 结束位置, -1查询所有
* @return 元素集合
*/
public static Set<Object> getZset(String key, long start, long end) {
return redisTemplate.opsForZSet().range(key, start, end);
} /**
* 从集合中删除指定元素
*
* @param key 键
* @param values 值
*/
public static void delZset(String key, Object... values) {
redisTemplate.opsForZSet().remove(key, values);
} /**
* 增加元素的score值,并返回增加后的值
*
* @param key 键
* @param value 值
* @param num 增加多少score值
* @return 增加后的score值
*/
public static double incScoreZset(String key, String value, double num) {
Double result = redisTemplate.opsForZSet().incrementScore(key, value, num);
return ObjUtil.isNull(result) ? 0 : result;
} /**
* 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列
*
* @param key 键
* @param value 值
* @return 0表示第一位
*/
public static long rankZset(String key, Object value) {
Long result = redisTemplate.opsForZSet().rank(key, value);
return ObjUtil.isNull(result) ? 0 : result;
} /**
* 获取集合大小
*
* @param key 键
* @return 集合大小
*/
public static long getZsetSize(String key) {
Long result = redisTemplate.opsForZSet().size(key);
return ObjUtil.isNull(result) ? 0 : result;
} /**
* 获取键对应的所有值
*
* @param key 键
* @return 对应的多个键值
*/
public static Map<Object, Object> getHash(String key) {
return redisTemplate.opsForHash().entries(key);
} /**
* 根据键和项取值
*
* @param key 键
* @param item 项
*/
public static Object getHash(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
} /**
* 设值
*
* @param key 键
* @param map 对应多个键值
*/
public static void setHash(String key, Map<String, Object> map) {
redisTemplate.opsForHash().putAll(key, map);
} /**
* 设值
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
*/
public static void setHash(String key, Map<String, Object> map, long time) {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
} /**
* 向一张hash表中放入数据,如果不存在则创建
*
* @param key 键
* @param item 项
* @param value 值
*/
public static void setHash(String key, String item, Object value) {
redisTemplate.opsForHash().put(key, item, value);
} /**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
*/
public static void setHash(String key, String item, Object value, long time) {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
} /**
* 判断hash表中是否有该项的值
*
* @param key 键,不能为null
* @param item 项,不能为null
* @return 结果
*/
public static boolean hasHash(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
} /**
* 删除hash表中的值
*
* @param key 键,不能为null
* @param item 项,可以是多个,不能为null
*/
public static void delHash(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
} /**
* hash递增,如果不存在,就会创建一个,并把新增后的值返回
*
* @param key 键
* @param item 项
* @param num 要增加几(大于0)
*/
public static double incHash(String key, String item, double num) {
return redisTemplate.opsForHash().increment(key, item, num);
} /**
* hash递减
*
* @param key 键
* @param item 项
* @param num 要减少几(小于0)
*/
public static double decHash(String key, String item, double num) {
return redisTemplate.opsForHash().increment(key, item, -num);
} }

参考

https://www.bilibili.com/video/BV1S54y1R7SB?spm_id_from=333.999.0.0

版本

6.2.6

Redis 19 SpringBoot集成的更多相关文章

  1. 【redis】-- springboot集成redis及使用

    springboot自动配置的redis并不是特别好用,所以需要我们使用原生的jedis, 1.添加依赖 2.在application文件中配置 # Redis服务器地址 redis.host= # ...

  2. springboot集成redis(mybatis、分布式session)

    安装Redis请参考:<CentOS快速安装Redis> 一.springboot集成redis并实现DB与缓存同步 1.添加redis及数据库相关依赖(pom.xml) <depe ...

  3. 【springBoot】springBoot集成redis的key,value序列化的相关问题

    使用的是maven工程 springBoot集成redis默认使用的是注解,在官方文档中只需要2步; 1.在pom文件中引入即可 <dependency> <groupId>o ...

  4. SpringBoot集成redis的key,value序列化的相关问题

    使用的是maven工程 springBoot集成redis默认使用的是注解,在官方文档中只需要2步; 1.在pom文件中引入即可 <dependency> <groupId>o ...

  5. Windows环境下springboot集成redis的安装与使用

    一,redis安装 首先我们需要下载Windows版本的redis压缩包地址如下: https://github.com/MicrosoftArchive/redis/releases 连接打开后如下 ...

  6. springBoot集成Redis遇到的坑(择库)源码分析为什么择库失败

    提示: springboot提供了一套链接redis的api,也就是个jar包,用到的连接类叫做LettuceConnectionConfiguration,所以我们引入pom时是这样的 <de ...

  7. Springboot集成mybatis(mysql),mail,mongodb,cassandra,scheduler,redis,kafka,shiro,websocket

    https://blog.csdn.net/a123demi/article/details/78234023  : Springboot集成mybatis(mysql),mail,mongodb,c ...

  8. SpringBoot | 集成Redis

    Windows下安装: https://github.com/MicrosoftArchive/redis/releases zip下就解包到自定义目录下,msi就跟着步骤安装 进入安装目录下运行命令 ...

  9. springboot集成redis使用redis作为session报错ClassNotFoundException类RememberMeServices

    springboot 集成redis使用redis作为缓存,会报错的问题. 错误信息: java.lang.IllegalStateException: Error processing condit ...

  10. 基于Springboot集成security、oauth2实现认证鉴权、资源管理

    1.Oauth2简介 OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAu ...

随机推荐

  1. Javascript之Object、Array

    Object.keys 对象的键转化为数组 Object.values 对象的属性值转化为数组 Object.assign 对象的合并   Array.from() 伪数组对象的属性值转化为数组.类似 ...

  2. 【Azure 事件中心】Azure Event Hub中的数据能不能存储大于7天呢?如果7天之后是不是会自动删除呢?

    问题描述 Event Hub中有个retention的设置为7天,有没有办法增大这个Retention的时间? 如果没办法,是不是超过7天的数据就会被删除? 问题解答 因为Azure Event Hu ...

  3. 【Azure 环境】Azure Key Vault 采用自签名证书,是否需要CA provider

    关于 Azure Key Vault 证书,密钥保管库证书支持适用于 x509 证书管理,它提供以下行为: 允许证书所有者通过密钥保管库创建过程或通过导入现有证书来创建证书. 包括自签名证书和证书颁发 ...

  4. 『Echarts』基本使用

    一.前言 本篇文章是『Echarts』文章的第 2 篇,主要介绍『Echarts』基本使用 在『Echarts』第 1 篇文章中,我们介绍了 Echarts 的概述及其强大的数据可视化功能.本篇将继续 ...

  5. linux下查看文件时显示行号

    1.用 vi 或 vim 打开文件后显示行号: 显示当前行号: :nu 显示所有行号: :set nu     2.设置服务器显示行号 2.1:编辑~/.vimrc文件,在该文件中加入         ...

  6. 辨析Java与网络通信中的编码与解码

    在Java字符流上下文中的编码和解码,以及在网络通信中的编码概念. 在Java中,当我们谈论字符流(如Reader和Writer)时,编码和解码主要涉及将字符数据转换为字节数据,以及将字节数据转换回字 ...

  7. [VueJsDev] 基础知识 - AutoNumber VsCode 插件开发

    [VueJsDev] 目录列表 https://www.cnblogs.com/pengchenggang/p/17037320.html AutoNumber VsCode插件开发 ::: deta ...

  8. linux下命令行打开文件夹窗口

    方法一: 使用自带的命令:nautilus . 打开当前文件夹 nautilus . 打开指定路径文件夹 nautilus ddd/ccc/ 方法二:xdg-open xdg-open 命令相当于在 ...

  9. 【stars-one】JetBrains产品试用重置工具

    原文[stars-one]JetBrains产品试用重置工具 | Stars-One的杂货小窝 一款可重置JetBrains全家桶产品的试用时间的小工具,与其全网去找激活码,还不如每个月自己手动重置试 ...

  10. 记一次maven不下来的经历

    起因:自己手动搭建个项目,参考公司项目使用了很多依赖,但是当自己maven时候发现一个依赖怎么也down不下来,就此展开了一番折腾 这个依赖叫 <dependency> <group ...