SpringBoot使用Redis

1.Spring是如何集成Redis的?

Spring Data Redis

引入依赖

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

 </dependency>
 <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-pool2</artifactId>
 </dependency>

2.高级封装 

3.Redis配置

#Redis服务器地址
spring.redis.host=192.168.11.84
#Redis连接端口
spring.redis.port=6379
#Redis数据库索引(默认为0)
spring.redis.database=0
#Redis服务器的连接密码默认为空
spring.redis.password=
#连接超时时间
spring.redis.timeout=30000
#连接池最大的连接数(使用负值表示没有限制)默认为8
spring.redis.lettuce.pool.max-active=8
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=1
#连接池中最大空闲等待时间,3s没有活干的时候直接驱逐该链接
spring.redis.lettuce.pool.time-between-eviction-runs=3000
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1

4.StringRedisTemplate

String

@SpringBootTest
class StringTests {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Resource(name="redisTemplate")
    RedisTemplate<String,Student> redisTemplate;

    @Test
    public void test3() {
        Student student = Student.builder().id(1).name("海洋").build();
        redisTemplate.opsForValue().set("student.1",student);
//        stringRedisTemplate.opsForValue().set("Student."+student.getId(), JSONUtil.toJsonStr(student));
        Student student1 = redisTemplate.opsForValue().get("student.1");
        System.out.println(student1);
    }
    @Test  //设置过期时间
    public void test(){
//        stringRedisTemplate.opsForValue().set("海洋","帅呆了",30, TimeUnit.SECONDS);
        stringRedisTemplate.opsForValue().set("海洋","帅呆了",Duration.ofSeconds(30));
        String s = stringRedisTemplate.opsForValue().get("海洋");
        System.out.println(s);
    }
    @Test  //setnx(锁的竞争)
    public void test1() {
        Boolean haiyang = stringRedisTemplate.opsForValue().setIfAbsent("haiyang", "88");
    }
    @Test
    public void test2() {
        Long haiyang = stringRedisTemplate.opsForValue().increment("haiyang");
        Long haiyang1 = stringRedisTemplate.opsForValue().increment("haiyang", 20);
        Long haiyang2 = stringRedisTemplate.opsForValue().decrement("haiyang", 50);
    }

    @Test
    public void test4() {
        stringRedisTemplate.opsForValue().append("haiyang","酷");
    }
}

Hash

package com.by;

import com.by.model.Product;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;

@SpringBootTest
class HashTests {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Resource(name="redisTemplate")
    RedisTemplate<String, Product> redisTemplate;

    @Test
    public void test(){
        redisTemplate.opsForHash().put("手机","name","小米");
        redisTemplate.opsForHash().put("手机","age","6个月");
        Product product = Product.builder().id(1).name("手机").build();
        redisTemplate.opsForHash().put("手机","小米品牌手机",product);
    }
    @Test
    public void test1(){
        Object o = redisTemplate.opsForHash().get("手机", "name");
        System.out.println(o);
    }
    @Test
    public void test2(){
        Boolean aBoolean = redisTemplate.opsForHash().hasKey("手机", "name");
        Map<Object, Object> entries = redisTemplate.opsForHash().entries("手机");//key和value同时获取
    }
    @Test
    public void test3(){
        Set<Object> objects = redisTemplate.opsForHash().keys("手机");
    }
    @Test
    public void test4(){
        List<Object> values = redisTemplate.opsForHash().values("手机");
    }
    @Test
    public void test5(){
        Product product1 = Product.builder().id(1).name("小米手机").build();
        Product product2 = Product.builder().id(1).name("华为手机").build();
        redisTemplate.opsForHash().put("黑名单",String.valueOf(1),product1);
        redisTemplate.opsForHash().put("黑名单",String.valueOf(2),product2);
    }


}

List

@SpringBootTest
class ListTests {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Resource(name="redisTemplate")
    RedisTemplate<String, Product> redisTemplate;

    @Test
    public void test(){
        Product oppo1 = Product.builder().id(1).name("OPPO").build();
        Product oppo2 = Product.builder().id(2).name("OPPOX").build();
        redisTemplate.opsForList().leftPushAll("OPPO手机",oppo1,oppo2);
    }
    @Test
    public void test1(){
        Product oppo3 = Product.builder().id(3).name("OPPOB").build();
        redisTemplate.opsForList().leftPush("OPPO手机",oppo3);
    }

    @Test
    public void test2(){
      redisTemplate.opsForList().leftPop("OPPO手机");
    }
    @Test
    public void test3(){
        redisTemplate.opsForList().rightPop("OPPO手机");
    }
    @Test
    public void test4(){
        Product product = redisTemplate.opsForList().index("OPPO手机", 0);
        System.out.println(product);
    }
    @Test
    public void test5(){
        Long size = redisTemplate.opsForList().size("OPPO手机");
        System.out.println(size);
    }
    @Test
    void test6() {
        // 如果一些原生命令,spring 没有给我们封装,redisTemplate.execute(new RedisCallback)
        while (true){
            System.out.println("开始一轮监听");
            List<byte[]> rawResults = redisTemplate.execute(new RedisCallback<List<byte[]>>() {
                @Override
                public List<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
                    return connection.bRPop(10,"OPPO手机".getBytes());
                }
            });
            if(ObjUtil.isNotEmpty(rawResults)){
                byte[] rawKey = rawResults.get(0);
                byte[] rawValue = rawResults.get(1);
                Product product = (Product)redisTemplate.getValueSerializer().deserialize(rawValue);
                System.out.println(product);
            }
        }
    }
}

Set

package com.by;

import cn.hutool.core.util.ObjUtil;
import com.by.model.Product;
import com.by.model.Student;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;


@SpringBootTest
class SetTests {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Resource(name="redisTemplate")
    SetOperations<String, Student> setOperations;

    @Test//取差集
    void test(){
        stringRedisTemplate.opsForSet().add("海洋","语文","数学","英语","品德");
        stringRedisTemplate.opsForSet().add("洋洋","语文","数学","英语","美术");
        Set<String> difference = stringRedisTemplate.opsForSet().difference("海洋", "甜甜");
    }
    @Test//取交集
    void test1(){
        stringRedisTemplate.opsForSet().add("海洋","语文","数学","英语","品德");
        stringRedisTemplate.opsForSet().add("洋洋","语文","数学","英语","美术");
        Set<String> intersect = stringRedisTemplate.opsForSet().intersect("海洋", "甜甜");
    }
    @Test//取交集
    void test2(){
        stringRedisTemplate.opsForSet().add("海洋","语文","数学","英语","品德");
        stringRedisTemplate.opsForSet().add("洋洋","语文","数学","英语","美术");
        Set<String> union = stringRedisTemplate.opsForSet().union("海洋", "甜甜");
    }

}

Zset

@SpringBootTest
class ZSetTests {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Resource(name="redisTemplate")
    SetOperations<String, Student> setOperations;
    @Test
    void test(){
        stringRedisTemplate.opsForZSet().add("海洋","语文",80);
        stringRedisTemplate.opsForZSet().add("海洋","英语",60);
        stringRedisTemplate.opsForZSet().add("海洋","数学",70);
        Long aLong = stringRedisTemplate.opsForZSet().size("海洋");
        Long aLong1 = stringRedisTemplate.opsForZSet().removeRangeByScore("海洋", 60, 100);

    }
    @Test
    void test1(){
        stringRedisTemplate.opsForZSet().add("海洋","语文",80);
        stringRedisTemplate.opsForZSet().add("海洋","英语",60);
        stringRedisTemplate.opsForZSet().add("海洋","数学",70);
        Set<String> range1 = stringRedisTemplate.opsForZSet().range("海洋", 0,-1);
        Set<ZSetOperations.TypedTuple<String>> tuples = stringRedisTemplate.opsForZSet().rangeByScoreWithScores("海洋", 60, 100);
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores("海洋", 50, 100);//正序排列
    }

    @Test //模拟新闻点击量,排名
    void test2(){
        String key ="product.hot";
        ArrayList<Integer> productId = CollUtil.newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);//使用hutool中的工具,获取先的数组
        ExecutorService executorService = Executors.newFixedThreadPool(100);//jdk自带的线程池
        for (int i = 1; i <=100; i++) {
            executorService.submit(()->{
                int c = RandomUtil.randomInt(1, 11);//RandomUtil.randomInt 获得指定范围内的随机数,例如我们想产生一个[10, 100)的随机数
                System.out.println("访问了"+c);
                stringRedisTemplate.opsForZSet().incrementScore(key,String.valueOf(c),1);//每次访问,数据加一
            });
        }
        //因为是异步的,避免冲突
        ThreadUtil.safeSleep(5000);
        Set<String> strings = stringRedisTemplate.opsForZSet().reverseRange(key, 0, -1);
    }


}

BitMap

@SpringBootTest
class BitMapTests {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Resource(name="redisTemplate")
    RedisTemplate<String, Student> redisTemplate;
    private String key = "sing.2024.haiyang";

    @Test //签到
    void test(){
        Boolean b = stringRedisTemplate.opsForValue().setBit(key, 10, true);//设置某一天的偏移量,表示第10天的偏移量为1
         b = stringRedisTemplate.opsForValue().setBit(key, 30, true);
         b = stringRedisTemplate.opsForValue().setBit(key, 56, true);

        RedisCallback<Long> redisCallback = new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.bitCount(key.getBytes());
            }
        };
        Long execute = redisTemplate.execute(redisCallback);
    }
    @Test //车展,统计总的人数和这三天都来的人数
    void test1() {
        String key1 = "2024.3.28";
        String key2 = "2024.3.29";
        String key3 = "2024.3.30";
        int yangyang = 10, tiantian = 20, tangtang = 40;
        //第一天
        stringRedisTemplate.opsForValue().setBit(key1, yangyang, true);
        stringRedisTemplate.opsForValue().setBit(key1, tangtang, true);
        //第二天
        stringRedisTemplate.opsForValue().setBit(key2, yangyang, true);
        stringRedisTemplate.opsForValue().setBit(key2, tiantian, true);
        stringRedisTemplate.opsForValue().setBit(key2, tangtang, true);
        //第三天
        stringRedisTemplate.opsForValue().setBit(key3, yangyang, true);
        stringRedisTemplate.opsForValue().setBit(key3, tangtang, true);
        //Q1统计一共来了多少人
        String q1 = "q1";
        RedisCallback<Long> redisCallback = connection -> {
            return connection.bitOp(RedisStringCommands.BitOperation.OR, q1.getBytes(), key1.getBytes(), key2.getBytes(), key3.getBytes());
        };
        //将三天的key合并值放到q1的key中
        Long aLong = redisTemplate.execute(redisCallback);

        RedisCallback<Long> redisCallback2 = connection -> {
            return connection.bitCount(q1.getBytes());
        };
        //求q1里面1的总和
        Long execute = redisTemplate.execute(redisCallback2);
        //Q2:统计每天都来的人数
         String q2="q2";
        redisCallback = connection -> {
            return connection.bitOp(RedisStringCommands.BitOperation.AND, q2.getBytes(), key1.getBytes(), key2.getBytes(), key3.getBytes());
        };
        //将三天的key合并值放到q1的key中
        Long aLong1 = redisTemplate.execute(redisCallback);

        redisCallback2 = connection -> {
            return connection.bitCount(q2.getBytes());
        };
        //求q1里面1的总和
        execute = redisTemplate.execute(redisCallback2);
    }

}

 

5.RedisTemplate

5.1乱码的问题

 JdkSerializationRedisSerializer  serializer = new JdkSerializationRedisSerializer();
        byte[] serialize = serializer.serialize("user#01");
        System.out.println(new String(serialize));

5.2自定义序列化工具(RedisTemplate)配置类

@Configuration
public class RedisConfig {
    @Bean //主动注册了一个名字为redisTemplate的bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        //启用默认类型推理,将类型信息作为属性写入json
        //就是把类型的全类名写入JSON
        mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(),ObjectMapper.DefaultTyping.NON_FINAL);
        jackson.setObjectMapper(mapper);
        template.setKeySerializer(RedisSerializer.string());
        template.setValueSerializer(jackson);
        template.setHashKeySerializer(RedisSerializer.string());
        template.setHashValueSerializer(jackson);
        return template;
    }

}

SetNX(分布式锁)

@SpringBootTest
class SetNXTests {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Resource(name="redisTemplate")
    ValueOperations<String, String> valueOperations;

    @Test
    void test(){
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 1; i <=5; i++) {
            executorService.execute(()->{
                //某一个工人
                String ioId="IO"+ RandomUtil.randomInt(1,1000);
                while (true){
                    Boolean b = valueOperations.setIfAbsent("lock.product.1", ioId + " : " + DateUtil.now());
                    if (b){
                        System.out.println(Thread.currentThread().getId()+"获得了分布式锁======");
                        //执行业务
                        ThreadUtil.safeSleep(3000);
                        //执行业务成功后
                        stringRedisTemplate.delete("lock.product.1");
                        System.out.println(Thread.currentThread().getId()+"释放了分布式锁++++++++");
                        break;
                    }else {
                        System.out.println(Thread.currentThread().getId()+"没有获得分布式锁-------------");
                        ThreadUtil.safeSleep(3000);
                    }
                }
            });
        }
        ThreadUtil.safeSleep(100000);
    }

LuaTest 

在Redis中使用lua脚本,主要是其能够使多条redis语句具有原子性,在处理订单模块具有重要作用

  1. 参数说明:

    • KEYS[]数组用于在脚本中引用传入的键名。
    • ARGV[]数组用于传递额外的参数(非键名)给脚本。
    • redis.call()函数在脚本内部调用Redis命令。
@SpringBootTest
class LuaTests {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Resource(name="redisTemplate")
    RedisTemplate<String, Student> redisTemplate;

    @Test
    void test(){
        String lua =  "return redis.call('set',KEYS[1],ARGV[1])";
        RedisScript<String> redisScript = RedisScript.of(lua, String.class);
        stringRedisTemplate.execute(redisScript, CollUtil.newArrayList("a"),"b100");
    }

    @Test
    void test1(){
        for (int i = 1; i <= 5; i++) {
            stringRedisTemplate.opsForValue().set("product."+i,String.valueOf(i));
        }
    }

    @Test  //一次扣减一个库存商品
    void test2(){
        StringBuilder sb = new StringBuilder();
        sb.append( " local key = KEYS[1] " );//你要扣减的key,例如:product.1
        sb.append( " local qty = ARGV[1] " );//你要剪得的数量
        sb.append( "local redis_qty = redis.call('get',key) " );//查询redis里面存储的数量
        sb.append( " if tonumber(redis_qty) >= tonumber(qty) then" ); //库存量与需求量进行对比,tonumber作用是转成数字
        sb.append( " redis.call('decrby',key,qty) " );   //对redis数据库进行减操作
        sb.append( " return -1 " ); //满足条件,返回-1
        sb.append( " else " );
        sb.append( "   return tonumber(redis_qty) " );//如果不满足,返回库存数量
        sb.append( "  end " );
        RedisScript<Long> redisScript = RedisScript.of(sb.toString(), Long.class);
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 1; i <= 5; i++) {
            executorService.execute(()->{
                int qty = RandomUtil.randomInt(1,6);
                Long aLong = stringRedisTemplate.execute(redisScript, CollUtil.newArrayList("product.5"), String.valueOf(qty));
                if (aLong == -1L) {
                    System.out.println(Thread.currentThread().getId() + " 扣减成功,扣减了-> "+ qty);
                } else {
                    System.out.println(Thread.currentThread().getId() + "扣减失败,需求量是:"+qty+",剩余库存量:"+aLong);
                }
            });
             ThreadUtil.safeSleep(3000);//因为线程是异步的,所以要睡眠一定时间
        }

    }

    @Test  //一次扣减多个库存
    void test3(){
        StringBuilder sb = new StringBuilder();
        sb.append( " local table = {} " );//所有不满足的商品都存到table
        sb.append( " local values =  redis.call('mget', unpack(KEYS)) " );//查询所有的key所含有的value,[product.1,product.2]=>product.1,product.2
        sb.append( " for i = 1, #KEYS   do  " );//循环,#KEYS代表KEYS的值
        sb.append( " if tonumber(ARGV[i]) > tonumber(values[i]) then " );//如果需求量大于库存量
        sb.append( " table[#table + 1] =  KEYS[i] .. '=' .. values[i] " );
        sb.append( " end " );
        sb.append( " end " );
        sb.append( " if #table > 0 then " );//如果有不满足的商品,返回该需求
        sb.append( " return table " );
        sb.append( " end " );
        sb.append( " for i=1 ,#KEYS do " );//如果满足,进行循环扣除
        sb.append( " redis.call('decrby',KEYS[i],ARGV[i]) " );
        sb.append( " end " );
        sb.append( " return{} " );
        RedisScript<List> redisScript = RedisScript.of(sb.toString(), List.class);
        List<StockProduct> stockProducts =new ArrayList<>();
        stockProducts.add(new StockProduct(5,1));
        stockProducts.add(new StockProduct(4,2));
        List<String> keys = stockProducts.stream().map(it -> "product." + it.getId()).collect(Collectors.toList());
        Object[] qtys = stockProducts.stream().map(it -> it.getQty()+"").toArray();
        List<String> list = stringRedisTemplate.execute(redisScript, keys, qtys);
        if (list.isEmpty()){
            System.out.println("库存冻结成功");
        }else {
            for(String key_qty : list){
                String[] split = key_qty.split("=");
                System.out.println(split[0]+"库存不足,剩余库存量"+split[1]);
            }
        }
        ThreadUtil.safeSleep(3000);
    }
}

为什么不使用decyby,decrby具有弊端,以下通过demo进行演示

 @Test
    void test(){
        String key ="product.1";
        valueOperations.set(key,5);
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 1; i <=5; i++) {
            executorService.execute(()->{
                Integer redis_qty = valueOperations.get(key);
                if (redis_qty>=1){
                    //满足条件,数量减一,但是可能被打断
                    valueOperations.set(key,redis_qty-1);
                    System.out.println("线程:"+Thread.currentThread().getId() +"执行成功,数量减一");
                }else {
                    System.out.println("线程:"+Thread.currentThread().getId() +"执行失败");
                }
            });
        }
        ThreadUtil.safeSleep(3000);
    }

可以看出,定义了product.1的数量为5,线程数为5,正常结果应该为0,但是结果缺为4,这是因为,线程的执行速度非常快,多条线程执行时,库里面显示的都是5,才会造成这种原因。

@Test
    void test2(){
        String key ="product.1";
        valueOperations.set(key,5);
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 1; i <=8; i++) {
            executorService.execute(()->{
                Integer redis_qty = valueOperations.get(key);
                if (redis_qty>=0){
                    //满足条件,数量减一,但是可能被打断
                    Long redis_qty2 = valueOperations.decrement(key);
                    System.out.println("线程:"+Thread.currentThread().getId() +"执行成功,数量减一");
                }else {
                    System.out.println("线程:"+Thread.currentThread().getId() +"执行失败");
                }
            });
        }
        ThreadUtil.safeSleep(3000);
    }

decrby具有的弊端为,使商品多买,出现负数。

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

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

相关文章

第十四届蓝桥杯JavaA组省赛真题 - 棋盘

解题思路&#xff1a; 暴力 棋盘类题目取反操作&#xff1a; f[a][b]^1; 或者f[a][b] 1 - f[a][b]; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);int n scan.nextInt();int m scan.nex…

MyEclipse10配置Tomcat7+Web项目发布

配置时&#xff0c;MyEclipse→Preference&#xff0c;在左边栏目中选择MyEclipse——Servers——Tomcat——Tomcat7.x&#xff0c;如下&#xff1a; 把Tomcat服务器设为可用&#xff0c;选择Tomcat的路径&#xff08;选择Tomcat路径的时候一定要选对&#xff0c;不要选Tomcat下…

STM32使用U盘进行固件更新

前面提过串口IAP升级可以方便的进行不拆机固件更新 STM32串口IAP-CSDN博客文章浏览阅读577次,点赞20次,收藏6次。那么有哪些便捷的升级方式呢,其实有很多,比较常见的比如手机软件更新,很典型的远程升级案例。前面说过“修改STM32链接脚本可以修改程序写入闪存的起始地址”…

位置_分布式处理和数据的MVA考虑——可持续架构(七)

前言 理解分布式进程和数据的影响&#xff0c;可以使团队尚在未具备处理分布式能力的时候&#xff0c;做出更好的MVA决策。云计算并不能消除分布式问题&#xff0c;反而它可能会使问题更难解决&#xff0c;因为它隐藏了底层基础设施。改变数据位置可能会对应用程序逻辑产生微妙…

基于单片机的温度控制器系统仿真设计

**单片机设计介绍&#xff0c;基于单片机的温度控制器系统仿真设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的温度控制器系统仿真设计概要主要包括以下几个关键方面&#xff1a;硬件设计、软件设计、系统仿真与…

颜值测评打分微信小程序AI智能颜值测评小程序搭建流量主收益

功能简介&#xff1a; 1.该小程序是AI智能颜值测评 2.可配合流量主推广&#xff0c;广告变现 3.后台含有区间关键词&#xff0c;颜值分析管理可用于公众号吸粉 (保存海报上的二维码换成公众号二维码) 4.(美容院&#xff0c;整形机构活动&#xff0c;颜值评分X分以上可到店获…

安卓手机ip地址怎么切换?简单几步轻松实现

在移动互联网时代&#xff0c;安卓手机作为我们日常生活中不可或缺的一部分&#xff0c;扮演着越来越重要的角色。而在网络世界中&#xff0c;IP地址则是每个设备的标识&#xff0c;它决定了设备在网络中的位置与身份。然而&#xff0c;有时我们可能出于隐私保护、网络测试或其…

PTA L2-040 哲哲打游戏

哲哲是一位硬核游戏玩家。最近一款名叫《达诺达诺》的新游戏刚刚上市&#xff0c;哲哲自然要快速攻略游戏&#xff0c;守护硬核游戏玩家的一切&#xff01; 为简化模型&#xff0c;我们不妨假设游戏有 N 个剧情点&#xff0c;通过游戏里不同的操作或选择可以从某个剧情点去往另…

Jmeter —— 接口之间关联调用(获取上一个接口的返回值作为下一个接口的请求参数)

正则表达式&#xff1a; 具体如何操作&#xff1a; 1. 草稿保存&#xff0c; 此请求的响应数据的id 为发布总结的请求参数draft_id 2. 草稿保存的响应数据 3.在草稿保存的请求中&#xff0c;添加后置处理器- 正则表达式提取器&#xff0c; 提取响应数据的id信息 4. 发布总结请…

Linux+ARM 简单环境检测---软件部分

1、前言 这个是我学习linuxARM的在做的第一个软硬件结合项目&#xff0c;以往的类似这种整体类项目还是光单片机的时候&#xff0c;linux软件部分学习了差不多快一年了&#xff0c;因为各种事情耽搁&#xff0c;这个项目一直没有静下心来完成&#xff0c;不过终于哈哈哈哈搞完了…

【Java】:封装和包

目录 1.封装的概念 2.访问限定符号 3.封装扩展之包 3.1包的概念 3.2导入包中的类 3.3自定义包 3.4常见的包 1.封装的概念 面向对象程序三大特性&#xff1a;封装、继承、多态。何为封装&#xff1f;简单来说就是套壳屏蔽细节。 比如&#xff1a;对于电脑这样一个复杂的…

elementui的table根据是否符合需求合并列

<el-table :data"tableData" border style"width: 100%;" :span-method"objectSpanMethodAuto"><!-- 空状态 --><template slot"empty"><div><img src"/assets/images/noData.png" /></di…

【AcWing】蓝桥杯集训每日一题Day7|贡献法|4261.孤独的照片(C++)

4261.孤独的照片 AcWing 4261. 孤独的照片&#xff08;每日一题&#xff09; - AcWing难度&#xff1a;简单时/空限制&#xff1a;1s / 64MB总通过数&#xff1a;9889总尝试数&#xff1a;26088来源&#xff1a;USACO 2021 December Contest Bronze算法标签贡献法乘法原理 题目…

强烈推荐!13K star,一款Python开源自动化抢票神器!

马上就春节了&#xff0c;你抢到回家的票了吗&#xff1f; 别急&#xff0c;今天给大家推荐一款开源、功能强大且实用的12306抢票工具&#xff01; 1、介绍 该项目名为py12306&#xff0c;由 GitHub 用户 pjialin 创建和维护&#xff0c;用Python语言开发。 项目目前在GitHu…

【idea快捷键】idea开发java过程中常用的快捷键

含义win快捷键mac快捷键复制当前行或选定的代码块Ctrl DCommand D通过类名快速查找类Ctrl NCommand N通过文件名快速查找文件Ctrl Shift NCommand Shift N通过符号名称快速查找符号&#xff08;类、方法等&#xff09;Ctrl Alt Shift NCommand Shift O跳转到声明C…

精准定制:利用本地词库优化Jieba分词,提升景区评论数据LDA建模效果

引言&#xff1a; 在进行景区评论数据的LDA建模时&#xff0c;精确的分词是至关重要的。然而&#xff0c;通用的分词工具在处理特定领域的文本时可能表现不佳。针对这一挑战&#xff0c;本文探讨了如何利用本地词库&#xff0c;特别是搜狗词库中关于旅游领域的专业词汇&#x…

virtualbox 设置虚拟机 centos 网络

在VirtualBox中为运行CentOS系统的虚拟机配置网络连接&#xff0c;您通常可以选择以下几种网络模式之一&#xff0c;以满足不同的网络需求&#xff1a; NAT (Network Address Translation): 功能&#xff1a;允许虚拟机通过宿主机的网络连接访问互联网&#xff0c;同时也可以从…

【vue】一个小bug和key的引入

点击master Vue!删除后该list后输入框中的Jerry消失了 原因&#xff1a;vue当你更改元素时会在真实的dom中渲染并更新list。这两个goal是两个dom元素,触发点击事件后,vue并不会删除第一个dom元素,而是把第二个dom元素的动态内容({{ goal }} - {{ index }})复制到第一个dom元素…

Python基础:标准库 -- math (数学函数)

1. 官方文档 math --- 数学函数 — Python 3.12.2 文档 cmath --- 关于复数的数学函数 — Python 3.12.2 文档 Python 中&#xff0c;可以使用内置的数学运算符&#xff0c;例如加法 ()、减法 (-)、除法 (/) 和乘法 (*) 进行简单的数学运算。不过&#xff0c;更高级的运算&a…

SpringCloud下的微服务应用技术(结尾篇)

六. Feign远程调用 6.1 替代RestTemplate RestTemplate调用问题&#xff1a;代码可读性差&#xff0c;参数复杂且URL难维护。 Feign是一个声明式的HTTP客户端&#xff0c;官方地址&#xff1a;GitHub - OpenFeign/feign: Feign makes writing java http clients easier 它可…