当前位置: 首页 > news >正文

Spring Boot 3 集成 Spring Security(3)数据管理

文章目录

    • 准备工作
      • 新建项目
      • 引入MyBatis-Plus依赖
      • 创建表结构
      • 生成基础代码
    • 逻辑实现
      • `application.yml`配置
      • SecurityConfig 配置
      • 自定义 UserDetailsService
      • 创建测试
    • 启动测试

在前面的文章中我们介绍了 《Spring Boot 3 集成 Spring Security(1)认证》和 《Spring Boot 3 集成 Spring Security(2)授权》,这篇博客将介绍如何在 Spring Boot 3 项目中,整合 Spring Security 和 MyBatis-Plus ,轻松实现基于数据库的用户访问控制、权限管理。

准备工作

新建项目

springboot3-security-mysql-example 引入依赖

在这里插入图片描述

引入MyBatis-Plus依赖

MyBatis-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

注意事项

版本 3.5.9+ 开始修改为可选依赖,具体查看下文 maven bom 部分。

  <mybatisplus.version>3.5.9</mybatisplus.version>
    <!-- MyBatis-Plus https://baomidou.com--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-jsqlparser</artifactId></dependency>
    <dependencyManagement><dependencies><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-bom</artifactId><version>${mybatisplus.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>

创建表结构

这里我们定义三张表,来实现用户角色权限的操作

在这里插入图片描述

-- 用户表
CREATE TABLE `sys_user` (`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'ID',`username` VARCHAR ( 64 ) DEFAULT NULL COMMENT '用户名',`password` VARCHAR ( 64 ) DEFAULT NULL COMMENT '密码',`sex` CHAR ( 1 ) DEFAULT '0' COMMENT '性别 0 男 1 女 2 未知',`nick_name` VARCHAR ( 64 ) DEFAULT NULL COMMENT '昵称',`status` CHAR ( 1 ) DEFAULT '1' COMMENT '账号状态 0 禁用 1 启用',`valid` INT DEFAULT '1' COMMENT '有效状态 0 无效 1 有效',
PRIMARY KEY ( `id` ) 
) ENGINE = INNODB COMMENT = '用户';INSERT INTO `sys_user` (`id`, `username`, `password`, `sex`, `nick_name`, `status`, `valid`) VALUES (1, 'admin', '$2a$10$xZdonloiiL6YfoLZv6mrJuvxtD238uHPIKkVDpQKBuZxzMDpTf8uK', '0', '管理员张三', '1', 1);
INSERT INTO `sys_user` (`id`, `username`, `password`, `sex`, `nick_name`, `status`, `valid`) VALUES (2, 'user', '$2a$10$evM9SfvuN/E.ykWWOf6b3eTltPvuc6XjwW/qIhagSjlsTfi9l26Ba', '0', '用户李四', '1', 1);-- 角色表
CREATE TABLE `sys_role` (`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'ID',`name` VARCHAR ( 64 ) DEFAULT NULL COMMENT '角色名',`code` VARCHAR ( 64 ) DEFAULT NULL COMMENT '密码',`status` CHAR ( 1 ) DEFAULT '1' COMMENT '状态 0 禁用 1 启用',`valid` INT DEFAULT '1' COMMENT '有效状态 0 无效 1 有效',
PRIMARY KEY ( `id` ) 
) ENGINE = INNODB COMMENT = '角色';INSERT INTO `sys_role` (`id`, `name`, `code`, `status`, `valid`) VALUES (1, '管理员', 'ROOT', '1', 1);
INSERT INTO `sys_role` (`id`, `name`, `code`, `status`, `valid`) VALUES (2, '普通用户', 'USER', '1', 1);-- 用户角色关系表
CREATE TABLE `sys_user_role` (`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'ID',`user_id` bigint DEFAULT NULL COMMENT '用户ID',`role_id` bigint DEFAULT NULL COMMENT '角色ID',PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB COMMENT = '用户角色关系表';INSERT INTO `sys_user_role` (`id`, `user_id`, `role_id`) VALUES (1, 1, 1);
INSERT INTO `sys_user_role` (`id`, `user_id`, `role_id`) VALUES (2, 2, 2);

默认设置账户密码123456,在数据库中使用加密后的密码,关于密码加密,可以使用下面的测试方法。

    public static void main(String[] args) {BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();String result = encoder.encode("123456");// 输出加密后的密码System.out.println(result);// 对比加密后的密码和明文密码System.out.println(encoder.matches("123456", result));}

生成基础代码

这里我用了代码生成器插件,以提高生产效率,想具体了解,可以去官网上搭建使用。这里就不多说啦

在这里插入图片描述

本地代码勾选,使用 mybatis-plus 3

在这里插入图片描述

在这里插入图片描述

准备工作到这里基本上就可以了,接下来开始实现从数据库中读取用户角色权限

逻辑实现

application.yml配置

spring:thymeleaf:# 设置Thymeleaf模板文件的前缀位置(默认是`src/main/resources/templates`)prefix: classpath:/templates/# 设置模板文件的后缀(默认是`.html`)suffix: .html# 设置模板模式(默认是HTML5,Thymeleaf 3中为`HTML`)mode: HTML# 开启模板缓存(开发时建议关闭,生产时开启)cache: falsedatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/security_data?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: root#mybatis
mybatis-plus:mapper-locations: classpath*:/mapper/**/*.xml#实体扫描,多个package用逗号或者分号分隔typeAliasesPackage: cn.harry.*.domainglobal-config:#数据库相关配置db-config:#主键类型  AUTO:"数据库ID自增", INPUT:"用户输入ID", ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";id-type: AUTO# 逻辑删除全局属性名(驼峰和下划线都支持)logic-delete-field: validlogic-delete-value: 0 # 逻辑已删除值(默认为 1)logic-not-delete-value: 1 # 逻辑未删除值(默认为 0)banner: false#原生配置configuration:map-underscore-to-camel-case: truecache-enabled: falsecall-setters-on-nulls: truejdbc-type-for-null: 'null'# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

SecurityConfig 配置

要使用 Spring Security 进行用户认证,我们需要配置 SecurityConfig,并实现自定义的 UserDetailsService 来与数据库中的用户信息进行集成。


/*** @author harry* @公众号 Harry技术*/
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true) // 开启方法级别的权限控制
@RequiredArgsConstructor
public class SecurityConfig {// 通过构造函数注入自定义UserDetailsServiceprivate final UserDetailsService userDetailsService;@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(auth -> auth// 公开访问.requestMatchers("/").permitAll()// 其他接口需认证.anyRequest().authenticated()).userDetailsService(userDetailsService)
//                .exceptionHandling(exception -> exception
//                        .authenticationEntryPoint(restAuthenticationEntryPoint)
//                        .accessDeniedHandler(restfulAccessDeniedHandler)
//                )// 开启基于表单的登录.formLogin(Customizer.withDefaults())//                // 开启注销功能
//                .logout(Customizer.withDefaults())
//                // 开启 HTTP Basic 认证
//                .httpBasic(Customizer.withDefaults())
//                // 开启 CSRF 防护
//                .csrf(Customizer.withDefaults())
//                // 开启跨域资源共享
//                .cors(Customizer.withDefaults());return http.build();}@Beanpublic PasswordEncoder passwordEncoder() {// 使用 BCrypt 进行密码加密return new BCryptPasswordEncoder();}

自定义 UserDetailsService

想从数据库加载用户信息,就需要创建一个自定义的 UserDetailsService 实现类,它的主要作用:

用户认证:
UserDetailsService 负责从数据源(如数据库、LDAP等)中加载用户特定的安全信息,包括用户名、密码和权限(角色)。
Spring Security 使用 UserDetailsService 来验证用户提供的凭据是否正确。
用户授权:
加载用户的权限信息,以便在认证成功后进行授权检查。
权限信息通常包括用户的角色(如 ROLE_ADMIN, ROLE_USER 等),这些角色用于控制用户可以访问的资源和操作。

/*** 系统用户认证  service** @author harry* @公众号 Harry技术*/
@Slf4j
@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {private final SysUserMapper sysUserMapper;private final SysUserRoleMapper sysUserRoleMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {try {// 获取登录用户信息SysUser user = sysUserMapper.selectByUsername(username);// 用户不存在、用户停用 等校验 TODOLong useId = user.getId();// 获取角色Set<String> roles = sysUserRoleMapper.listRoleKeyByUserId(useId);return new SysUserDetails(user, roles, username);} catch (Exception e) {log.error("loadUserByUsername error", e);}return null;}
}

我们根据数据库中的用户信息加载用户,并将角色转换为 Spring Security 能识别的格式。我们写一个SysUserDetails类来实现自定义Spring Security 用户对象。


/*** 自定义 Spring Security 用户对象** @author harry* @公众号 Harry技术*/
@Data
@NoArgsConstructor
public class SysUserDetails implements UserDetails {private String username;private SysUser sysUser;private Collection<SimpleGrantedAuthority> authorities;public SysUserDetails(SysUser user, Set<String> roles, String username) {this.sysUser = user;Set<SimpleGrantedAuthority> authorities;if (CollectionUtil.isNotEmpty(roles)) {// 标识角色 前面加上 ROLE_authorities = roles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).collect(Collectors.toSet());} else {authorities = Collections.emptySet();}this.authorities = authorities;this.username = username;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {// 返回当前用户的权限return authorities;}@Overridepublic String getPassword() {return sysUser.getPassword();}@Overridepublic String getUsername() {return this.username;}/*** 是否可用 ,禁用的用户不能身份验证** @return 是否可用*/@Overridepublic boolean isEnabled() {return StatusEnums.ENABLE.getKey().equals(sysUser.getStatus());}
}

创建测试

  • 页面
  <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title><style>.content {width: 800px;height: 800px;text-align: center;line-height: 100px;font-size: 20px;flex: 1;flex-direction: column;display: flex;justify-content: center;align-items: center;}</style></head><body><div class="content"><!--去登陆 --><a href="/login">去登陆</a><!-- admin/info 接口 --><a href="/admin/info">访问 admin/info 接口</a><!-- 去首页 --><a href="/user/info">访问 user/info 接口</a><!--退出--><a href="/logout">退出</a></div></body></html>
  • 接口

    改写接口admin/info,并配置 @PreAuthorize("hasRole('ROOT')")只有 ADMIN 角色才能访问

  /*** @author harry* @公众号 Harry技术* Spring Boot 3 集成 Spring Security(2) 授权: https://mp.weixin.qq.com/s/HzzcYIQLnch_7r7wdUarew*/@Slf4j@RestControllerpublic class AdminController {@GetMapping("/admin/info")@PreAuthorize("hasRole('ROOT')")  // 只有 ADMIN 角色才能访问public SysUserDetails adminInfo() {// 获取当前登录的用户信息SysUserDetails user = (SysUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();log.info("当前登录的用户信息:{}", user.toString());return user;}}

改写接口user/info,并配置 @PreAuthorize("hasRole('USER')")只有 USER 角色才能访问

      @Slf4j@RestControllerpublic class UserController {@GetMapping("/user/info")@PreAuthorize("hasRole('USER')")  // 只有 user 角色才能访问public SysUserDetails userInfo() {// 获取当前登录的用户信息SysUserDetails user = (SysUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();log.info("当前登录的用户信息:{}", user.toString());return user;}}

启动测试

  • 1.登录admin账户

访问 admin/info 接口

在这里插入图片描述

访问 user/info 接口

在这里插入图片描述

  • 2.登录user用户

访问 admin/info 接口

在这里插入图片描述

访问 user/info 接口

在这里插入图片描述

通过上面的测试用例,通过定义用户和角色实体、实现自定义的 UserDetailsService,实现了数据库驱动的用户认证和基于角色的授权机制。这种结合方式不仅在安全性上提供了极大的灵活性,也让数据管理变得更加简洁高效。

关注我,在后续的文章中,我们进一步探讨如果使用JWT、OAuth2 等机制、使用Redis作为缓存来强化认证与授权的实现。

示例源码:关注公众号“Harry技术”,回复 security 获取源码地址。

相关文章:

Spring Boot 3 集成 Spring Security(3)数据管理

文章目录 准备工作新建项目引入MyBatis-Plus依赖创建表结构生成基础代码 逻辑实现application.yml配置SecurityConfig 配置自定义 UserDetailsService创建测试 启动测试 在前面的文章中我们介绍了 《Spring Boot 3 集成 Spring Security&#xff08;1&#xff09;认证》和 《…...

书生大模型实战营第四期-入门岛-4. maas课程任务

书生大模型实战营第四期-入门岛-4. maas课程任务 任务一、模型下载 任务内容 使用Hugging Face平台、魔搭社区平台&#xff08;可选&#xff09;和魔乐社区平台&#xff08;可选&#xff09;下载文档中提到的模型&#xff08;至少需要下载config.json文件、model.safetensor…...

Spring ApplicationListener监听

【JavaWeb】Spring ApplicationListener-CSDN博客 ApplicationEvent以及Listener是Spring为我们提供的一个事件监听、订阅的实现&#xff0c;内部实现原理是观察者设计模式&#xff0c;设计初衷也是为了系统业务逻辑之间的解耦&#xff0c;提高可扩展性以及可维护性。事件发布…...

K8s调度器扩展(scheduler)

1.K8S调度器 筛选插件扩展 为了熟悉 K8S调度器扩展步骤&#xff0c;目前只修改 筛选 插件 准备环境&#xff08;到GitHub直接下载压缩包&#xff0c;然后解压&#xff0c;解压要在Linux系统下完成&#xff09; 2. 编写调度器插件代码 在 Kubernetes 源代码目录下编写调度插件…...

IntelliJ IDEA 中,自动导包功能

在 IntelliJ IDEA 中&#xff0c;自动导包功能可以极大地提高开发效率&#xff0c;减少手动导入包所带来的繁琐和错误。以下是如何在 IntelliJ IDEA 中设置和使用自动导包功能的详细步骤&#xff1a; 一、设置自动导包 打开 IntelliJ IDEA&#xff1a; 启动 IntelliJ IDEA 并打…...

Spring事务笔记

目录 1.Spring 编程式事务 2.Transactional 3.事务隔离级别 4.Spring 事务传播机制 什么是事务? 事务是⼀组操作的集合, 是⼀个不可分割的操作. 事务会把所有的操作作为⼀个整体, ⼀起向数据库提交或者是撤销操作请求. 所以这组操作要么同时成 功, 要么同时失败 1.Spri…...

SQLite 管理工具 SQLiteStudio 3.4.5 发布

SQLiteStudio 3.4.5 版本现已发布&#xff0c;它带来了大量的 bug 修复&#xff0c;并增加了一些小功能。SQLiteStudio 是一个跨平台的 SQLite 数据库的管理工具。 具体更新内容包括&#xff1a; 现在可以使用 Collations Editor 窗口在数据库中注册 Extension-based collatio…...

QT 实现组织树状图

1.实现效果 在Qt中使用QGraphicsItem和QGraphicsScene实现树状图,你需要创建自定义的QGraphicsItem类来表示树的节点,并管理它们的位置和连接,以下是实现效果图。 2.实现思路 可以看见,上图所示,我们需要自定义连线类和节点类。 每个节点类Node,需要绘制矩形框体文字…...

go-学习

文章目录 简介标识符字符串的拼接&#xff0c;关键字数据类型声明变量常量算术运算符关系运算符逻辑运算符位运算赋值运算符其他运算符 简介 Go 语言的基础组成有以下几个部分&#xff1a; 1.包声明 2.引入包 3.函数 4.变量 5.语句 & 表达式 6.注释 package main import &q…...

【面试分享】主流编程语言的内存回收机制及其优缺点

以下是几种主流编程语言的内存回收机制及其优缺点&#xff1a; 一、Java 内存回收机制&#xff1a; Java 使用自动内存管理&#xff0c;主要通过垃圾回收器&#xff08;Garbage Collector&#xff0c;GC&#xff09;来回收不再被使用的对象所占用的内存。Java 的垃圾回收器会定…...

STM32-- 串口发送数据

while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)RESET);&#xff1f;&#xff1f; 答&#xff1a; 这行代码&#xff1a; while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) RESET);的作用是等待串口 USART2 的发送数据寄存器&#xff08;TXE&#xff0c;Transmit Dat…...

数据结构 (13)串的应用举例

前言 数据结构中的串&#xff08;String&#xff09;&#xff0c;也称为字符串&#xff0c;是一种常见且重要的数据结构&#xff0c;在计算机科学中被广泛应用于各种场景。 一、文本处理 文本编辑器&#xff1a;在文本编辑器中&#xff0c;字符串被用来表示和存储用户输入的文本…...

qt-- - 版本和下载介绍

qt版本很多&#xff0c;每个大版本都有几个版本是长期支持的&#xff08;LTS&#xff09;&#xff0c;最好使用长期支持的。 例如qt5.15 qt6.2 qt6.8 都是LTS版本的。 qt在线安装需要提供账号&#xff0c;之前安装qt6.8因为账号问题试了很长时间&#xff0c;密码错了。 …...

解锁 Vue 项目中 TSX 配置与应用简单攻略

在 Vue 项目中配置 TSX 写法 在 Vue 项目中使用 TSX 可以为我们带来更灵活、高效的开发体验&#xff0c;特别是在处理复杂组件逻辑和动态渲染时。以下是详细的配置步骤&#xff1a; 一、安装相关依赖 首先&#xff0c;我们需要在命令行中输入以下命令来安装 vitejs/plugin-v…...

ShuffleNet:一种为移动设备设计的极致高效的卷积神经网络

摘要 https://arxiv.org/pdf/1707.01083 我们介绍了一种名为ShuffleNet的计算效率极高的卷积神经网络&#xff08;CNN&#xff09;架构&#xff0c;该架构专为计算能力非常有限的移动设备&#xff08;例如10-150 MFLOPs&#xff09;而设计。新架构利用两种新操作&#xff1a;逐…...

yum源问题的解决方案

linux课堂作业 问题描述 yum 直接安装tree的问题截图 这个错误表明你的系统没有正确注册到 Red Hat Subscription Management&#xff08;这个问题不用管&#xff09;&#xff0c;也没有配置有效的 YUM 软件仓库&#xff0c;因此无法安装或更新软件包。 解决方案&#xff08…...

在Linux中备份msyql数据库和表的详细操作

目录 前情提要 一、备份mysql数据库 原库展示 (一)新建一个数据库 (二)在linux根目录下找个位置暂时存放 (三)临时sql还原真正存放到库中 (四)查看是否备份成功 备份库成功展示 二、备份表的操作 ​编辑 原表emp展示 (一)快速新建一个原结构相同的表 (二)原表所…...

实时数仓Kappa架构:从入门到实战

引言 随着大数据技术的不断发展&#xff0c;企业对实时数据处理和分析的需求日益增长。实时数仓&#xff08;Real-Time Data Warehouse, RTDW&#xff09;应运而生&#xff0c;其中Kappa架构作为一种简化的数据处理架构&#xff0c;通过统一的流处理框架&#xff0c;解决了传统…...

【老白学 Java】Warship v2.0(四)

Warship v2.0&#xff08;四&#xff09; 文章来源&#xff1a;《Head First Java》修炼感悟。 上一篇文章中&#xff0c;老白仔细分析了 v2.0 的设计思路以及实现手段&#xff0c;如果大家有好的设计方案也可以自行尝试。 本篇文章的主要内容是对 Warship 类进行最后的修改&a…...

LLM之学习笔记(一)

前言 记录一下自己的学习历程&#xff0c;也怕自己忘掉了某些知识点 Prefix LM 和 Causal LM区别是什么&#xff1f; Prefix LM &#xff08;前缀语⾔模型&#xff09;和 Causal LM&#xff08;因果语言模型&#xff09;是两者不同类型的语言模型&#xff0c;它们的区别在于生…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...