Springboot链接Redis实现AOP防止重复提交

news2024/11/24 3:10:41

目录

安装redis

 Springboot链接Redis

1.创建springboot项目

如果spring boot启动报Error creating bean with name 'redisUtil'/'redisTemplate'

2.新建application.yml配置

3.redis配置类-直接用

4.redis工具类-直接用

5.写Controller测试

6.启动、测试

整合AOP,防止重复提交

1.定义注解:

2.写一个HttpContextUtil工具类获取HttpServletRequest请求

3.定义一个切面

4.方法加上注解  

 5.测试:


安装redis

# wget http://download.redis.io/releases/redis-6.0.8.tar.gz

# tar xzf redis-6.0.8.tar.gz

# cd redis-6.0.8

# make

安装成功

  进入redis-6.0.8下的src目录

# cd redis-6.0.8

# cd src

启动之前要进行一些配置操作:

在redis-6.0.8目录下进入redis-conf文件,进行基本文件修改

69行 注释掉bind 127.0.0.1  //关闭连接限制

88行  protected-mode yes  改为 protected-mode no //关闭保护模式

92行 port 6379   //更改端口

790行  requirepass xxx  //设置密码

Redis启动:

# ./redis-server ../redis.conf

 Springboot链接Redis

1.创建springboot项目

导入依赖:

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

如果spring boot启动报Error creating bean with name 'redisUtil'/'redisTemplate'

还应该导入下面依赖

 <!--spring boot2.x以上版本需要引入,不然启动会报错!-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

redis中的传递依赖,没有依赖进来,也就是本地maven仓库里没有这个版本的jar包。 

2.新建application.yml配置

spring:
  redis:
    # Redis本地服务器地址,注意要开启redis服务,即那个redis-server.exe
    host: 你的服务器地址
    # Redis服务器端口,默认为6379.若有改动按改动后的来
    port: 端口号
    #Redis服务器连接密码,默认为空,若有设置按设置的来
    password: '密码'(引号必须加,就这一个小错卡我一早上)
    lettuce:
      pool:
        # 连接池最大连接数,若为负数则表示没有任何限制
        max-active: 8
        # 连接池最大阻塞等待时间,若为负数则表示没有任何限制
        max-wait: -1
        # 连接池中的最大空闲连接
        max-idle: 8

3.redis配置类-直接用

 
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
 
/**
 * redis配置类
 */
@Configuration
@EnableCaching //开启注解
public class RedisConfig extends CachingConfigurerSupport {
 
    /**
     * retemplate相关配置
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
 
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置连接工厂
        template.setConnectionFactory(factory);
 
        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
        Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
 
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);
 
        // 值采用json序列化
        template.setValueSerializer(jacksonSeial);
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
 
        // 设置hash key 和value序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jacksonSeial);
        template.afterPropertiesSet();
 
        return template;
    }
 
    /**
     * 对hash类型的数据操作
     */
    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }
 
    /**
     * 对redis字符串类型数据操作
     */
    @Bean
    public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForValue();
    }
 
    /**
     * 对链表类型的数据操作
     */
    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }
 
    /**
     * 对无序集合类型的数据操作
     */
    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }
 
    /**
     * 对有序集合类型的数据操作
     */
    @Bean
    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForZSet();
    }
 
}

4.redis工具类-直接用

 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
 
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
 
@Component
public class RedisUtil {
 
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
 
    public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
 
    /**
     * 指定缓存失效时间
     * @param key 键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key,long time){
        try {
            if(time>0){
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 根据key 获取过期时间
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key){
        return redisTemplate.getExpire(key,TimeUnit.SECONDS);
    }
 
    /**
     * 判断key是否存在
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key){
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 删除缓存
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String ... key){
        if(key!=null&&key.length>0){
            if(key.length==1){
                redisTemplate.delete(key[0]);
            }else{
                redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
            }
        }
    }
 
    //============================String=============================
    /**
     * 普通缓存获取
     * @param key 键
     * @return 值
     */
    public Object get(String key){
        return key==null?null:redisTemplate.opsForValue().get(key);
    }
 
    /**
     * 普通缓存放入
     * @param key 键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key,Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 普通缓存放入并设置时间
     * @param key 键
     * @param value 值
     * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key,Object value,long time){
        try {
            if(time>0){
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            }else{
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 递增
     * @param key 键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta){
        if(delta<0){
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }
 
    /**
     * 递减
     * @param key 键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta){
        if(delta<0){
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }
 
    //================================Map=================================
    /**
     * HashGet
     * @param key 键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    public Object hget(String key,String item){
        return redisTemplate.opsForHash().get(key, item);
    }
 
    /**
     * 获取hashKey对应的所有键值
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object,Object> hmget(String key){
        return redisTemplate.opsForHash().entries(key);
    }
 
    /**
     * HashSet
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public boolean hmset(String key, Map<String,Object> map){
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * HashSet 并设置时间
     * @param key 键
     * @param map 对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String,Object> map, long time){
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if(time>0){
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 向一张hash表中放入数据,如果不存在将创建
     * @param key 键
     * @param item 项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key,String item,Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 向一张hash表中放入数据,如果不存在将创建
     * @param key 键
     * @param item 项
     * @param value 值
     * @param time 时间(秒)  注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key,String item,Object value,long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if(time>0){
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 删除hash表中的值
     * @param key 键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item){
        redisTemplate.opsForHash().delete(key,item);
    }
 
    /**
     * 判断hash表中是否有该项的值
     * @param key 键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item){
        return redisTemplate.opsForHash().hasKey(key, item);
    }
 
    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     * @param key 键
     * @param item 项
     * @param by 要增加几(大于0)
     * @return
     */
    public double hincr(String key, String item,double by){
        return redisTemplate.opsForHash().increment(key, item, by);
    }
 
    /**
     * hash递减
     * @param key 键
     * @param item 项
     * @param by 要减少记(小于0)
     * @return
     */
    public double hdecr(String key, String item,double by){
        return redisTemplate.opsForHash().increment(key, item,-by);
    }
 
    //============================set=============================
    /**
     * 根据key获取Set中的所有值
     * @param key 键
     * @return
     */
    public Set<Object> sGet(String key){
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 
    /**
     * 根据value从一个set中查询,是否存在
     * @param key 键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key,Object value){
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 将数据放入set缓存
     * @param key 键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object...values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
 
    /**
     * 将set数据放入缓存
     * @param key 键
     * @param time 时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key,long time,Object...values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if(time>0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
 
    /**
     * 获取set缓存的长度
     * @param key 键
     * @return
     */
    public long sGetSetSize(String key){
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
 
    /**
     * 移除值为value的
     * @param key 键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object ...values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    //===============================list=================================
 
    /**
     * 获取list缓存的内容
     * @param key 键
     * @param start 开始
     * @param end 结束  0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end){
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 
    /**
     * 获取list缓存的长度
     * @param key 键
     * @return
     */
    public long lGetListSize(String key){
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
 
    /**
     * 通过索引 获取list中的值
     * @param key 键
     * @param index 索引  index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object lGetIndex(String key,long index){
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 
    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     * @param time 时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     * @param time 时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 根据索引修改list中的某条数据
     * @param key 键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index,Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 移除N个值为value
     * @param key 键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key,long count,Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
 
}

5.写Controller测试

 
import com.qcby.bootredis.NoRepeatSubmit;
import com.qcby.bootredis.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import javax.annotation.Resource;
 
 
@Slf4j
@RequestMapping("/redis")
@RestController
public class RedisController {
 
 
    @Resource
    private RedisUtil redisUtil;
 
    @RequestMapping("set")
   // @NoRepeatSubmit
    public boolean redisset(String key, String value){
        System.out.println(key+"--"+value);
        return redisUtil.set(key,value);
    }
 
    @RequestMapping("get")
    public Object redisget(String key){
        System.out.println(redisUtil.get(key));
        return redisUtil.get(key);
    }
 
    @RequestMapping("expire")
    public boolean expire(String key,long ExpireTime){
        return redisUtil.expire(key,ExpireTime);
    }
}

6.启动、测试

 

 

测试完毕,

整合AOP,防止重复提交

导入aop依赖

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

1.定义注解:

import java.lang.annotation.*;
 
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {
    int lockTime() default 5;
}

2.写一个HttpContextUtil工具类获取HttpServletRequest请求

public class HttpContextUtils {
    public static HttpServletRequest HttpServletRequest(){
        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
    }
}

3.定义一个切面

 采用的方案是Redis来缓存提交接口的唯一标识,然后设置过期时间。

唯一标识使用接口的URL和用户的token组合在一起的方式使达到唯一。用户每发起第一次添加请求,会经过界面,在切面获取信息后组装起来存入Redis,当用户后续发起请求时,首先判断Redis中是否缓存了这个key,如果缓存了,则证明已经提交,于是反馈给前端,如果不存在,证明没有提交,则存入Redis。

@Component
@Aspect
public class NoRepeatSubmitAspect {
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
 
    @Pointcut("@annotation(repeatSubmit)")
    public void pointcutNoRepeat(NoRepeatSubmit repeatSubmit){};
    @Around("pointcutNoRepeat(noRepeatSubmit)")
    public Object doNoRepeat(ProceedingJoinPoint point,NoRepeatSubmit noRepeatSubmit) throws Throwable {
        int i=noRepeatSubmit.lockTime();
        HttpServletRequest httpServletRequest = HttpContextUtils.HttpServletRequest();
        String token = httpServletRequest.getHeader("token");
        String url = httpServletRequest.getRequestURL().toString();
        String sign = url+"/"+token;
        Boolean key=redisTemplate.hasKey(sign);
        if (key){
            throw new Exception("请勿重复提交");
        }
        redisTemplate.opsForValue().set(sign,sign,i,TimeUnit.SECONDS);
        return  point.proceed();
    }
}
如果key存在抛出异常。
@Aspect:声明这是一个切面类(使用时需要与@Component注解一起用,表明同时将该类交给spring管理)

@pointcut(@annotation)是Spring AOP中的一个注解,它可以用来指定一个切点,该切点选择所有带有特定注解的方法或类。例如,如果我们想要记录所有带有@Log注解的方法的日志,我们可以定义一个切点,使用@pointcut(@annotation(Log.class)注解来选择这些方法。

@Around 环绕通知

 point.proceed():

  1. 环绕通知 ProceedingJoinPoint 执行proceed方法的作用是让目标方法执行,这也是环绕通知和前置、后置通知方法的一个最大区别。
  2. 简单理解,环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的。

4.方法加上注解  

 5.测试:

启动项目,多次点击提交看看效果

 


参考文章:SpringBoot+Redis使用AOP防止重复提交 - 刘牌 - 博客园 (cnblogs.com)

个人见解,不足请补充,实践出真知!

 

 坤坤没有管住坤坤,鸡棚塌了😭😭😭😭😭

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内网横线移动—WmiSmbCrackMapExecProxyChainsImpacket

内网横线移动—Wmi&Smb&CrackMapExec&ProxyChains&Impacket 1. 前置环境准备2. wmic介绍2.1. wmic操作演示2.1.1. 受控主机上线2.1.1.1. 内网存活探测2.1.1.2. 密码抓取 2.1.2. 横向移动2.1.2.1. 上传文件2.1.2.2. 文件上传目标主机2.1.2.3. 执行木马 2.2. wmi…

JAVA 安全-JWT 安全及预编译 CASE 注入等(40)

在各种语言脚本的环境下&#xff0c;也会产生一些新的漏洞&#xff0c;如果是java又能产生那些漏洞&#xff0c;思维导图里面常规漏洞之前都有&#xff1b; java的访问控制&#xff0c;jwt令牌&#xff08;php几乎没有&#xff09;组件安全&#xff0c;这些都是java特有的 #综…

C#核心知识回顾——3.继承构造、拆装箱、多态

1.继承中的构造函数&#xff1a; 特点&#xff1a; 当申明一个子类对象时 先执行父类的构造函数&#xff0c;再执行子类的构造函数注意&#xff01;&#xff01;&#xff1a; 1.父类的无参构造很重要 2.子类可以通过base关键字代表父类调用父类构造 public class Mot…

【单片机】STM32单片机,定时器的输入捕获,基于捕获的频率计,STM32F103

文章目录 简单介绍外部计数频率计TIM5 频率计 简单介绍 下面的定时器都具有输入捕获能力&#xff1a; 外部计数频率计 查看另一篇文章&#xff1a;https://qq742971636.blog.csdn.net/article/details/131471539 外部计数频率计的缺点&#xff1a;需要两个定时器配合&#x…

控制 显示、隐藏

1、使用 v-if < v-if"isShow"></> data(){ return:{ isShow:false } } if (concepts && concepts.length >0){ this.isShow nv.concepts.includes(snap) } 确认 数组中有某个 字段&#xff0c;用includes 有&…

Qt QGraphics导入背景图并绘制图形,画布移动、缩放、图形旋转等

前言 之前写过一篇博文《Qt鼠标拖动绘制基本几何图形》 &#xff0c;这是介绍使用QGraphic中利用鼠标事件实现基本几何图形的绘制&#xff0c;支持直线、矩形、圆形、椭圆&#xff0c;本次是在此基础上进行扩展&#xff0c;实现背景图导入&#xff0c;并在图片上进行几何图形绘…

现货白银行情实时行情与展望

现货白银作为低门槛、高收益的贵金属投资工具&#xff0c;因为交易时间自且没有涨跌幅限制而大受全球投资者追捧&#xff0c;它每天的实时行情走势中充满机会&#xff0c;投资者可结合技术和基本面分析手段&#xff0c;预测其未来的价格走势&#xff0c;在市场的波动中把握住获…

Go编写流量代理工具

目录 这是一个演示主要分为俩包&#xff1a;流程&#xff1a;逻辑&#xff1a;(端口随意&#xff0c;本地ssh为例)用法&#xff1a;文件地址&#xff1a;代码如下&#xff1a; 这是一个演示 代理本地HTTP服务 代理局域网SSH服务 其他的TCP服务没测试了 主要分为俩包&#x…

什么是DevOps? 什么是DORA?

1. 前言 对于搞云原生应用的同学&#xff0c;对于DevOps和DORA应该都不陌生。但对于传统应用程序开发的同学&#xff0c;经常被DevOps, Microservice, CICD, DORA这些新颖的名词搞得晕头转向。那么到底什么是DevOps? 什么是DORA呢&#xff1f; 2. 解析 2.1 DevOps DevOps并…

群晖NAS搭建WebDV服务手机ES文件浏览器远程访问

文章目录 1. 安装启用WebDAV2. 安装cpolar3. 配置公网访问地址4. 公网测试连接5. 固定连接公网地址 转载自cpolar极点云文章&#xff1a;群晖NAS搭建WebDAV服务手机ES文件浏览器远程访问 有时候我们想通过移动设备访问群晖NAS 中的文件,以满足特殊需求,我们在群辉中开启WebDav服…

支持刷机(OpenWrt)的路由器大全

2023年上半年最热门的刷机路由器当然是360T7、小米WR30U这两款&#xff0c;主要是性价比高&#xff0c;闲鱼100多搞定&#xff0c;支持刷OpenWrt、支持WiFi6&#xff0c;采用MTK798X系列处理器&#xff0c;性能强&#xff0c;轻松跑满千兆&#xff0c;如果你想追新&#xff0c;…

SpringMVC基础知识

一、SpringMVC 1. Spring与Web环境集成 1.1 ApplicationContext应用上下文获取方式 应用上下文对象是通过new ClasspathXmlApplicationContext(spring配置文件) 方式获取的&#xff0c;但是每次从容器中获得Bean时都要编写new ClasspathXmlApplicationContext(spring配置文件…

云捷|打破应用孤岛加速企业数字化转型

CBG云服务BU X 神州数码云基地 一、引言 从流程信息化到整体的数字化转型&#xff0c;对企业而言是一场深刻的升级再造。企业在决心开启数字化转型之路后&#xff0c;有近5成民营企业数字化转型采用标准化工具&#xff1b;关于“贵公司未来将在工作中增加哪些数字应用的使用…

强化学习从基础到进阶-案例与实践[4.2]:深度Q网络DQN-Cart pole游戏展示

【强化学习原理项目专栏】必看系列&#xff1a;单智能体、多智能体算法原理项目实战、相关技巧&#xff08;调参、画图等、趣味项目实现、学术应用项目实现 专栏详细介绍&#xff1a;【强化学习原理项目专栏】必看系列&#xff1a;单智能体、多智能体算法原理项目实战、相关技巧…

基于PaddleDetection fairmot目标跟踪 C++ 部署

1 源码下载 PaddleDetection 2 工程编译 参考&#xff1a;paddle 目标检测C部署流程 3 导出模型 python tools/export_model.py -c configs/mot/fairmot/fairmot_dla34_30e_576x320.yml --output_dir ./inference -o weightshttps://paddledet.bj.bcebos.com/models/mot/…

AutoSAR系列讲解(入门篇)4.7-BSW的Diagnostics功能

一、架构与术语解释 首先简单介绍以下诊断&#xff08;Diagnostics&#xff09;&#xff0c;由于百度百科中就有很好的解释&#xff0c;这里直接引用一下&#xff1a; 汽车诊断技术是凭借仪器设备对汽车进行性能测试和故障检查的方法和手段&#xff0c;它能够测试出汽车各项工作…

CMU 15-445 -- 存储篇 - 02

CMU 15-445 -- 存储篇 - 02 引言Database StorageDisk Manager 简介计算机存储体系为什么不使用 OS 自带的磁盘管理模块磁盘管理模块的核心问题在文件中表示数据库File StorageDatabase PagesHeap File OrganizationPage LayoutData LayoutTuple LayoutTuple Storage Data Repr…

Windows Update当前无法检查更新怎么办?

当进行Windows更新或升级时&#xff0c;可能会提示“Windows Update当前无法检查更新&#xff0c;因为未运行服务。您可能需要重新启动计算机”。而当重启也无法解决问题时&#xff0c;我们该怎么办呢&#xff1f;下面我们就来了解一下。 1、删除Software Distribution文件夹中…

Hyperledger Fabric交易流程分析

1、交易流程 客户端利用受支持的SDK(Golang、Java、Node、Python)提供的API构建交易提案请求&#xff0c;将交易事务提案打包成为一个正确的格式。交易提案包含如下要素&#xff1a; ①channelID:通道信息。 ②chaincodelD:要调用的链码信息。 ③timestamp:时间戳。 ④sign:客户…

百度智能车竞赛丝绸之路2——手柄控制

百度智能车竞赛丝绸之路1——智能车设计与编程实现控制 百度智能车竞赛丝绸之路2——手柄控制 一、机器人设计 二、实现原理 本教程使用Python的Serial库和Struct二进制数据解析库去实现Xbox手柄百度大脑学习开发板&#xff08;上位机&#xff09;和机器人控制器&#xff08;…