shiro学习五:使用springboot整合shiro。在前面学习四的基础上,增加shiro的缓存机制,源码讲解:认证缓存、授权缓存。
文章目录
- 前言
- 1. 直接上代码最后在讲解
- 1.1 新增的pom依赖
- 1.2 RedisCache.java
- 1.3 RedisCacheManager.java
- 1.4 jwt的三个类
- 1.5 ShiroConfig.java新增Bean
- 2. 源码讲解。
- 2.1 shiro 缓存的代码流程。
- 2.2 缓存流程
- 2.2.1 认证和授权简述
- 2.2.2 AuthenticatingRealm.getAuthenticationInfo() 认证缓存。
- 2.2.3 AuthorizingRealm.getAuthorizationInfo() 授权缓存。
- 2.3 redis缓存的设置入口(个人认为是重点)
- 3. 问题解决
- 3.1 授权的流程是怎么做的
- 3.2 @RequiresPermissions("sys:user:list")是如何工作的
- **1. 基本原理**
- **2. 具体流程**
- **1. 用户登录阶段**
- **2. 调用 `listUsers` 方法时**
- **3. 匹配机制**
前言
-
shiro学习一:了解shiro,学习执行shiro的流程。使用springboot的测试模块学习shiro单应用(demo 6个)
-
shiro学习二:shiro的加密认证详解,加盐与不加盐两个版本。
-
shiro学习三:shiro的源码分析
-
密码专辑:对密码加盐加密,对密码进行md5加密,封装成密码工具类
-
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
-
代码所在地:https://github.com/fengfanli/springboot-shiro 记得给个星哦。
-
本文详细介绍了在Java Spring Boot项目中使用Apache Shiro进行权限管理的实现方式。通过整合Redis作为缓存管理器,实现了用户权限的缓存,提高了权限验证的效率。文章还解析了@RequiresPermissions注解的工作原理,说明了如何通过AOP机制拦截方法,并进行权限字符串的匹配校验,确保只有具备相应权限的用户能够访问受保护的方法。整体上,文章为Shiro在Spring Boot项目中的应用提供了全面的技术指导。
1. 直接上代码最后在讲解
1.1 新增的pom依赖
<!--JWT--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>
1.2 RedisCache.java
package com.feng.shiro;import com.alibaba.fastjson.JSON;
import com.feng.constant.Constant;
import com.feng.jwt.JwtTokenUtil;
import com.feng.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.util.CollectionUtils;import java.util.*;
import java.util.concurrent.TimeUnit;/*** @ClassName: RedisCache* @Description: 缓存工具类* @createTime: 2020/2/9 20:42* @Author: 冯凡利* @UpdateUser: 冯凡利* @Version: 0.0.1*//*** 这里的 RedisUtils 不能注入** @param <K>* @param <V>*/
@Slf4j
public class RedisCache<K, V> implements Cache<K, V> {private final static String PREFIX = "shiro-cache:";private String cacheKey;private long expire = 24; // 24 小时private RedisUtil redisUtil;public RedisCache(String name, RedisUtil redisUtil) {
// this.cacheKey=PREFIX+name+":";this.cacheKey = Constant.IDENTIFY_CACHE_KEY;this.redisUtil = redisUtil;}/*** 根据 key 值 获取 权限信息** @param key jwt* @return* @throws CacheException*/@Overridepublic V get(K key) throws CacheException {log.info("Shiro 从缓存中获取数据 KEY 值[{}]", key);if (key == null) {return null;}try {String redisCacheKey = getRedisCacheKey(key);Object rawValue = redisUtil.get(redisCacheKey); // 根据key 获取 数据if (rawValue == null) {return null;}SimpleAuthorizationInfo info = JSON.parseObject(rawValue.toString(), SimpleAuthorizationInfo.class);V value = (V) info;return value;} catch (Exception e) {throw new CacheException(e);}}/*** 存值** @param key jwt* @param value* @return* @throws CacheException*/@Overridepublic V put(K key, V value) throws CacheException {log.info("put key [{}]", key);if (key == null) {log.warn("Saving a null key is meaningless, return value directly without call Redis.");return value;}try {String redisCacheKey = getRedisCacheKey(key); // cacheKey + userIdredisUtil.set(redisCacheKey, value != null ? value : null, expire, TimeUnit.HOURS);return value;} catch (Exception e) {throw new CacheException(e);}}/*** 根据 key 值 删除缓存的值** @param key* @return* @throws CacheException*/@Overridepublic V remove(K key) throws CacheException {log.info("remove key [{}]", key);if (key == null) {return null;}try {String redisCacheKey = getRedisCacheKey(key);Object rawValue = redisUtil.get(redisCacheKey);V previous = (V) rawValue;redisUtil.delete(redisCacheKey);return previous;} catch (Exception e) {throw new CacheException(e);}}/*** 清除 所有的值** @throws CacheException*/@Overridepublic void clear() throws CacheException {log.debug("clear cache");Set<String> keys = null;try {keys = redisUtil.keys(this.cacheKey + "*");} catch (Exception e) {log.error("get keys error", e);}if (keys == null || keys.size() == 0) {return;}for (String key : keys) {redisUtil.delete(key);}}/*** 获取 redis 所存的 缓存数的大小** @return*/@Overridepublic int size() {int result = 0;try {result = redisUtil.keys(this.cacheKey + "*").size();} catch (Exception e) {log.error("get keys error", e);}return result;}/*** 获取key值** @return*/@SuppressWarnings("unchecked")@Overridepublic Set<K> keys() {Set<String> keys = null;try {keys = redisUtil.keys(this.cacheKey + "*");} catch (Exception e) {log.error("get keys error", e);return Collections.emptySet();}if (CollectionUtils.isEmpty(keys)) {return Collections.emptySet();}Set<K> convertedKeys = new HashSet<>();for (String key : keys) {try {convertedKeys.add((K) key);} catch (Exception e) {log.error("deserialize keys error", e);}}return convertedKeys;}/*** 获取 value值** @return*/@Overridepublic Collection<V> values() {Set<String> keys = null;try {keys = redisUtil.keys(this.cacheKey + "*");} catch (Exception e) {log.error("get values error", e);return Collections.emptySet();}if (CollectionUtils.isEmpty(keys)) {return Collections.emptySet();}List<V> values = new ArrayList<V>(keys.size());for (String key : keys) {V value = null;try {value = (V) redisUtil.get(key);} catch (Exception e) {log.error("deserialize values= error", e);}if (value != null) {values.add(value);}}return Collections.unmodifiableList(values);}/*** 获取 redis 中的 缓存 key ,很重要,** @param key* @return*/private String getRedisCacheKey(K key) {if (null == key) {return null;} else {return this.cacheKey + JwtTokenUtil.getUserId(key.toString());}}
}
1.3 RedisCacheManager.java
package com.feng.shiro;import com.feng.utils.RedisUtil;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.springframework.beans.factory.annotation.Autowired;/*** @ClassName: RedisCacheManager* @Description: 描述* @createTime: 2020/2/9 21:14* @Author: 冯凡利* @UpdateUser: 冯凡利* @Version: 0.0.1*/
public class RedisCacheManager implements CacheManager {@Autowiredprivate RedisUtil redisUtil;@Overridepublic <K, V> Cache<K, V> getCache(String s) throws CacheException {return new RedisCache<>(s, redisUtil);}
}
1.4 jwt的三个类
我不贴了,不是核心代码,可直接看GitHub。
四个部分:
- JwtTokenUtil.java:jwt的工具类
- JwtPropertiesConfig.java:application.properties 中的jwt的属性读取类
- InitializerJwtPropertiesConfig.java:将 JwtPropertiesConfig.java进行注入。
- application.properties 中的jwt的自定义属性配置。
1.5 ShiroConfig.java新增Bean
新增了redisCacheManager bean,然后再 getShiroRealm() 函数中 ,通过 Realm(ShiroRealm) 进行设置 缓存。
/*** shiro 的 缓存管理器* 需要在 ShiroRealm bean 中进行设置* @return*/@Bean(name = "redisCacheManager")public RedisCacheManager redisCacheManager() {return new RedisCacheManager();}/*** 登录的 认证域** @param hashedCredentialsMatcher* @return*/@Bean(name = "shiroRealm")public ShiroRealm getShiroRealm(@Qualifier("shiroHashedCredentialsMatcher") HashedCredentialsMatcher hashedCredentialsMatcher,@Qualifier("redisCacheManager") RedisCacheManager redisCacheManager) {ShiroRealm shiroRealm = new ShiroRealm();// 自定义 处理 token 过滤shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);// 自定义 缓存管理器shiroRealm.setCacheManager(redisCacheManager);return shiroRealm;}
shiro 新增的 shiro 缓存 代码到此结束。
其他代码没有展示,是因为 shiro 缓存的代码只有这些。
2. 源码讲解。
2.1 shiro 缓存的代码流程。
- 首先编写 RedisCache.java:实现 Cache 接口,再这里重写redis的一些操作函数
- 编写RedisCacheManager.java 类:实现 CacheManager 接口,将RedisCache.java 类加入到 缓存管理中。
- 编写ShiroConfig.java 类:将RedisCacheManager注入生Bean,然后再Realm(本案例是ShiroRealm)中设置
缓存管理,同时也是设置资格匹配的地方。
2.2 缓存流程
shiro的核心是再 数据域中,也就是Realm,本案例的是ShiroRealm,继承 AuthorizingRealm 授权域, 授权域 继承了 AuthenticatingRealm 认证域,认证域 又继承了 CachingRealm 缓存域。这三个类是shiro 认证、授权、缓存 三个最重要的类。
2.2.1 认证和授权简述
继承了 AuthorizingRealm 授权域,就要重写两个最重要的方法
-
认证函数 doGetAuthenticationInfo(),既然认证,重写的就是
AuthenticatingRealm认证域 中的函数。在函数getAuthenticationInfo()中。源码截图如下:

-
授权函数 doGetAuthorizationInfo(),既然授权,重写的就是
AuthorizingRealm授权域 中的函数。在函数getAuthorizationInfo()中,源码截图如下:

在 Shiro 中,认证缓存(authentication cache) 和 授权缓存(authorization cache) 是两个不同的缓存,它们用于不同的目的:
- 认证缓存 (authenticationCache):用于缓存用户的认证信息(如,用户是否存在,凭证是否正确等)。这通常是一个比较频繁更新的缓存,因为用户登录的凭证(如密码)是动态变化的,可能会变得无效。
- 授权缓存 (authorizationCache):用于缓存用户的授权信息(如,用户的角色、权限等)。授权信息通常不太会频繁变动,因此可以缓存很长时间。它一般是用于存储用户的角色和权限信息,以减少每次请求时对数据库或外部系统的查询。
2.2.2 AuthenticatingRealm.getAuthenticationInfo() 认证缓存。
该函数的第一句就是:AuthenticationInfo info = this.getCachedAuthenticationInfo(token); 该函数就是从缓存中获取认证信息。
先说答案:shiro不推荐、默认不支持 认证从缓存中获取。
代码中可以看到 在AuthenticatingRealm类属性 this.authenticationCachingEnabled = false; 在构造函数中 默认为 false,不开启缓存。
究其原因:用于缓存用户的认证信息(如,用户是否存在,凭证是否正确等)。这通常是一个比较频繁更新的缓存,因为用户登录的凭证(如密码)是动态变化的,可能会变得无效。
所以不推荐缓存,通过debug,也可以看到。
2.2.3 AuthorizingRealm.getAuthorizationInfo() 授权缓存。
授权缓存 在shiro 中是支持的。因为 AuthorizingRealm 授权域类中的 类属性 this.authorizationCachingEnabled = true; 在构造函数中默认为true的。
getAuthorizationInfo() 函数就是从缓存中进行获取的,没有获取到在 进入 到 doGetAuthorizationInfo() 函数中进行获取、授权。
可以通过debug的方式一点点去查看。
如果没有设置redis作为缓存管理,默认可以配置缓存,但是shiro并没有帮我指定缓存,估计是怕默认指定之后怕内存使用过高,需要自行设定,接下来讲解。
2.3 redis缓存的设置入口(个人认为是重点)
前边讲的都是逻辑流程,如何从缓存中获取。我在读源码的时候我就很好奇,那设置redis作为缓存的地方在哪里呢?默认是用内存作为缓存的设置又在哪里呢?抱着这些疑问继续走。
答案:入口就在ShiroConfig中 Realm 的配置中。
ShiroRealm shiroRealm = new ShiroRealm();// 自定义 处理 token 过滤shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);// 自定义 缓存管理器shiroRealm.setCacheManager(redisCacheManager);
new ShiroRealm()时 ;会执行 AuthorizingRealm、AuthenticatingRealm的构造函数。构造函数中会设置 缓存启动情况、缓存的配置情况。
-
其中
AuthenticatingRealm认证域的构造函数中,会默认指定SimpleCredentialsMatcher作为 凭证匹配器 的 类,shiro还提供了HashedCredentialsMatcher作为 凭证匹配器 类(具体有几个,看CredentialsMatcher类的实现类有几个即可,下图所示)。后面我们自定义了 凭证匹配器 类CustomHashedCredentialsMatcher,其中的doCredentialsMatch()函数就是默认 认证的最核心的函数。

-
AuthorizingRealm 授权域的构造函数中,会默认指定 缓存管理(在CachingRealm 类中)、凭证匹配器(认证域类中) 的初始化,默认都是null。
-
shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);:调用 认证域类 中的方法设置凭证匹配器。 -
shiroRealm.setCacheManager(redisCacheManager);:调用缓存域类中的方法设置缓存管理器 以及 实现缓存的方式(第二行语句),该方法是个接口,有两个实现方法:一个是 认证域,一个是授权域。往下走。
-
这里就是 授权域 中的
afterCacheManagerSet()函数,- 第一个函数调用父类也就是认证域上的函数,会继续调用
this.getAvailableAuthenticationCache()。认证域前边说了,认证缓存shiro默认是关闭的,debug走一边流程就明白了;重点就是授权域了。 - 在第二个函数上,先判断是否有缓存,为null,然后再看 授权域 是否支持 授权缓存(默认支持,前边说了);然后进入懒加载缓存(下面第二张图);到获取缓存的地方,缓存管理不为null,是redis的,接着从158行,获取缓存,158行往下debug,就是上面的1.3小节的
RedisCacheManager.java,将redis返回。


- 第一个函数调用父类也就是认证域上的函数,会继续调用
-
我又来问题了,如果没有redis,走的是哪个呢?首先我也不知道,得先把redis缓存管理给去掉。看看使用的哪个。CacheManager.java 是接口,其实现类截图如下,第一个是我实现的,其余三个都是shiro自带的(第二个应该不是,看源码)。
-
通过源码查看,shiro并没有默认使用缓存配置,仅仅是打开了缓存配置,可以供我们使用,如果想用使用缓存需要自行配置缓存,想上面配置 redis一样,将下面的第二个或者第四个配置到缓存管理中去。

到这里为止源码讲解完啦。
3. 问题解决
3.1 授权的流程是怎么做的
这个需要有背景的。
我基于这个项目来说一下
前端 LayUI+thymeleaf
后端使用springboot、shiro作为权限管理。
根据请求 /api/users,进行举例。
前端发请求后,会先认证,此处略。
然后会先从前端标签获取 权限字符串 sys:user:list,这里使用到了 thymeleaf,然后 通过 doGetAuthorizationInfo()获取所有权限字符串和角色,然后与从前端拿到的 权限字符串 sys:user:list进行对比,若包含,这通过。否则失败
3.2 @RequiresPermissions(“sys:user:list”)是如何工作的
1. 基本原理
@RequiresPermissions("sys:user:list") 是 Apache Shiro 提供的权限控制注解,用于声明访问某个方法或类需要的特定权限。
它的工作机制如下:
-
拦截注解:
- Shiro 提供了
AuthorizationAttributeSourceAdvisor和 AOP(切面编程)机制来拦截被注解标记的类或方法。 - 当调用被标记的方法时,Shiro 拦截并执行权限校验。
- Shiro 提供了
-
获取当前用户的权限:
- Shiro 从当前登录用户的
Subject(主体)中获取用户的权限信息(通常是一组权限字符串)。
- Shiro 从当前登录用户的
-
权限字符串匹配:
- Shiro 将注解中的权限字符串(如
"sys:user:list")与当前用户的权限列表进行比对。 - 如果用户的权限列表中包含注解指定的权限字符串,则校验通过;否则抛出
AuthorizationException,拒绝访问。
- Shiro 将注解中的权限字符串(如
2. 具体流程
假设你有以下代码:
@RequiresPermissions("sys:user:list")
public void listUsers() {// 获取用户列表逻辑
}
1. 用户登录阶段
- 用户通过登录接口认证成功后,Shiro 会根据用户身份(如用户名)从数据库或缓存中加载用户的所有权限,并存储在
Subject中。 - 示例权限列表:
["sys:user:list", "sys:user:edit", "sys:user:delete"]
2. 调用 listUsers 方法时
- Shiro 拦截
@RequiresPermissions注解,通过当前用户的Subject获取权限列表。 - 调用
Subject.isPermitted("sys:user:list")方法,具体逻辑如下:- Shiro 将注解中的权限字符串
"sys:user:list"传递给AuthorizingRealm的doGetAuthorizationInfo方法。 doGetAuthorizationInfo返回用户的权限列表。- Shiro 比较
"sys:user:list"是否存在于用户的权限列表中:- 存在:校验通过,继续执行方法。
- 不存在:抛出异常
AuthorizationException。
- Shiro 将注解中的权限字符串
3. 匹配机制
- 权限字符串可以使用通配符(Wildcard)进行匹配:
- 完全匹配:
"sys:user:list"对比"sys:user:list",通过。 - 通配符匹配:
"sys:user:*"对比"sys:user:list",通过。 - 多级通配符:
"sys:*:*"对比"sys:user:list",通过。
- 完全匹配:
相关文章:
shiro学习五:使用springboot整合shiro。在前面学习四的基础上,增加shiro的缓存机制,源码讲解:认证缓存、授权缓存。
文章目录 前言1. 直接上代码最后在讲解1.1 新增的pom依赖1.2 RedisCache.java1.3 RedisCacheManager.java1.4 jwt的三个类1.5 ShiroConfig.java新增Bean 2. 源码讲解。2.1 shiro 缓存的代码流程。2.2 缓存流程2.2.1 认证和授权简述2.2.2 AuthenticatingRealm.getAuthentication…...
负载均衡器高可用部署
Haproxy 和 Keepalived安装Haproxy配置文件准备Keepalived配置及健康检查启动Haproxy & Keepalived服务继续上一篇文章《K8S集群架构及主机准备》,下面介绍负载均衡器搭建过程 Haproxy 和 Keepalived安装 在负载均衡器两个主机上安装即可 apt install haproxy keepalived…...
属性编程与权限编程
问题 如何获取文件的大小,时间戳以及类型等信息? 再论 inode 文件的物理载体是硬盘,硬盘的最小存储单元是扇区 (每个扇区 512 字节) 文件系统以 块 为单位(每个块 8 个扇区) 管理文件数据 文件元信息 (创建者、创建日期、文件大小&#x…...
用 HTML、CSS 和 JavaScript 实现抽奖转盘效果
顺序抽奖 前言 这段代码实现了一个简单的抽奖转盘效果。页面上有一个九宫格布局的抽奖区域,周围八个格子分别放置了不同的奖品名称,中间是一个 “开始抽奖” 的按钮。点击按钮后,抽奖区域的格子会快速滚动,颜色不断变化…...
R语言绘制有向无环图(DAG)
有向无环图(Directed Acyclic Graph,简称DAG)是一种特殊的有向图,它由一系列顶点和有方向的边组成,其中不存在任何环路。这意味着从任一顶点出发,沿着箭头方向移动,你永远无法回到起始点。 从流…...
报错Too many open files
1、先查看系统最大打开文件数 # 查看当前系统打开文件最大数 # ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signal…...
Spring Web MVC基础第一篇
目录 1.什么是Spring Web MVC? 2.创建Spring Web MVC项目 3.注解使用 3.1RequestMapping(路由映射) 3.2一般参数传递 3.3RequestParam(参数重命名) 3.4RequestBody(传递JSON数据) 3.5Pa…...
129.求根节点到叶节点数字之和(遍历思想)
Problem: 129.求根节点到叶节点数字之和 文章目录 题目描述思路复杂度Code 题目描述 思路 遍历思想(利用二叉树的先序遍历) 直接利用二叉树的先序遍历,将遍历过程中的节点值先利用字符串拼接起来遇到根节点时再转为数字并累加起来,在归的过程中…...
unity中的动画混合树
为什么需要动画混合树,动画混合树有什么作用? 在Unity中,动画混合树(Animation Blend Tree)是一种用于管理和混合多个动画状态的工具,包括1D和2D两种类型,以下是其作用及使用必要性的介绍&…...
AWS EMR使用Apache Kylin快速分析大数据
在AWS Elastic MapReduce(EMR)集群上部署和使用Apache Kylin,以实现对大规模数据集的快速分析,企业可以充分利用云计算的强大资源和Kylin的数据分析能力,实现快速、高效的数据分析。以下是该案例的详细步骤和要点&…...
MySQL存储过程和存储函数_mysql 存储过 call proc_stat_data(3,null)
2)很难调试存储过程。只有少数数据库管理系统允许调试存储过程。不幸的是,MySQL不提供调试存储过程的功能。 1.2 数据准备 创建数据库: DEFAULT CHARACTER SET utf8; use test;这里记得设置编码! 创建测试表: DROP…...
spacemacs gnuplot
个人博客地址:spacemacs gnuplot | 一张假钞的真实世界 环境 Ubuntu 16.10Emacs 24 安装过程 spacemacs安装 安装Emacs sudo apt-get install emacs 安装spacemacs (1)如果已经存在Emacs配置文件,首先备份: c…...
Flink2支持提交StreamGraph到Flink集群
最近研究Flink源码的时候,发现Flink已经支持提交StreamGraph到集群了,替换掉了原来的提交JobGraph。 新增ExecutionPlan接口,将JobGraph和StreamGraph作为实现。 Flink集群Dispatcher也进行了修改,从JobGraph改成了接口Executio…...
Kotlin 使用 Springboot 反射执行方法并自动传参
在使用反射的时候,执行方法的时候在想如果Springboot 能对需要执行的反射方法的参数自动注入就好了。所以就有了下文。 知识点 获取上下文通过上下文获取 Bean通过上下文创建一个对象,该对象所需的参数由 Springboot 自己注入 创建参数 因为需要对反…...
索罗斯的“反身性”(Reflexivity)理论:市场如何扭曲现实?(中英双语)
索罗斯的“反身性”(Reflexivity)理论:市场如何扭曲现实? 一、引言:市场是镜子,还是哈哈镜? 在传统经济学中,市场通常被认为是一个理性、有效的反映现实的系统。按照经典经济学理论…...
Vue 入门到实战 七
第7章 渲染函数 目录 7.1 DOM树 7.2 什么是渲染函数 7.3 h()函数 7.3.1 基本参数 7.3.2 约束 7.3.3 使用JavaScript代替模板功能 7.1 DOM树 7.2 什么是渲染函数 在多数情况下,Vue推荐使用模板template来创建HTML。然而在一些应用场景中,需要使用J…...
系统学习算法: 专题八 二叉树中的深搜
深搜其实就是深度优先遍历(dfs),与此相对的还有宽度优先遍历(bfs) 如果学完数据结构有点忘记,如下图,左边是dfs,右边是bfs 而二叉树的前序,中序,后序遍历都可…...
进程、线程、内存和IO模型的概念详解
进程、线程、内存和IO模型的概念详解 1 进程与线程1.1 进程1.1.1 进程分类1.1.2 进程的状态和转换1.1.3 僵尸进程和孤儿进程的区别1.1.4 进程之间的通信1.1.5 用户态和内核态1.1.6 用户空间和内核空间 1.2 线程1.2.1 线程的状态和转换1.2.2 进程与线程的区别 1.3 多进程和多线程…...
DeepSeek:AI领域的创新先锋
在人工智能领域,DeepSeek正以其独特的创新技术引领着行业的发展。作为一款高性能、低成本的AI模型,DeepSeek在架构设计、训练优化和应用场景等多个方面都展现出了显著的创新点。这些创新不仅使其在技术上取得了突破,也为AI的普及化和应用拓展…...
Labelme转Voc、Coco
Q:在github找的cv代码基本都是根据现有且流行的公共数据集格式组织的训练数据集,这导致我使用labelme标注好之后需要我们重新组织数据集 labelme2coco #!/usr/bin/env pythonimport argparse import collections import datetime import glob import j…...
pytorch实现变分自编码器
人工智能例子汇总:AI常见的算法和例子-CSDN博客 变分自编码器(Variational Autoencoder, VAE)是一种生成模型,属于深度学习中的无监督学习方法。它通过学习输入数据的潜在分布(Latent Distribution)&…...
使用 Numpy 自定义数据集,使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测,对预测结果计算精确度和召回率及F1分数
1. 导入必要的库 首先,导入我们需要的库:Numpy、Pytorch 和相关工具包。 import numpy as np import torch import torch.nn as nn import torch.optim as optim from sklearn.metrics import accuracy_score, recall_score, f1_score2. 自定义数据集 …...
JVM方法区
一、栈、堆、方法区的交互关系 二、方法区的理解: 尽管所有的方法区在逻辑上属于堆的一部分,但是一些简单的实现可能不会去进行垃圾收集或者进行压缩,方法区可以看作是一块独立于Java堆的内存空间。 方法区(Method Area)与Java堆一样,是各个…...
【Python】第七弹---Python基础进阶:深入字典操作与文件处理技巧
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【MySQL】【Python】 目录 1、字典 1.1、字典是什么 1.2、创建字典 1.3、查找 key 1.4、新增/修改元素 1.5、删除元素 1.6、遍历…...
指导初学者使用Anaconda运行GitHub上One - DM项目的步骤
以下是指导初学者使用Anaconda运行GitHub上One - DM项目的步骤: 1. 安装Anaconda 下载Anaconda: 让初学者访问Anaconda官网(https://www.anaconda.com/products/distribution),根据其操作系统(Windows、M…...
在实际开发中,如何正确使用 INT(1) 和 INT(10)
在实际开发中,如何正确使用 INT(1) 和 INT(10) 前言 在数据库设计和开发过程中,数据类型的选择至关重要。 最近,我在工作中遇到了一个关于MySQL中INT类型的误解问题,这让我意识到很多开发者对INT类型的理解存在误区。 本文将深…...
像接口契约文档 这种工件,在需求 分析 设计 工作流里面 属于哪一个工作流
οゞ浪漫心情ゞο(20***328) 2016/2/18 10:26:47 请教一下,像接口契约文档 这种工件,在需求 分析 设计 工作流里面 属于哪一个工作流? 潘加宇(35***47) 17:17:28 你这相当于问用例图、序列图属于哪个工作流,看内容。 如果你的&quo…...
GAMES101学习笔记(六):Geometry 几何(基本表示方法、曲线与曲面、网格处理)
文章目录 几何的表示方法隐式几何 Implicit Geometry代数曲面(Algebraic surface)构造实体几何CSG(Constructive Solid Geometry)距离函数(Distance Function)水平集方法(Level Set Methods)分型几何(Fractal) 显式几何 Explicit Geometry点云(Point Cloud)多边形网格(Polygon …...
【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.24 随机宇宙:生成现实世界数据的艺术
1.24 随机宇宙:生成现实世界数据的艺术 目录 #mermaid-svg-vN1An9qZ6t4JUcGa {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-vN1An9qZ6t4JUcGa .error-icon{fill:#552222;}#mermaid-svg-vN1An9qZ6t4JUc…...
深入解析:一个简单的浮动布局 HTML 示例
深入解析:一个简单的浮动布局 HTML 示例 示例代码解析代码结构分析1. HTML 结构2. CSS 样式 核心功能解析1. 浮动布局(Float)2. 清除浮动(Clear)3. 其他样式 效果展示代码优化与扩展总结 在网页设计中,浮动…...
