Shiro学习总结
第一章 入门概述
1.概念
shiro是一个Java安全框架,可以完成:认证、授权、加密、会话管理、与web集成、缓存…
2.优势
● 易于使用,构建简单
● 功能全面
● 灵活,可以在任何应用程序环境中工作,并且不需要依赖它们
● 高效支持web,可以基于应用程序URL和Web协议创建灵活的安全策略
● 兼容性强,易于和其他框架和应用程序集成
● 社区支持
3.与springsecurity的区别
● shiro需要和spring整合开发,而springsecurity基于spring开发,配合起来更便利
● springsecurity比shiro功能丰富,如安全维护
● shiro配置和使用简单,springsecurity较难
● shiro依赖性低,不需要任何框架和容器,可以独立运行,而springsecurity需要依赖spring容器
● shiro可以工作于任何应用环境,独立于容器
4.基本功能
- Authentication:身份认证/登录,验证用户是否拥有对应的身份
- authorization:权限验证,验证用户是否拥有某个权限,判断用户可以进行什么操作
- session management:会话管理,即用户登录后的一次会话,在没有登出之前,所有的信息都保存在会话中
- cryptography:加密,保证数据的安全,比如密码加密存储数据库
- web support:web支持,集成web环境
- caching:缓存,比如用户登录后,用户信息、角色和权限保存下来
- concurrency:多线程并发验证,比如在一个线程红开启另一个线程,可以把权限自动传播过去
- Testing:测试功能
- run as:伪装用户
- remember me:记住我
5.原理
shiro外部架构
subject:对外API核心,与应用代码直接交互的对象,与subject的所有交互都会委托为securitymanager
securitymanager:安全管理器,所有与安全相关的操作都会与securitymanager交互,管理所有的subject,是shiro的核心,相当于spingmvc的dispatcherservlet的角色
realm:从realm中获取安全数据信息(用户、角色、权限)
shiro内部架构
- Subject:任何可以与应用交互的“用户”
- SecurityManager :相当于 SpringMVC 中的 DispatcherServlet;是 Shiro 的心脏; 所有具体的交互都通过 SecurityManager 进行控制;它管理着所有 Subject、且负责进 行认证、授权、会话及缓存的管理
- Authenticator:负责 Subject 认证,是一个扩展点,可以自定义实现;可以使用认证策略(Authentication Strategy),即什么情况下算用户认证通过了
- Authorizer:授权器、即访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能
- Realm:可以有 1 个或多个 Realm,可以认为是安全实体数据源,即用于获取安全实体的;可以是 JDBC 实现,也可以是内存实现等等;由用户提供;所以一般在应用中都需要实现自己的 Realm
- SessionManager:管理 Session 生命周期的组件
- CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据 基本上很少改变,放到缓存中后可以提高访问的性能
- Cryptography:密码模块,Shiro 提高了一些常见的加密组件用于如密码加密/解密。
第二章 基本使用
1.环境搭建
● 引入依赖
<dependencies><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.9.0</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency>
</dependencies>
● ini文件:src/main/resources/shiro.ini
[users]
zhangsan=z3
lisi=l4
2.登录认证
概念:
① 身份验证:一般需要提供如身份ID等一些标识信息来表明登录者的身份,如提供email,用户名/密码来证明
② 在shiro中,用户需要提供principals(身份)和credentials(证明)给shiro,从而应用能验证用户身份
③ principals:身份,即主体的标识属性,可以是任何属性,如用户名、邮箱等,唯一即可。一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/邮箱/手机号
④ credentials:证明/凭证,即只有主体知道的安全值,如密码/数字证书等
最常见的principals和credentials组合就是用户名/密码
流程:
① 收集用户身份/凭证,即如用户名/密码
② 调用 Subject.login 进行登录,如果失败将得到相应 的 AuthenticationException异常,根据异常提示用户 错误信息;否则登录成功
③ 创建自定义的 Realm 类,继承 org.apache.shiro.realm.AuthenticatingRealm类,实现 doGetAuthenticationInfo() 方法
实例:
public class ShiroRun {public static void main(String[] args) {//1.初始化获取securitymanagerIniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);//2.获取subject对象Subject subject = SecurityUtils.getSubject();//3.创建token对象,web应用用户名密码从页面传递AuthenticationToken token = new UsernamePasswordToken("zhangsan", "z3");//4.完成登录try {subject.login(token);System.out.println("login successful");} catch (UnknownAccountException e) {e.printStackTrace();System.out.println("用户不存在");}catch (IncorrectCredentialsException e) {e.printStackTrace();System.out.println("密码错误");}catch (AuthenticationException e) {e.printStackTrace();System.out.println("登录失败");}}
}
3.授权
① 授权,也叫访问控制,即在应用中控制谁访问哪些资源(如访问页面/编辑数据/页面 操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限 (Permission)、角色(Role)
② 主体(Subject):访问应用的用户,在 Shiro 中使用 Subject 代表该用户。用户只有授权 后才允许访问相应的资源
③ 资源(Resource):在应用中用户可以访问的 URL,比如访问 JSP 页面、查看/编辑 某些 数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问
④ 权限(Permission):安全策略中的原子授权单位,通过权限我们可以表示在应用中用户 有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如:访问用 户列表页面查看/新增/修改/删除用户数据(即很多时候都是CRUD(增查改删)式权限控 制)等。权限代表了用户有没有操作某个资源的权利,即反映在某个资源上的操作允不允许
⑤ Shiro 支持粗粒度权限(如用户模块的所有权限)和细粒度权限(操作某个用户的权限, 即实例级别的)
⑥ 角色(Role):权限的集合,一般情况下会赋予用户角色而不是权限,即这样用户可以拥有 一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等都是角色,不同的角色拥有一组不同的权限
授权方式:
- 编程式:
subject.hasRole("admin")
- 注解式:
@RequiresRoles("admin")
- jsp/gsp标签:
<shiro:hasRole name="admin"></shiro:hasRole>
授权流程:
- 首先调用Subject.isPermitted*/hasRole*接口,其会委托给SecurityManager,而SecurityManager接着会委托给 Authorizer
- Authorizer是真正的授权者,如果调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例
- 在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限
- Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted*/hasRole* 会返回 true,否则返回false表示授权失败
实例:
1.给shiro.ini增加角色配置
[users]
fate=admin,role1,role2
fuck=123456
2.增加权限配置
[roles]
role1=user:insert,user:select
3.测试代码
public static void main(String[] args) {//1.初始化获取securitymanagerIniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);//2.获取subject对象Subject subject = SecurityUtils.getSubject();//3.创建token对象,web应用用户名密码从页面传递AuthenticationToken token = new UsernamePasswordToken("zhangsan", "z3");//4.完成登录try {subject.login(token);System.out.println("login successful");//5.判断角色boolean hasRole = subject.hasRole("role1");System.out.println("是否拥有role1角色:" + hasRole);//6.判断权限boolean permitted = subject.isPermitted("user:insert");System.out.println("是否拥有此权限:" + permitted);//也可以用checkPermission方法,但没有返回值,没权限抛AuthenticationExceptionsubject.checkPermission("user:update");} catch (UnknownAccountException e) {e.printStackTrace();System.out.println("用户不存在");} catch (IncorrectCredentialsException e) {e.printStackTrace();System.out.println("密码错误");} catch (AuthenticationException e) {e.printStackTrace();System.out.println("登录失败");}
}
4.加密
Shiro内嵌很多常用的加密算法,比如MD5加密
public class ShiroMD5 {public static void main(String[] args) {//密码明文String password = "admin";//使用MD5加密Md5Hash md5Hash = new Md5Hash(password);System.out.println("md5加密:" + md5Hash);//带盐的md5加密,盐就是在密码明文后拼接新字符串,然后再进行加密Md5Hash md5Hash1 = new Md5Hash(password, "salt");System.out.println("带盐的md5加密:" + md5Hash1.toHex());//为了保证安全,避免被破解还可以多次迭代加密,保证数据安全Md5Hash md5Hash2 = new Md5Hash(password, "salt", 3);System.out.println("带盐的3次迭代加密:" + md5Hash2);//使用父类进行加密SimpleHash simpleHash = new SimpleHash("MD5", password, "salt", 3);System.out.println("父类带盐的3次加密:" + simpleHash);}
}
5.自定义登录认证
Shiro 默认的登录认证是不带加密的,如果想要实现加密认证需要自定义登录认证, 自定义Realm
public class MyRealm extends AuthenticatingRealm {//自定义登录认证方法,shiro的login方法的底层会调用该类的认证方法进行认证//需要配置自定义的realm生效,应该在ini文件中配置,如果有springboot框架,也可以在Springboot中进行配置//该方法只是获取进行对比的信息,认证逻辑还是按照shiro的底层认证逻辑来完成protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//1.获取身份信息String principal = authenticationToken.getPrincipal().toString();//2.获取凭证信息String password = new String((char[]) authenticationToken.getCredentials());System.out.println("认证的用户信息:" + principal + "---" + password);//3.获取数据库中存储的用户信息if(principal.equals("zhangsan")){//3.1数据库中存储的加盐3次迭代的密码String pwdInfo = "b073e9301c412431159e7075340c4c66";//4.创建封装校验逻辑的对象,封装数据返回AuthenticationInfo info = new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),pwdInfo,ByteSource.Util.bytes("salt"),authenticationToken.getPrincipal().toString());return info;}return null;}
}
添加配置信息,让shiro知晓你使用的是自定义的Realm
[main]
#在shiro.ini中添加配置信息
md5CredentialsMatcher=org.apache.shiro.authc.credential.Md5CredentialsMatcher
md5CredentialsMatcher.hashIterations=3
myrealm=com.atguigu.shirotest.MyRealm
myrealm.credentialsMatcher=$md5CredentialsMatcher
securityManager.realms=$myrealm[users]
zhangsan=7174f64b13022acd3c56e2781e098a5f,role1,role2
lisi=l4 [roles]
role1=user:insert,user:select
第三章 与springboot整合
框架整合
1.引入依赖:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.1.RELEASE</version>
</parent>
<dependencies><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-web-starter</artifactId><version>1.9.0</version></dependency><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.0.5</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.46</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>
2.配置文件
# mybatis配置
mybatis-plus:configuration:# 日志log-impl: org.apache.ibatis.logging.stdout.StdOutImplmapper-locations: classpath:mapper/ *.xmlspring:
# 数据库配置datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/shirodb?characterEncoding=utf-8&useSSL=falsepassword: rootusername: root
# json格式jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8shiro:
# 登录接口loginUrl: /myController/login
3.自定义realm
@Component
public class MyRealm extends AuthorizingRealm{@Autowiredprivate UserService userService;//自定义授权方法@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}//自定义登录认证方法@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//1.获取用户身份信息String name = authenticationToken.getPrincipal().toString();//2.调用业务层获取用户信息(数据库)User user = userService.getUserInfoByName(name);//3.非空判断,将数据封装返回if(user != null){AuthenticationInfo info = new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),user.getPwd(),ByteSource.Util.bytes("salt"),authenticationToken.getPrincipal().toString());return info;}return null;}
}
4.配置类
@Slf4j
@Configuration
public class ShiroConfig {@Autowiredprivate MyRealm myRealm;//配置SecurityManager@Beanpublic DefaultWebSecurityManager defaultWebSecurityManager(){//1.创建defaultWebSecurityManager 对象DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();//2.创建加密对象,设置相关属性HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();//2.1 采用md5加密matcher.setHashAlgorithmName("md5");//2.2 迭代加密次数matcher.setHashIterations(3);//3.将加密对象存储到myRealm中myRealm.setCredentialsMatcher(matcher);//4.将myRealm存入defaultWebSecurityManager 对象defaultWebSecurityManager.setRealm(myRealm);//5.返回return defaultWebSecurityManager;}//配置Shiro内置过滤器拦截范围@Beanpublic DefaultShiroFilterChainDefinition shiroFilterChainDefinition(){DefaultShiroFilterChainDefinition defaultShiroFilterChainDefinition = new DefaultShiroFilterChainDefinition();
// 设置不认证就可以访问的资源defaultShiroFilterChainDefinition.addPathDefinition("/myController/userLogin","anon");defaultShiroFilterChainDefinition.addPathDefinition("/login","anon");
// 设置需要进行登录认证的拦截范围defaultShiroFilterChainDefinition.addPathDefinition("/**","authc");return defaultShiroFilterChainDefinition;}
}
5.编写控制类
@Controller
@RequestMapping("myController")
public class MyController{@GetMapping("userLogin")@ResponseBobypublic String userLogin(String name,String pwd){//1.获取subject对象Subject subject = SecurityUtils.getSubject();//2.封装请求数据到tokenAuthenticationToken token = new UsernamePasswordToken(name,pwd);//3.调用login方法进行登录认证try{ subject.login(token);return "登录成功";}catch(AuthenticationException e){e.printStackTrace();System.out.println("登录失败");return "登录失败";}
}
相关文章:

Shiro学习总结
第一章 入门概述 1.概念 shiro是一个Java安全框架,可以完成:认证、授权、加密、会话管理、与web集成、缓存… 2.优势 ● 易于使用,构建简单 ● 功能全面 ● 灵活,可以在任何应用程序环境中工作,并且不需要依赖它们…...

AS中回退git历史版本并删除历史提交记录
当您想把某个版本后的代码删除,回滚到指定的版本。可以使用一下的方法。 一、打开AS中git历史提交窗口 二、选择需要回滚的版本选项,右键弹出菜单。选择Reset Current Branch to Here... 三、选择 Hard 选项 soft:将合并的更改应用到当前分支…...

线性代数的学习和整理5: 矩阵的加减乘除及其几何意义
目录 1 矩阵加法 1.1 矩阵加法的定义 1.2 加法的属性 1.2.1 只有同类型,相同n*m的矩阵才可以相加 1.2.1 矩阵加法的可交换律: 1.2.2 矩阵加法的可结合律: 1.3矩阵加法的几何意义 2 矩阵的减法 2.1 矩阵减法定义和原理基本同 矩阵的…...
sqlsugar 使用TNS连接oracle
在使用SqlSugar连接Oracle数据库时,可以通过TNS来实现连接。以下是一个示例代码,展示了如何使用TNS连接Oracle数据库: 首先,确保您已经安装了Oracle客户端,并正确配置了TNS的相关信息。 // 引入SqlSugar命名空间 usi…...
用python解压zip文件
因为某个需求,需要用python处理解压文件,这里记录下完成的代码,需要注意的是删除解压出来的文件夹时,很多博客都说直接用removedirs就行,实际我在py3.7上测试会提示“文件夹非空”,而且想想如果直接移除了根…...
代码随想录22| 216.组合总和III, 17.电话号码的字母组合
216.组合总和III 题目链接/文章讲解:链接地址 视频讲解:链接地址 代码思路:回溯三部曲: 1.确定函数参数:n,k,sum,startIndex; 2.结束条件,path k,并且如果sumn 结束递归 3.递归回溯逻辑。 class Solution…...

ITIL4—战略与指导
战略与指导 成功的服务提供,需要朝着商定的目标采取协调一致的行动。本节将探讨服务供应商战略的创建和管理,其目的是首先对战略的本质、范围,以及战略与指导的关系建立基本的理解,然后为与该战略一致的指导活动提供指导。 本节…...

【Spring】Spring循环依赖(超重要!!)
目录 什么是循环依赖问题 循环依赖具体是怎么解决的 具体的解决步骤: 通俗实例: 严谨的循环依赖解决图例 为什么使用的是三级缓存,二级缓存不够用吗? 什么是循环依赖问题 Spring的循环依赖是指在Bean之间存在相互依赖关…...
数据分析之路应该是就此开启了
咱就是说工作以后,就是重新学习的开始啊。 祝自己顺顺利利。 前路漫漫亦灿灿。 数据分析之路,开启吧。 以下是借鉴网上的学习路线。 这个学习路线图主要分为以下几个部分: 基础知识 :包括数学、统计学和编程语言。这是数据分析的…...

win10如何配置jdk环境变量
1.首先要打开系统环境变量配置的页面。具体操作是:打开开始菜单,找到“此电脑”,然后右键“更多”→“属性”。 2.在弹出的页面,选择“高级系统设置” 3.在弹出的页面,选择“环境变量(N)…”。 …...

pm4py使用指南(非机翻)
目录 1. 日志数据读取及预处理(1)查看case和event数量(2)查看起始事件和结束事件(3)时间戳格式的问题 2. 日志数据过滤3. 流程发现4. 模型转化5. 模型可视化 1. 日志数据读取及预处理 通过 pandas库 读取c…...

ChatGPT帮助提升工作效率和质量:完成时间下降40%,质量评分上升 18%
自ChatGPT去年11月发布以来,人们就开始使用它来协助工作,热心的用户利用它帮助撰写各种内容,从宣传材料到沟通话术再到调研报告。 两名MIT经济学研究生近日在《科学》杂志上发表的一项新研究表明,ChatGPT可能有助于减少员工之…...
第二章 搜索
本篇博文是笔者归纳汇总的AcWing基础课题集,方便读者后期复盘巩固~ PS:本篇文章只给出完整的算法实现,并没有讲解具体的算法思路。如果想看算法思路,可以阅读笔者往期写过的文章(或许会有),也可…...
transform_train.json文件解析
transform_train.json 文件内容解析transform_matrix 文件内容解析 {"camera_angle_x": 0.6911112070083618,"frames": [{"file_path": "./train/r_0","rotation": 0.012566370614359171,"transform_matrix": [[…...

Wlan——锐捷零漫游网络解决方案以及相关配置
目录 零漫游介绍 一代零漫游 二代单频率零漫游 二代双频率零漫游 锐捷零漫游方案总结 锐捷零漫游方案的配置 配置无线信号的信道 开启关闭5G零漫游 查看配置 零漫游介绍 普通的漫游和零漫游的区别 普通漫游 漫游是由一个AP到另一个AP或者一个射频卡到另一个射频卡的漫…...

分布式锁系列之zookeeper分布式锁和mysql分布式锁
目录 介绍 下载安装 基本指令编辑 java集成zookeeper 官方提供版 永久节点 临时节点编辑 永久序列化节点 判断当前节点是否存在 获取当前节点中的数据内容 获取当前节点的子节点 更新节点内容 删除节点 zookeeper实现分布式锁 Mysql实现分布式锁 总结 介绍 ZooK…...
Ubuntu部署PHP7.4
系统版本:Ubuntu22.04 PHP版本: 7.4 Mysql版本:8.0 Nginx版本: 最新 1. 更新系统 首先,确保系统包是最新的: sudo apt update && sudo apt upgrade -y2. 安装 Nginx Nginx 在默认的 Ubuntu 仓库中,因此安装…...

WPF中的数据转换-StringFormat
WPF中的数据转换-StringFormat 前言 字符串格式化。使用该功能可以通过设置Binding.StringFormat属性对文本形式的数据进行转换——例如包含日期和数字的字符串。对于至少一半的格式化任务,字符串格式化是一种便捷的技术。 使用 当设置Binding.StringFormat属性…...

java.lang.UnsupportedOperationException解决方法
java.lang.UnsupportedOperationException解决方法 先放错误信息业务场景报错分析先看报错代码位置进入源码查看至此 真相大白 解决方法总结 先放错误信息 业务场景 已知有学生 张三李四王五赵六 等人 private List<String> nameList Arrays.asList("张三", &…...

docker for window更改到非系统盘的使用记录
1、使用Hyper-v模式的docker安装 2、安装docker for windows后安装目录没办法自己选择,固定在c盘 卸载后通过命令行方式设置软连接方式后重新安装来让其安装到软连接的d盘,解决c盘空间问题 mklink /j "C:\Program Files\Docker" "D:\Pr…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...