当前位置: 首页 > article >正文

Jedis

目录

依赖下载

配置SSH转发

连接到redis服务器

客户端的使用 

get / set

exists / del 

keys

expire /ttl 

type

字符串命令 

mget / mset

getrange /setrange 

 append

incr / decr

列表list 

push / pop / lrange

blpop/brpop

llen

集合set

sadd

sismember 

scard 

spop 

sinter 

sinterstore 

hash 

hset / hget 

hexists

hdel

hkeys / hvals

 有序集合zset

zadd

zcard

zrem

zscore 

 zrank


依赖下载

        前往maven仓库搜索jedis:

https://mvnrepository.com/search?q=jedisicon-default.png?t=N7T8https://mvnrepository.com/search?q=jedis

选择4版本:

然后引入或者下载依赖即可。

这里直接提供了maven的一个jedis地址:

<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.4.3</version>
</dependency>

 在pom.xml中引入依赖:

配置SSH转发

        以xshell为例子:

 

        右键你所选择的会话。选择属性:

        然后添加:

然后点击连接。

        查看是否生效:

        使用netstat命令来访问 8888端口:

  • win + r 输入cmd打开命令行。
  • 输入: netstat -ano |findstr 8888

         说明转发成功。

        如果什么都不显示,则表示配置失败。

        此时此刻,在后续的本地windows编程中,咱们的java代码就可以通过127.0.0.1:8888来访问我们的redis服务器了。同时外面的客户端是无法直接访问redis的6379端口了。 

        接下来可以正式编辑代码了。

连接到redis服务器

        在java目录中创建一个案例,如下:

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class RedisDemo {
    public static void main(String[] args) {
        // 连接到redis 服务器.
        JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");

        // 从redis池中取出一个连接来
        try (Jedis  jedis = jedisPool.getResource()) {
            // Redis各种命令就对应到Jedis对象的各种方法,调用方法,就相当于执行命令.
            String pong = jedis.ping();
            System.out.println(pong);
        }
    }
}
  • 首先需要创建一个jedis池,也就是JedisPool类,然后在这个pool中取出连接,来进行执行命令。
  • 使用jedisPool中的getResource方法来获取一个jedis连接,返回值为Jedis类型数据,这个Jedis类型的数据就是建立好的一个链接
  • 通过这个Jedis连接来进行编写代码,最简单的一个代码用来验证是否连接上了,如上:jedis.ping(),如果返回值为pong,那么说明连接成功,如代码:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
PONG

Process finished with exit code 0

         最开始安装Redis的时候,要配置绑定的ip,以及关闭保护模式。下面来看看如何操作:

  • 找到Redis的配置文件:redis.conf,然后打开
  • 找到bind选项:

    这里默认绑定的是127.0.0.1,此时只能本机和本机访问,不能跨主机访问。应该将其改为图所示的0.0.0.0
  • 关闭保护模式,首先找到redis.conf配置文件中的protected-mode

    这里默认是yes,如果是yes的话就是开启保护模式,跨主机也是不能访问的。将其设置为no。

警告:当前的使用java代码和ssh转发进行的redis服务器访问操作仅限于开发阶段,实际情况就需要根据实际情况来修改ip。


客户端的使用 

         下面就将介绍jedis中的通用命令:

  • get/set
  • exists
  • del
  • keys
  • expire /ttl
  • type
  • ......

        接下来的介绍不会覆盖到所有的命令,这里只是介绍到比较重要的、具有代表性的命令进行演示。

get / set

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.swing.*;

public class RedisDemo {
    public static void test1(Jedis jedis) {
        System.out.println("jedis的get和set的使用");
        // 先清空数据库(避免上一组数据对本次测试的影响)
        jedis.flushAll(); // 此命令就相当于Redis中的flushall

        // 使用set
        jedis.set("key","111");
        jedis.set("key2","222");

        // 进行get
        System.out.println("key: " + jedis.get("key"));
        System.out.println("key2: "+jedis.get("key2"));


    }
    public static void main(String[] args) {
        // 连接到redis 服务器.
        JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");

        // 从redis池中取出一个连接来
        try (Jedis  jedis = jedisPool.getResource()) {
            // Redis各种命令就对应到Jedis对象的各种方法,调用方法,就相当于执行命令.
            test1(jedis);
        }
    }
}

         注意看,在编写set的时候,你会发现,这里的set有很多重载的方法,例如:

        除了指定keyvalue 的方法,还可以设置一个参数,这个参数的类型是SetParams。

        首先我们先new一个SetParams,并创建其对象。

        可以看见里面提供了很多方法:

  • 其中有一个ex的方法可以用于设置超时时间,单位是秒,这里不做过多讲解。 
  • nx():用于对不存在的数据进行操作,只会添加数据,不会更新数据
  • xx():用于已经存在的数据,才能够进行修改。
    public static void test1(Jedis jedis) {
        System.out.println("jedis的get和set的使用");
        // 先清空数据库(避免上一组数据对本次测试的影响)
        jedis.flushAll(); // 此命令就相当于Redis中的flushall

        // 使用set
        SetParams params = new SetParams();
        params.ex(10);
        params.xx();
        jedis.set("key","111",params);
        // 进行get
        System.out.println(jedis.get("key"));

    }

        执行test1方法,就会出现:

        因为设置了xx参数,代表只会对已经存在的数据进行修改,但是此时的set操作当前的key是不存在的,所以get返回一个空。 

exists / del 

        实例:

    public static void test2(Jedis jedis) {
        System.out.println("exists 和 del的使用");
        jedis.flushAll(); // 此命令就相当于Redis中的flushall

        // 首先set两个key
        jedis.set("key1","111");
        jedis.set("key2","222");

        System.out.println(jedis.exists("key1")); // 已经设置,打印true
        System.out.println(jedis.exists("key2")); // 已经设置,打印true
        System.out.println(jedis.exists("key3")); // 没有设置,打印false

        long ret = jedis.del("key1"); // 成功删除key1这一个健,返回1
        // del 返回long类型表示成功返回多少个元素.
        System.out.println(ret);

        // 判定这个被删除的key1是否存在
        boolean retEx = jedis.exists("key1"); // 已经被删除,返回false.
        System.out.println(retEx);

        // 如果要删除多个key: jedis.del("key1","key2","key3", ... )
    }

         Jedis的方法exists,如果key已经存在,那么返回值为boolean类型的true,如果不存在则返回false。del则是删除已经存在的key,返回值为long类型,表示删除key的个数。

        当然del还支持多个key同时删除:

jedis.del("key1","key2","key3", ... )

keys

    public static void test3(Jedis jedis) {
        System.out.println("keys* 的使用");
        jedis.flushAll(); // 此命令就相当于Redis中的flushall

        // 设置四个key
        jedis.set("key1","1");
        jedis.set("key2","2");
        jedis.set("key3","3");
        jedis.set("key4","4");

        // 使用keysm,参数为pattern,通过特定格式的字符串来匹配符合要求的key,其中最简单的就是*,表示匹配任意结果
        Set<String> set = jedis.keys("*");

        // 这里使用set表示,是因为set里面的key是不能重复的
        System.out.println(set);
    }

         调用test3(),输出:

expire /ttl 

    public static void test4(Jedis jedis) {
        System.out.println("expire / ttl* 的使用");
        jedis.flushAll(); // 此命令就相当于Redis中的flushall

        jedis.set("key","111");
        jedis.expire("key",10);  // expire的第一个参数是key,第二个参数是long类型.表示秒

        // ttl 判断一个key还有多少过期时间,返回类型为long
        long time = jedis.ttl("key");
        System.out.println(time);

        // 休眠三秒
        try {
            Thread.sleep(Long.parseLong("3000"));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        // 再次ttl查看多少秒
        System.out.println(jedis.ttl("key"));
    }

输出:

 

        这里有延迟,说明服务器有延迟。 

  • expire:给存活的key设置一个过期时间,有两个参数,第一个参数是key对象,第二个 参数是long类型的数字,表示存活多少秒
  • ttl:查看一个key的存活时间,返回类型为long类型,表示还剩多少秒。

type

    public static void test5(Jedis jedis) {
        System.out.println("type 的使用");
        jedis.flushAll(); // 此命令就相当于Redis中的flushall

        // type: 查看一个key的value是什么类型
        jedis.set("key","111");
        String type = jedis.type("key");
        System.out.println(type);

        jedis.lpush("list","111","222","333");
        System.out.println(jedis.type("list"));
    }

字符串命令 

  • get/set 
  • mget /mset
  • getrange和setrange
  • append
  • incr 、decr

mget / mset

    public static void test1(Jedis jedis) {
        System.out.println("mget,mset");
        jedis.flushAll();

        jedis.mset("key1","111","key2","222","key3","333");

        // 返回值为 List<String>
        List<String> list = jedis.mget("key1","key2","key3","key100");
        System.out.println("values:" + list);
    }

输出:

        如果没有找到,那么使用null来表示。

getrange /setrange 

    public static void test2(Jedis jedis) {
        System.out.println("mget,mset");
        jedis.flushAll();

        jedis.set("key","0123456789");
        // 有三个参数,第一个参数用来指定key,第二个和第三个参数用来指定范围,类型都是long,这里的下标可以理解为字符串的charAt()
        System.out.println(jedis.getrange("key", 0, 4));
        System.out.println(jedis.getrange("key",1,8));

        jedis.setrange("key",9,"xxx");
        System.out.println(jedis.get("key"));
    }

 append

    public static void test3(Jedis jedis) {
        System.out.println("append");
        jedis.flushAll();

        jedis.set("key","abcdef");
        jedis.append("key","ghijk");

        String val = jedis.get("key");
        System.out.println(val);
    }

 输出:

incr / decr

    public static void test4(Jedis jedis) {
        System.out.println("incr / decr");
        jedis.flushAll();

        jedis.set("key","100");
        long ret = jedis.incr("key");
        System.out.println(ret);

        ret = jedis.decr("key");
        System.out.println(ret);
    }

输出:

  • 他们两个的返回值都是执行命令之后的结果。
  • 除了incr和decr之外,还有很多,例如:

    这些就不做过多的讲解,可以自己参考上面的例子进行演示。 

列表list 

  • lpush / lpop / lrange
  • rpush / rpop 
  • blpop / brpop
  • llen

push / pop / lrange

    public static void test1(Jedis jedis) {
        System.out.println("lpush 和 lrange");
        jedis.flushAll();

        // 头插
        jedis.lpush("key","111","222","333","444");

        // 尾插
        jedis.rpush("key","000");
        List<String> list = jedis.lrange("key",0,-1);
        System.out.println(list);

        // 弹出444和000
        jedis.lpop("key");
        jedis.rpop("key");

        list  = jedis.lrange("key",0,-1);
        System.out.println(list);
    }

输出:

blpop/brpop

        首先创建一个延迟100秒的brpop并执行:

    public static void test2(Jedis jedis) {
        System.out.println("brpop");
        jedis.flushAll();

        // 返回结果是一个二元组,一个是从哪个key对应的list中删除,另外一个是删除的是什么
        List<String> list = jedis.brpop(100,"key");
        System.out.println(list);
    }

        首先输出:

        然后在设置的100s内,打开redis客户端,set一个key:

        此时idea控制台输出:

["key","111"]

        blpop同理。

llen

        求列表的长度:

    public static void test3(Jedis jedis) {
        System.out.println("llen");
        jedis.flushAll();

        jedis.lpush("key","111","222","333");
        long len = jedis.llen("key");
        System.out.println(len);
    }

 输出:

  • llen返回值为long类型。
  • 返回值表示列表中元素的个数。

集合set

  •  sadd, smembers
  • sismember
  • scard
  • spop
  • sinter, sinterstore

sadd

public class JedisSet {
    public static void test1(Jedis jedis) {
        System.out.println("sadd");
        jedis.flushAll();

        jedis.sadd("key","1","2","3","4");
        Set<String> set  = jedis.smembers("key");
        System.out.println(set);
    }
    public static void main(String[] args) {
        JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
        try(Jedis jedis = jedisPool.getResource()) {
            test1(jedis);
        }
    }
}

 输出:

sismember 

    public static void test2(Jedis jedis) {
        System.out.println("sadd");
        jedis.flushAll();
        long ret = jedis.sadd("key","1","2","3","4");

        System.out.println(jedis.sismember("key", "1"));
        System.out.println(jedis.sismember("key", "10"));
    }

 

scard 

    public static void test3(Jedis jedis ){
        System.out.println("scard");
        jedis.flushAll();

        long ret = jedis.sadd("key","1","2","3","4");
        long nums = jedis.scard("key");
        System.out.println(nums);
    }

 

spop 

    public static void test4(Jedis jedis) {
        System.out.println("spop");
        jedis.flushAll();

        long ret = jedis.sadd("key","1","2","3","4");
        String res = jedis.spop("key");
        System.out.println(res);

    }

 输出:

sinter 

    public static void test5(Jedis jedis) {
        System.out.println("sinter");
        jedis.flushAll();

        jedis.sadd("key1","1","2","3");
        jedis.sadd("key2","2","3","4");

        Set<String> set = jedis.sinter("key1","key2");

        System.out.println(set);
    }

 

sinterstore 

    public static void test6(Jedis jedis) {
        System.out.println("sinterstore");
        jedis.flushAll();
        jedis.sadd("key1","1","2","3");
        jedis.sadd("key2","2","3","4");

        long nums = jedis.sinterstore("key3","key1","key2");
        System.out.println(nums);
        System.out.println(jedis.smembers("key3"));

    }

 

hash 

  • hset / hget
  • hexists
  • hdel
  • hkeys
  • hvals
  • hmget / hmset 

hset / hget 

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.HashMap;
import java.util.Map;

public class JedisHash {
    public static void testHgetAndHset(Jedis jedis) {
        System.out.println("hset和hget");
        jedis.flushAll();

        // 每次都只设置一次 key的filed和value
        jedis.hset("key","f1","v1");
        jedis.hset("key","f2","v2");
        jedis.hset("key","f3","v3");
        jedis.hset("key","f4","v4");

        // 一次性设置多个key的field
        Map<String, String> map = new HashMap<>();
        map.put("f5","v5");
        map.put("f6","v6");
        jedis.hset("key",map);

        // 获取
        String res = jedis.hget("key","f1");
        System.out.println(res);

        // 尝试获取不存在的
        res = jedis.hget("key","f100");
        System.out.println(res);
    }
    public static void main(String[] args) {
        JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
        try(Jedis jedis = jedisPool.getResource()) {
            testHgetAndHset(jedis);
        }

    }
}

 输出:

hexists

    public static void testHexists(Jedis jedis) {
        System.out.println("hexists");
        jedis.flushAll();

        jedis.hset("key","f1","v1");
        jedis.hset("key","f2","v2");
        jedis.hset("key","f3","v3");

        System.out.println(jedis.hexists("key","f1"));
        System.out.println(jedis.hexists("key","f2"));
        System.out.println(jedis.hexists("key","f100"));
    }

hdel

 public static void testHdel(Jedis jedis) {
        System.out.println("hdel");
        jedis.flushAll();
        jedis.hset("key","f1","v1");
        jedis.hset("key","f2","v2");
        jedis.hset("key","f3","v3");

        // 删除key中的f3
        jedis.hdel("key","f3");
        // 使用hexists查看是否存在
        System.out.println(jedis.hexists("key", "f3"));

        // 同时hdel可以同时删除多个
        long ret = jedis.hdel("key","f1","f2");

        System.out.println(jedis.hexists("key", "f1"));
        System.out.println(jedis.hexists("key", "f2"));
        System.out.println("一共被删除" + ret + "个field");
    }

 

hkeys / hvals

    public static void testHkeysAndHvals(Jedis jedis) {
        System.out.println("hkeys and hvals");
        jedis.flushAll();

        jedis.hset("key","f1","v1");
        jedis.hset("key","f2","v2");
        jedis.hset("key","f3","v3");

        // 使用hkeys获取所有的key
        System.out.println("获取所有的key");
        Set<String> set = jedis.hkeys("key");
        System.out.println(set);

        // 使用hvals获取所有的val
        System.out.println("获取所有的val");
        List<String> list = jedis.hvals("key");
        System.out.println(list);
    }

 有序集合zset

  • zadd
  • zrange
  • zcard
  • zrem
  • zscore
  • zrank

zadd

    public static void testZaddAndZrange(Jedis jedis) {
        System.out.println("zadd / zrange");
        jedis.flushAll();

        // 一次性添加一个元素
        jedis.zadd("key", 10.0,"zhangsan");

        // 一次性添加多个元素
        Map<String,Double> map = new HashMap<>();
        map.put("lisi",11.3);
        map.put("wangwu",13.5);
        jedis.zadd("key",map);

        // 使用zrange查看
        List<String> list = jedis.zrange("key",0, -1);
        System.out.println(list);

        // 携带分数score:zrangeWithScores
        List<Tuple> listWithScores = jedis.zrangeWithScores("key", 0, -1);
        System.out.println(listWithScores);

        // 获取listWithScores中的元素
        String member = listWithScores.get(0).getElement();
        double score = listWithScores.get(0).getScore();
        System.out.println("member:" + member + ",score:" + score);
    }

 

  • Tuple是Jedis或者说是Redis依赖中所携带的类,不是java本身自带的库.

        Jedis中的Tuple类是一个用于存储键值对的简单数据结构。它包含两个泛型字段:key和value。key字段用于存储键,而value字段用于存储与键关联的值。Tuple类主要用于在Redis中存储和操作键值对数据。

以下是一个简单的示例:

import redis.clients.jedis.Tuple;

public class JedisTupleExample {
    public static void main(String[] args) {
        // 创建一个Tuple对象
        Tuple<String, String> tuple = new Tuple<>("name", "张三");

        // 获取键和值
        String key = tuple.getKey();
        String value = tuple.getValue();

        System.out.println("Key: " + key);
        System.out.println("Value: " + value);
    }
}

        在这个示例中,我们创建了一个包含键"name"和值"张三"的Tuple对象。然后,我们使用getKey()和getValue()方法分别获取键和值,并将它们打印到控制台。 

        下面是Tuple的原码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package redis.clients.jedis.resps;

import java.util.Arrays;
import java.util.Objects;
import redis.clients.jedis.util.ByteArrayComparator;
import redis.clients.jedis.util.SafeEncoder;

public class Tuple implements Comparable<Tuple> {
    private byte[] element;
    private Double score;

    public Tuple(String element, Double score) {
        this(SafeEncoder.encode(element), score);
    }

    public Tuple(byte[] element, Double score) {
        this.element = element;
        this.score = score;
    }

    public int hashCode() {
        int prime = true;
        int result = 1;
        result = 31 * result;
        if (null != this.element) {
            byte[] var3 = this.element;
            int var4 = var3.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                byte b = var3[var5];
                result = 31 * result + b;
            }
        }

        long temp = Double.doubleToLongBits(this.score);
        result = 31 * result + (int)(temp ^ temp >>> 32);
        return result;
    }

    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        } else if (obj == this) {
            return true;
        } else if (!(obj instanceof Tuple)) {
            return false;
        } else {
            Tuple other = (Tuple)obj;
            return !Arrays.equals(this.element, other.element) ? false : Objects.equals(this.score, other.score);
        }
    }

    public int compareTo(Tuple other) {
        return compare(this, other);
    }

    public static int compare(Tuple t1, Tuple t2) {
        int compScore = Double.compare(t1.score, t2.score);
        return compScore != 0 ? compScore : ByteArrayComparator.compare(t1.element, t2.element);
    }

    public String getElement() {
        return null != this.element ? SafeEncoder.encode(this.element) : null;
    }

    public byte[] getBinaryElement() {
        return this.element;
    }

    public double getScore() {
        return this.score;
    }

    public String toString() {
        return '[' + SafeEncoder.encode(this.element) + ',' + this.score + ']';
    }
}

        里面提供了两个比较关键的数据一个是element,也就是member,另外一个就是score,也就是分数.

zcard

    public static void testZcard(Jedis jedis) {
        System.out.println("zcard");
        jedis.flushAll();

        Map<String,Double> map = new HashMap<>();
        map.put("lisi",11.3);
        map.put("wangwu",13.5);
        map.put("zhangsan", 10.5);
        jedis.zadd("key",map);
        long ret = jedis.zcard("key");
        System.out.println(ret);
    }

zrem

    public static void testZrem(Jedis jedis) {
        System.out.println("zrem");
        jedis.flushAll();

        Map<String,Double> map = new HashMap<>();
        map.put("lisi",11.3);
        map.put("wangwu",13.5);
        map.put("zhangsan", 10.5);
        jedis.zadd("key",map);

        long  n = jedis.zrem("key","zhangsan");
        System.out.println("删除的个数:" + n);

        System.out.println(jedis.zrangeWithScores("key", 0, -1));
    }

 

zscore 

    public static void testZscore(Jedis jedis) {
        System.out.println("zscore");
        jedis.flushAll();

        Map<String,Double> map = new HashMap<>();
        map.put("lisi",11.3);
        map.put("wangwu",13.5);
        map.put("zhangsan", 10.5);
        jedis.zadd("key",map);

        double ret = jedis.zscore("key","lisi");
        System.out.println(ret);
         ret = jedis.zscore("key","wangwu");
        System.out.println(ret);
         ret = jedis.zscore("key","zhangsan");
        System.out.println(ret);
    }

 

 zrank

   public static void testZrank(Jedis jedis) {
        System.out.println("zrank");
        jedis.flushAll();

        Map<String,Double> map = new HashMap<>();
        map.put("lisi",11.3);
        map.put("wangwu",13.5);
        map.put("zhangsan", 10.5);
        jedis.zadd("key",map);

        long rankLisi = jedis.zrank("key","lisi");
        
        long rankwangwu = jedis.zrank("key","wangwu");
        long rankzhangsan = jedis.zrank("key","zhangsan");
        System.out.println("lisi分数:" + jedis.zscore("key","lisi") + ", 排名:" +rankLisi);
        System.out.println("wangwu分数:" + jedis.zscore("key","wangwu") + ", 排名:" +rankwangwu);
        System.out.println("zhangsan分数:" + jedis.zscore("key","zhangsan") + ", 排名:" +rankzhangsan);
    }

如果指定一个不存在的member,会出现异常:

Exception in thread "main" java.lang.NullPointerException
	at JedisZset.testZrank(JedisZset.java:96)
	at JedisZset.main(JedisZset.java:110)

 本章完结 ... ..


http://www.kler.cn/a/234982.html

相关文章:

  • RunCam WiFiLink连接手机图传测试
  • UE UMG 多级弹出菜单踩坑
  • linux zip unzip 命令的使用
  • 【Tomcat】第六站(最后一站啦!):数据的返回
  • C语言编程1.27汉诺塔
  • web自动化测试知识总结
  • HarmonyOS 横屏调试与真机横屏运行
  • Spring Boot生成二维码的两种实现方式
  • 使用 Windows 11/10 上的最佳 PDF 转 Word 转换器释放 PDF 的潜力
  • 没更新的日子也在努力呀,布局2024!
  • sql常用函数积累(非窗口函数)
  • 从MySQL到TiDB:兼容性全解析
  • Linux(Ubuntu) 环境搭建:MySQL
  • Python中使用opencv-python进行人脸检测
  • Conda历史版本下载地址和python对应关系
  • 73. 矩阵置零(Java)
  • 泽攸科技ZEM系列台扫助力环境科研创新:可见光催化抗生素降解的探索
  • lua脚本动态插入script标签 在nginx层面
  • (附源码)ssm面向过程性考核的高校课程实验系统-计算机毕设 00941
  • 单片机——FLASH(2)
  • 单页404源码
  • 【ES】--Elasticsearch的分词器深度研究
  • 大数据应用对企业的价值
  • 《二叉树》——4(Leetcode题目练习)
  • ChatGPT升级至GPT-4 Turbo:性能升级同时更为经济
  • 根据三维点坐标使用matplotlib绘制路径轨迹