Springboot整合redis+jedis

2023-11-09

Spring Boot整合Redis+Jedis

1)在pom.xml添加Redis依赖Jedis依赖和,示例代码如下

      <!--  <version>2.1.5.RELEASE</version>Springboot版本 -->
      
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

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

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

       <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

2)配置文件application.properties。

server.port=8088

spring.redis.database=0
spring.redis.host=192.168.221.150
spring.redis.port=6379
spring.redis.password=
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-wait=-1000
spring.redis.jedis.pool.max-idle=500
spring.redis.jedis.pool.min-idle=0
spring.redis.timeout=100000

3)  Liunx启动redis

1.进入bin目录启动命令
./redis-server &

2.关闭redis的保护模式,先连接redis
./redis-cli -h 127.0.0.1 -p 6379

3.连接成功设置关闭redis保护模式
config set protected-mode "no"

4)  配置Config类

@Configuration
public class RedisConfig {

        //读取配置文件中的redis的ip地址
        @Value("${spring.redis.host}")
        private String host;

        @Value("${spring.redis.port:0}")
        private int port;

        @Value("${spring.redis.database:0}")
        private int database;

        @Bean
        public RedisUtil getRedisUtil(){
            if(host.equals("disabled")){
                return null;
            }
            RedisUtil redisUtil=new RedisUtil();
            redisUtil.initPool(host,port,database);
            return redisUtil;
        }
}

5)  编写jedis工具类

public class RedisUtil {
    private JedisPool jedisPool;

    public void initPool(String host,int port ,int database){
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(200);
        poolConfig.setMaxIdle(30);
        poolConfig.setBlockWhenExhausted(true);
        poolConfig.setMaxWaitMillis(10*1000);
        poolConfig.setTestOnBorrow(true);
        jedisPool=new JedisPool(poolConfig,host,port,20*1000);
    }

    public Jedis getJedis(){
        Jedis jedis = jedisPool.getResource();
        return jedis;
    }
}

6)  测试添加缓存数据

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class SpringbootRedisApplicationTests {

    @Autowired
    RedisUtil redisUtil;

    @Test
    public void TestRedis() {
        Jedis jedis = redisUtil.getJedis();
        String test = jedis.set("test", "123");
        System.out.println(test);
        String s = jedis.get("test");
        System.out.println(s);
    }

}

7)jedis操作Api

 @Test
    public void test16() {
        //jedis操作Hash
        Jedis jedis = redisUtil.getJedis();
        Long hset = jedis.hset("bb", "String", "12456");//设置key在String域中有了返回0,域中没有相同的返回1
        Long hset2 = jedis.hset("ss", "String2", "12456");
        Long hset3 = jedis.hset("ss", "String", "123");
        System.out.println(hset2);
        System.out.println(hset);
        String hget = jedis.hget("ss", "String");//根据key到那个域中取值
        System.out.println(hget);
        Boolean aBoolean = jedis.hexists("sss", "String");//判断key是否在那个域中。
        System.out.println(aBoolean);
        Map<String, String> map = jedis.hgetAll("ss");//从所有域中获取为key的值。
        System.out.println(map);
        Long hdel = jedis.hdel("ss", "String");//从哪个些域(多个域中删除)中删除为key的,删除多少条数据返回的数就是多少。
        System.out.println(hdel);
    }

    @Test
    public void test17() {
        //jedis操作String
        Jedis jedis = redisUtil.getJedis();

        jedis.set("name", "king james");//添加一条数据

        jedis.get("name");//根据key找到对应的value的值

        jedis.set("name", "kobe bryant");//再次设置:对一个key多次赋值的话,key对应的值是最后一次赋值的值,之前的被覆盖。

        jedis.append("name", "  is my love");//字符串拼接

        jedis.del("name");//删除某个键

        jedis.mset("name", "king james", "age", "33", "country", "American");//同时设置多个键值对:获取值的方式同上

        jedis.incr("age");//假如值里面有数字(字符串形式),可以进行+1的操作    age的值变成34

        jedis.decr("age");//进行-1的操作

        jedis.incrBy("age", 20);//某个值增加多少:这里是+20

        jedis.decrBy("age", 20);//某个值减少多少:这里是-20

        jedis.exists("name");//判断是否存在某个key

        jedis.setex("name", 5, "king james");//设置值的时间:存在5s
        //查询值的存活时间:当 key不存在时,返回 -2,当key存在但没有设置剩余生存时间时,返回-1,否则,以秒为单位,返回key的剩余生存时间。
        Long ttl = jedis.ttl("name");

        jedis.persist("name");//去掉key的时间设置:不再有失效时间

        //设置该值不能重复设置(nx),该值的过期时间5分钟,设置成功返回大小OK,重复设置返回null
        String rest = jedis.set("userid2", "1", "nx", "px", 60 * 5 * 1000);

        System.out.println(rest);
    }

    @Test
    public void test18() {
        //jedis操作List集合
        Jedis jedis = redisUtil.getJedis();

        jedis.lpush("users", "king james");//保存数据:lpush-->left push
        jedis.lpush("users", "kobe bryant");
        jedis.lpush("users", "stephen curry");
        jedis.lpush("users", "Kevin Durant");
        //查询:第一个值是key,第二个值表示从0开始,第三个值表示结束(-1表示取全部)
        //userListA当中的值排列情况:["Kevin Durant","stephen curry","kobe bryant","king james"]
        List<String> userListA = jedis.lrange("users", 0, -1);

        jedis.rpush("users", "Wilt Chamberlain");//保存数据:rpush-->right push
        jedis.rpush("users", "John Smith");
        jedis.rpush("users", "Karl Malone");
        //查询:第一个值是key,第二个值表示从0开始,第三个值表示结束(-1表示取全部)
        //userListB当中值排列情况:["Kevin Durant","stephen curry","kobe bryant","king james","Wilt Chamberlain","John Smith","Karl Malone"]
        List<String> userListB = jedis.lrange("users", 0, -1);
        //移除并返回列表key的头元素:lpop-->left pop
        String nameA = jedis.lpop("users");//Kevin Durant
        //移除并返回列表key的尾元素:rpop-->right pop
        String nameB = jedis.rpop("users");//Karl Malone
        //删除key
        jedis.del("users");
        //给特定位置赋值
        jedis.lset("users", 1, "Yao Ming");
        //查询特定位置的值:idnex从0开始
        jedis.lindex("users", 1);
        //对list进行裁剪:只保留下标1-3的值,其他的全部删除,下标从0开始
        jedis.ltrim("users", 1, 3);
        //返回list的长度
        jedis.llen("users");
        //根据参数count的值,移除列表中与参数value相等的元素。
        //count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
        //count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
        //count = 0 : 移除表中所有与 value 相等的值。
        jedis.lrem("users", 2, "king james");
        /**
         * ("key","LIST_POSITION","pivot","value")
         * LINSERT key BEFORE|AFTER pivot value
         * 将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。
         * 当 pivot 不存在于列表 key 时,不执行任何操作。
         * 当 key 不存在时, key 被视为空列表,不执行任何操作。
         * 如果 key 不是列表类型,返回一个错误。
         */
        jedis.linsert("users", BinaryClient.LIST_POSITION.AFTER, "Yao Ming", "AAAA");
        //从users的右边弹出一个元素,把该元素左插入到players列表当中
        jedis.rpoplpush("users", "players");

    }

    @Test
    public void test19() {
        //jedis操作set集合
        Jedis jedis = redisUtil.getJedis();
        //操作Set集合:和列表不同,集合中的元素是无序的,因此元素也不能重复。
        jedis.sadd("users", "king james");
        jedis.sadd("users", "kobe bryant");
        jedis.sadd("users", "stephen curry");
        jedis.sadd("users", "Kevin Durant");
        Set<String> users = jedis.smembers("users");//查询users里面的所有数据

        jedis.srem("users", "Kevin Durant");//移除users当中的某个元素

        Long size = jedis.scard("users");//获取users当中的元素个数

        jedis.spop("users");//随机移除users当中的一个元素

        jedis.srandmember("users");//返回users里面的一个随机元素

        /**
         * 从users当中返回一个长度为3的随机数组。
         * 当数字大于0时,list里面元素都不相同,小于0时,元素可能相同,长度为count的绝对值
         */
        List<String> list = jedis.srandmember("users", 3);
        Boolean isMember = jedis.sismember("users", "king james");//判断users里面是否含有某个元素

        jedis.sadd("players", "Yao Ming", "Wilt Chamberlain", "Karl Malone");//批量插入数据

        Set<String> sinter = jedis.sinter("users", "players");//交集

        Set<String> sdiff = jedis.sdiff("users", "players");//差集

        Set<String> sunion = jedis.sunion("users", "players");//并集

        jedis.smove("users", "players", "king james");//把users当中的king james 移动到players当中

    }

    @Test
    public void test20() {
        //jedis操作Zset集合
        Jedis jedis = redisUtil.getJedis();

        //操作有序Set
        jedis.zadd("users", 10, "king james");//新增:根据“第二个参数(score)”进行排序。

        jedis.zadd("users", 20, "king james");//元素相同时,更新为当前的排序数

        Set<String> usersA = jedis.zrange("users", 0, -1);//查询users里面的所有元素

        jedis.zcard("users");//查询当前set集合的元素个数

        jedis.zcount("users", 10, 20);//返回users集合里面,score 值在min和max之间(包括)元素个数

        jedis.zrem("users", "king james");//移除users中的一个或多个成员,不存在的成员将被忽略。

        //移除users当中第0到第1之间的元素(包含),也可以是负数:以 -1 表示最后一个成员, -2 表示倒数第二个成员
        jedis.zremrangeByRank("users", 0, 3);
        jedis.zremrangeByScore("users", 10, 20);//移除users当中score值在min和max之间(包括)元素

        jedis.zscore("users", "king james");//返回某个元素的score值

        jedis.zrangeByScore("users", 10, 20);//返回有序集users中,所有score值介于min和max之间(包括)的元素

        long rank = jedis.zrank("users", "king james");//返回元素king james在users当中的序号,排第一位0

    }

    @Test
    public void test21() {
        //jedis操作HashMap集合
        Jedis jedis = redisUtil.getJedis();
        //操作HashMap
        Map<String, String> map = Maps.newHashMap();
        map.put("Cleveland Cavaliers", "King James");
        map.put("Los Angeles", "Kobe Bryant");
        map.put("Memphis Grizzlies", "Mike Conley");
        map.put("Miami Heat", "Goran Dragic");
        map.put("Golden State Warriors", "Stephen Curry");

        jedis.hmset("NBA", map);//设置值

        //根据map当中的key,去查询key对应的value
        List<String> MVP = jedis.hmget("NBA", "Los Angeles", "Cleveland Cavaliers");
        jedis.hdel("NBA", "Miami Heat");//删除某个key对应的value

        jedis.hlen("NBA");//返回NBA当中map的键值对的数量

        jedis.exists("NBA");//是否存在NBA这个key

        Set<String> teams = jedis.hkeys("NBA");//返回NBA当中map的所有的key

        List<String> players = jedis.hvals("NBA");//返回NBA当中所有的key对应value的值

        Map<String, String> map1 = jedis.hgetAll("NBA");//返回NBA当中对应的map的值

    }

    @Test
    public void test22() {
        //jedis操作其他
        Jedis jedis = redisUtil.getJedis();
        //通用操作
        jedis.del("NBA");//删除

        jedis.exists("NBA");//存在检测

        jedis.expire("NBA", 600);//设置key的过期时间,单位为秒

        jedis.expireAt("NBA", System.currentTimeMillis() + 30 * 1000);//设置key在那个时间点过期

        Set<String> keys = jedis.keys("*");//获取redis当中的所有的key值

        jedis.move("NBA", 1);//当前数据库的key移动到给定的数据库db当中。

        jedis.persist("NBA");//移除给定key的生存时间

        jedis.pttl("NBA");//以毫秒为单位返回 key 的剩余生存时间

        jedis.ttl("NBA");//以秒为单位返回 key 的剩余生存时间

        jedis.randomKey();//从当前数据库中随机返回(不删除)一个 key

        jedis.rename("NBA", "CBA");//将 key 改名为 newkey

        jedis.renamenx("NBA", "CBA");//当且仅当 newkey 不存在时,将 key 改名为 newkey

        jedis.type("NBA");//返回 key 所储存的值的类型

    }

个人推荐使用Jedis来操作Redis,因为jedis性能比redisTemplate性能更好读写更快。

 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Springboot整合redis+jedis 的相关文章

  • Eclipse 在源代码管理中保存操作

    我们希望找到一种在签入之前执行代码标准的 轻量级 方法 我们真的很喜欢使用 Eclipse 内置的想法保存操作 go to Preferences gt gt Java gt gt Editor gt gt Save Actions 其中有
  • 如何创建一个显示 Spinners 的 x 和 y 值的表格?

    我想创建一个位于图表右侧的表格 其中显示 2 列 x 和 y 值已输入到xSpin and ySpin旋转器 我已经画了一张我想要桌子放置的位置的图 我尝试过在网格窗格布局中使用文本框来创建表格并将值直接输入到文本框网格中 但是我无法将它们
  • Java:迭代 Collection 的最佳方法(此处为 ArrayList)

    今天 当我看到一段我已经使用了数百次的代码时 我很高兴地开始编码 迭代集合 此处为 ArrayList 出于某种原因 我实际上查看了 Eclipse 的自动完成选项 这让我想知道 在什么情况下以下循环比其他循环更好使用 经典的数组索引循环
  • Java:如何从转义的 URL 获取文件?

    我收到了一个定位本地文件的 URL 事实上我收到的 URL 不在我的控制范围内 URL 按照 RFC2396 中的定义进行有效转义 如何将其转换为 Java File 对象 有趣的是 URL getFile 方法返回一个字符串 而不是文件
  • 运行具有外部依赖项的 Scala 脚本

    我在 Users joe scala lib 下有以下 jar commons codec 1 4 jar httpclient 4 1 1 jar httpcore 4 1 jar commons logging 1 1 1 jar ht
  • wait() 在游戏中如何工作?

    在 playframework 的文档中here http www playframework org documentation 1 2 1 asynchronous已写 public static void loopWithoutBlo
  • 如何在不超过最大值的情况下增加变量?

    我正在为学校开发一个简单的视频游戏程序 我创建了一个方法 如果调用该方法 玩家将获得 15 点生命值 我必须将生命值保持在最大值 100 并且由于我目前的编程能力有限 我正在做这样的事情 public void getHealed if h
  • Cassandra java驱动程序协议版本和连接限制不匹配

    我使用的java驱动程序版本 2 1 4卡桑德拉版本 dsc cassandra 2 1 10cql 的输出给出以下内容 cqlsh 5 0 1 Cassandra 2 1 10 CQL spec 3 2 1 Native protocol
  • 使用 AES SecretKey 的 Java KeyStore setEntry()

    我目前正在 Java 中开发一个密钥处理类 特别是使用 KeyStore 我正在尝试使用 AES 实例生成 SecretKey 然后使用 setEntry 方法将其放入 KeyStore 中 我已经包含了代码的相关部分 The KS Obj
  • 画透明圆,外面填充

    我有一个地图视图 我想在其上画一个圆圈以聚焦于给定区域 但我希望圆圈倒转 也就是说 圆的内部不是被填充 而是透明的 其他所有部分都被填充 请参阅这张图片了解我的意思 http i imgur com zxIMZ png 上半部分显示了我可以
  • Hazelcast 分布式锁与 iMap

    我们目前使用 Hazelcast 3 1 5 我有一个简单的分布式锁定机制 应该可以跨多个 JVM 节点提供线程安全性 代码非常简单 private static HazelcastInstance hInst getHazelcastIn
  • 在游戏视图下添加 admob

    我一直试图将 admob 放在我的游戏视图下 这是我的代码 public class HoodStarGame extends AndroidApplication Override public void onCreate Bundle
  • Jersey 客户端请求中未设置 Content-Length-Header

    我正在使用 Jersey Client 访问网络服务 如下所示 response r accept MediaType TEXT PLAIN TYPE header content length 0 post String class 其中
  • 如何知道抛出了哪个异常

    我正在对我们的代码库进行审查 有很多这样的陈述 try doSomething catch Exception e 但我想要一种方法来知道 doSomething 抛出了哪个异常 在 doSomething 的实现中没有 throw 语句
  • 测试弱引用

    在 Java 中测试弱引用的正确方法是什么 我最初的想法是执行以下操作 public class WeakReferenceTest public class Target private String value public Targe
  • 替换后增量

    我自己已经有一个问题了 但我想扩展它后增量示例 https stackoverflow com questions 51308967 post increment with example char a D int b 5 System o
  • Java中的Object类是什么?

    什么是或什么类型private Object obj Object http download oracle com javase 6 docs api java lang Object html是Java继承层次结构中每个类的最终祖先 从
  • Eclipse 中 Spring MVC 模型对象的 (jsp /jstl) 视图中的代码辅助

    在 Spring MVC 中 当将对象放置在视图模型中时 如下所示 public String getUser Model model fetch user model addAttribute user user return viewN
  • 为什么C++代码执行速度比java慢?

    我最近用 Java 编写了一个计算密集型算法 然后将其翻译为 C 令我惊讶的是 C 的执行速度要慢得多 我现在已经编写了一个更短的 Java 测试程序和一个相应的 C 程序 见下文 我的原始代码具有大量数组访问功能 测试代码也是如此 C 的
  • 为什么这个作业不起作用?

    我有课Results which extends ArrayList

随机推荐

  • Echarts 给pie圆饼图series.data 赋值

    1 如何去掉字符串最外层的双引号 使其变成数组 var data id 32 wd 20 3 jd 113 3 id 321 wd 20 3 jd 113 3 var yy var mm yy data split for var i 0
  • 数据挖掘算法与现实生活中的应用案例

    如何分辨出垃圾邮件 如何判断一笔交易是否属于欺诈 如何判断红酒的品质和档次 扫描王是如何做到文字识别的 如何判断佚名的著作是否出自某位名家之手 如何判断一个细胞是否属于肿瘤细胞 等等 这些问题似乎都很专业 都不太好回答 但是 如果了解一点点
  • 归因分析计算因子贡献度常见的方法

    在归因分析中 我们一般都需要计算出每个因子的贡献度是多少 比如产品DAU上升 对年龄段维度进行拆解 看是不同年龄段的用户对DAU上升的贡献度是多少 一般根据指标的类型 计算贡献度的方法也不一样 下面就列出一些常见的归因分析贡献度的计算方法
  • mt4服务器显示无连接,MT4登录显示“无效账户”,“无法连接”怎么解决

    MT4账户分为实盘账户和模拟账户 小编每天都会收到很多客户实盘账号登入不上去的申请 有的客户反应账户显示登录无效 或者无连接 没有数据流 客户就会问 是不是我的账号过期不能使用 其实不是的 账户登入不上有如下几个原因 首先我先要告诉大家 一
  • ISP(图像信号处理)算法概述、工作原理、架构、处理流程

    转自 https zhuanlan zhihu com p 115321553 ISP的主要内部构成 ISP内部包含 CPU SUP IP 各种功能模块的通称 IF 等设备 ISP的控制结构 1 ISP逻辑 2 运行在其上的firmware
  • ARM 浮点运算详解

    一 早期ARM上的浮点模拟器 早期的ARM没有协处理器 所以浮点运算是由CPU来模拟的 即所需浮点运算均在浮点运算模拟器 float math emulation 上进行 需要的浮点运算 常要耗费数千个循环才能执行完毕 因此特别缓慢 直到今
  • Vue路由中,history和hash两种模式有什么区别?

    前端路由有两种模式 hash 模式和 history 模式 接下来分析这两种模式的实现方式和优缺点 hash 模式 hash 模式是一种把前端路由的路径用井号 拼接在真实 URL 后面的模式 当井号 后面的路径发生变化时 浏览器并不会重新发
  • MySQL 表连接 JOIN

    参考 表连接 前言 建表语句 测试数据 一 表连接JOIN基础 1 什么是表连接 什么是JOIN 2 表连接的分类 2 1 内连接 2 2 外连接 2 3 等值连接 2 4 自然连接 前言 建表语句 表a CREATE TABLE a ta
  • C++迭代器作为参数传递进函数使用时的注意事项

    外部函数对迭代器进行值传递而非引用 需要注意的一点是在使用迭代器作为传入参数进行迭代器运算操作的时候 作用对象仅仅是对传入迭代器的拷贝 因为在传入迭代器后函数直接对传入的对象进行拷贝操作而不访问源对象的内存空间https blog csdn
  • html 线条外阴影,怎么添加阴影边框?

    本文介绍使用CSS添加阴影边框和word文档中添加阴影边框的方法 有一定的参考价值 有需要的朋友可以参考一下 希望对大家有所帮助 CSS添加阴影边框的方法 方法1 使用box shadow属性添加阴影边框 相关推荐 css在线手册 box
  • 程序员最全的Linux命令,不全来找我随时更新!

    一 引言 1 1 Linux引言 Linux是一套免费使用和自由传播的类Unix操作系统 是一个基于POSIX和Unix的多用户 多任务 支持多线程和多CPU的操作系统 伴随着互联网的发展 Linux得到了来自全世界软件爱好者 组织 公司的
  • 常见传感器和芯片的介绍

    文章目录 一 传感器 1 1 KY xxxx系列 KY 002 KY 003 KY 004 KY 005 KY 006 KY 007 KY 008 KY 009 KY 010 KY 011 KY 012 KY 013 KY 014 KY 0
  • 虚拟服务器ftp上传权限设置,13. 为 FTP虚拟用户设置“不同文件目录”和“访问权限”...

    Re FTP 文件传输服务 FTP 服务不论在企业或教学中 是很常用的文件共享方式 它既可以做到匿名访问 也可以做到用户名和密码访问 更可以做到只能提交但不能够访问的特殊要求等等功能 本课程将一一详细演示 FTP 服务器的一般应用场景在 企
  • check allInputDimensionsSpecified() for second profile fail

    目录 yolov7 tensorrt预测时报错 在python代码里 在调用engine推理前做这样的设置即可 yolov7修改后的tenorr
  • Java JUC概述

    Java JUC Java Util Concurrent 是 Java 平台提供的并发编程工具包 它提供了一系列的工具类和接口 用于简化多线程编程 JUC 中的类和接口都是基于 Java 平台的底层并发原语 如锁 信号量 原子变量等 实现
  • 机器视觉及其应用发展

    导读 一 机器视觉的研究和发展动态 机器视觉的研究 发展和应用还远没有达到成熟的程度 机器视觉从诞生到今天才只有短短的三十多年时间 在机器视觉中承担 大脑 作用的图像分析处理 图像理解和模式识别理论和技术基础还非常不完善 甚至 机器视觉的图
  • TextMeshPro 使用及性能

    目录 TextMeshPro 组件介绍 Main Setting Extra Setting 轮廓 阴影 外发光 表情混编使用 表情资源制作 中文字体制作 关于性能 TextMeshPro ps 第一次写博客 排版和表述可能有不尽人意的地方
  • 精选36道SQL练习题解析 from(原50道SQL练习题)

    SQL练习题 友情链接 1 医疗信息管理系统数据库 MySQL 2 邮件管理数据库设计 MySQL 3 SQL Server医疗信息管理系统数据库 英文版 源码 Medical Management System Database 4 SQ
  • 安装Homebrew——各种报错解决(2020-5-4亲测)

    国内安装Homebrew 2020 5 4亲测 今天安装Homebrew时 挂了VPN报错 curl 7 Failed to connect to raw githubusercontent com port 443 Connection
  • Springboot整合redis+jedis

    Spring Boot整合Redis Jedis 1 在pom xml添加Redis依赖Jedis依赖和 示例代码如下