Shiro学习总结

第一章 入门概述

1.概念

shiro是一个Java安全框架,可以完成:认证、授权、加密、会话管理、与web集成、缓存…

2.优势

● 易于使用,构建简单
● 功能全面
● 灵活,可以在任何应用程序环境中工作,并且不需要依赖它们
● 高效支持web,可以基于应用程序URL和Web协议创建灵活的安全策略
● 兼容性强,易于和其他框架和应用程序集成
● 社区支持

3.与springsecurity的区别

● shiro需要和spring整合开发,而springsecurity基于spring开发,配合起来更便利
● springsecurity比shiro功能丰富,如安全维护
● shiro配置和使用简单,springsecurity较难
● shiro依赖性低,不需要任何框架和容器,可以独立运行,而springsecurity需要依赖spring容器
● shiro可以工作于任何应用环境,独立于容器

4.基本功能

在这里插入图片描述

  1. Authentication:身份认证/登录,验证用户是否拥有对应的身份
  2. authorization:权限验证,验证用户是否拥有某个权限,判断用户可以进行什么操作
  3. session management:会话管理,即用户登录后的一次会话,在没有登出之前,所有的信息都保存在会话中
  4. cryptography:加密,保证数据的安全,比如密码加密存储数据库
  5. web support:web支持,集成web环境
  6. caching:缓存,比如用户登录后,用户信息、角色和权限保存下来
  7. concurrency:多线程并发验证,比如在一个线程红开启另一个线程,可以把权限自动传播过去
  8. Testing:测试功能
  9. run as:伪装用户
  10. 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.初始化获取securitymanager
        IniSecurityManagerFactory 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>

授权流程:

  1. 首先调用Subject.isPermitted*/hasRole*接口,其会委托给SecurityManager,而SecurityManager接着会委托给 Authorizer
  2. Authorizer是真正的授权者,如果调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例
  3. 在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限
  4. 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.初始化获取securitymanager
    IniSecurityManagerFactory 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方法,但没有返回值,没权限抛AuthenticationException
        subject.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.StdOutImpl
  mapper-locations: classpath:mapper/ *.xml
 
 
spring:
# 数据库配置
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shirodb?characterEncoding=utf-8&useSSL=false
    password: root
    username: root
# json格式
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
 
shiro:
# 登录接口
  loginUrl: /myController/login

3.自定义realm

@Component
public class MyRealm extends AuthorizingRealm{
 
    @Autowired
    private UserService userService;
 
    //自定义授权方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
 
    //自定义登录认证方法
    @Override
    protected 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 {
    @Autowired
    private MyRealm myRealm;
 
    //配置SecurityManager
    @Bean
    public 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内置过滤器拦截范围
    @Bean
    public 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")
    @ResponseBoby
    public String userLogin(String name,String pwd){
        //1.获取subject对象
        Subject subject = SecurityUtils.getSubject();
        //2.封装请求数据到token
        AuthenticationToken token = new UsernamePasswordToken(name,pwd);
        //3.调用login方法进行登录认证
        try{        
            subject.login(token);
            return "登录成功";
        }catch(AuthenticationException e){
            e.printStackTrace();
            System.out.println("登录失败");
            return "登录失败";
        }
}

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

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

相关文章

RabbitMQ笔记-RabbitMQ基本术语

RabbitMQ基本术语 相关概念; 生产者&#xff08;Producer&#xff09;&#xff1a;投递消息。消息&#xff1a;消息体&#xff08;payload&#xff09;标签&#xff08;label&#xff09;&#xff1b;生产者把消息交给rabbitmq&#xff0c;rabbitmq会根据标签把消息发给感兴趣…

【自动驾驶】TI SK-TDA4VM 开发板上电调试,AI Demo运行

1. 设备清单 TDA4VM Edge AI 入门套件【略】USB 摄像头(任何符合 V4L2 标准的 1MP/2MP 摄像头,例如:罗技 C270/C920/C922)全高清 eDP/HDMI 显示屏最低 16GB 高性能 SD 卡连接到互联网的 100Base-T 以太网电缆【略】UART电缆外部电源或电源附件要求: 标称输出电压:5-20VDC…

第1章:计算机网络体系结构

文章目录 1.1 计算机网络 概述1.概念2.组成3.功能4.分类5.性能指标1.2 计算机网络 体系结构&参考模型1.分层结构2.协议、接口、服务3.ISO/OSI模型4.TCP/IP模型1.1 计算机网络 概述 1.概念 2.组成 1.组成部分&

多线程基础篇(包教包会)

文章目录 一、第一个多线程程序1.Jconsole观察线程2.线程休眠-sleep 二、创建线程三、Thread类及常见方法1. Thread 的常见构造方法2. Thread 的几个常见属性3. 启动线程 - start4. 中断线程5. 等待一个线程 四、线程状态五、线程安全问题(synchronized)&#xff08;重点&#…

深入理解回调函数qsort:从入门到模拟实现

&#x1f341;博客主页&#xff1a;江池俊的博客 &#x1f4ab;收录专栏&#xff1a;C语言进阶之路 &#x1f4a1;代码仓库&#xff1a;江池俊的代码仓库 &#x1f3aa;我的社区&#xff1a;GeekHub &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐ 文章目录 前…

七夕学算法

目录 P1031 [NOIP2002 提高组] 均分纸牌 原题链接 : 题面 : 思路 : 代码 : P1036 [NOIP2002 普及组] 选数 原题链接 : 题面 : 思路 : 代码 : P1060 [NOIP2006 普及组] 开心的金明 原题链接 : 题面 : 思路 : 01背包例题 : 代码 : P1100 高低位交换 原题…

HarmonyOS开发第一步,熟知开发工具DevEco Studio

俗话说的好&#xff0c;工欲善其事&#xff0c;必先利其器&#xff0c;走进HarmonyOS第一步&#xff0c;开发工具必须先行&#xff0c;当然了&#xff0c;关于开发工具的使用&#xff0c;官网和其他的博客也有很多的讲解&#xff0c;但是并没有按照常用的功能进行概述&#xff…

诚迈科技子公司智达诚远与Unity中国达成合作,打造智能座舱新时代

2023 年 8 月 23 日&#xff0c;全球领先的实时 3D 引擎 Unity 在华合资公司 Unity 中国举办发布会&#xff0c;正式对外发布 Unity 引擎中国版——团结引擎&#xff0c;并带来专为次世代汽车智能座舱打造的团结引擎车机版。发布会上&#xff0c;诚迈科技副总裁、诚迈科技子公司…

python中的matplotlib画折线图(数据分析与可视化)

先导包&#xff08;必须安装了numpy 、pandas 和matplotlib才能导包&#xff09;&#xff1a; import numpy as np import pandas as pd import matplotlib.pyplot as plt核心代码&#xff1a; import numpy as np import pandas as pd import matplotlib.pyplot as pltpd.se…

Android初学之android studio运行java/kotlin程序

第一步骤&#xff1a;File—>New—>New Module&#xff0c;然后弹出一个框&#xff0c;&#xff08;左边&#xff09;选择Java or Kotlin Library&#xff0c;&#xff08;右边&#xff09;编辑自己的图书馆名、包名、类名&#xff0c;选择Java一个语言&#xff0c;然后F…

LeetCode42.接雨水

这道题呢可以按列来累加&#xff0c;就是先算第1列的水的高度然后再加上第2列水的高度……一直加到最后就是能加的水的高度&#xff0c;我想到了这里然后就想第i列的水其实就是第i-1列和i1列中最小的高度减去第i列的高度&#xff0c;但是其实并不是&#xff0c;比如示例中的第5…

计算机竞赛 基于LSTM的天气预测 - 时间序列预测

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 机器学习大数据分析项目 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/po…

SQL地址门牌排序,字典序转为数字序

页面有一批地址数据查询&#xff0c;结果字符排序默认是字典序的&#xff0c;所以造成了门牌3号在30号之前&#xff0c;影响用户体验&#xff1b; id, road_code, road_name, address_fullname, address_name 102 10086 人民一路 北江省南海市西湖区人民一路3号 3号 103 10086…

Java设计模式-抽象工厂模式

简介 设计模式是软件设计中的一种常见方法&#xff0c;通过定义一系列通用的解决方案&#xff0c;来解决常见的软件设计问题。其中&#xff0c;抽象工厂模式是一种非常常见的设计模式&#xff0c;它可以帮助我们创建一组相关的对象&#xff0c;而不需要指定具体的实现方式。 …

Unity 3D之 利用Vector3 计算移动方向,以及实现位移多少

文章目录 先分析代码&#xff0c;从代码中了解Vector3 moveDirection new Vector3(10f, 0f, 100f);合法吗Vector3 moveDirection new Vector3 (xf,yf,zf)不是用来表示三维坐标的怎么表示在某个方向的位移 先分析代码&#xff0c;从代码中了解 这段代码是一个在游戏开发中常见…

Tushare入门小册

Tushare入门小册 一、Tushare平台介绍 Pro版数据更稳定质量更好了&#xff0c;我们提供的不再是直接从互联网抓取&#xff0c;而是通过社区的采集和整理存入数据库经过质量控制后再提供给用户。但Pro依然是个开放的&#xff0c;免费的平台&#xff0c;不带任何商业性质和目的…

【C修炼计划】卷壹 · 初识C语言

文章目录 卷壹 初识C语言一 C语言的起源二 C语言的特性三 C语言的应用范围四 C语言程序结构五 C语言书写规范六 C语言编译器安装附 参考资料 卷壹 初识C语言 一 C语言的起源 C语言的前生是B语言&#xff08;BCPL&#xff0c;一种早期的高级语言&#xff09;。下图描…

【Python原创毕设|课设】基于Python Flask的上海美食信息与可视化宣传网站项目-文末附下载方式以及往届优秀论文,原创项目其他均为抄袭

基于Python Flask的上海美食信息与可视化宣传网站&#xff08;获取方式访问文末官网&#xff09; 一、项目简介二、开发环境三、项目技术四、功能结构五、运行截图六、功能实现七、数据库设计八、源码获取 一、项目简介 随着大数据和人工智能技术的迅速发展&#xff0c;我们设…

PySide6学习笔记--gui小模版使用

一、界面绘制 1.desiner画图 2.画图代码 # -*- coding: utf-8 -*-################################################################################ ## Form generated from reading UI file t1gui.ui ## ## Created by: Qt User Interface Compiler version 6.5.2 ## ##…

驱动开发——字符设备

字符设备 Linux 将系统设备分为&#xff1a;字符设备、块设备、网络设备。工作原理 字符设备是 Linux 驱动中最基本的一类设备驱动&#xff0c;字符设备就是一个一个字节&#xff0c; 按照字节流进行读写操作的设备&#xff0c;读写数据是分先后顺序的。在Linux的世界里面一切…