整合SaToken 实现登录功能

整合SaToken 实现登录功能

1.整合redis

1.1添加相关依赖

        // 省略...<!-- Redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- Redis 连接池 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>// 省略...

1.2添加配置

spring:datasource:// 省略...data:redis:database: 0 # Redis 数据库索引(默认为 0)host: 127.0.0.1 # Redis 服务器地址port: 6379 # Redis 服务器连接端口password:  # Redis 服务器连接密码(默认为空)timeout: 5s # 读超时时间connect-timeout: 5s # 链接超时时间lettuce:pool:max-active: 200 # 连接池最大连接数max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)min-idle: 0 # 连接池中的最小空闲连接max-idle: 10 # 连接池中的最大空闲连接    

1.3自定义 RedisTemplate

@Configuration
public class RedisTemplateConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();// 设置 RedisTemplate 的连接工厂redisTemplate.setConnectionFactory(connectionFactory);// 使用 StringRedisSerializer 来序列化和反序列化 redis 的 key 值,确保 key 是可读的字符串redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());// 使用 Jackson2JsonRedisSerializer 来序列化和反序列化 redis 的 value 值, 确保存储的是 JSON 格式Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);redisTemplate.setValueSerializer(serializer);redisTemplate.setHashValueSerializer(serializer);redisTemplate.afterPropertiesSet();return redisTemplate;}
}

2.鉴权设计:RBAC 权限模型

什么是 RBAC 模型?

RBAC(Role-Based Access Control)是一种基于角色的访问控制。它通过角色来管理用户的权限。RBAC 的核心思想是将用户与角色进行关联,并将权限分配给角色,而不是直接分配给用户。这样,通过改变用户的角色,就可以灵活地控制用户的权限。

RBAC 的主要组成部分包括:

  • 用户(User):系统的使用者。
  • 角色(Role):权限的集合,一个角色可以包含多个权限。
  • 权限(Permission):对系统资源的访问操作,如读取、写入、删除等。

RBAC 1:基于角色的层次模型(Role Hierarchies)

RBAC 1 在 RBAC 0 的基础上增加了角色层次结构(Role Hierarchies)。角色层次结构允许角色之间存在继承关系,一个角色可以继承另一个角色的权限。

主要特点
  • 角色继承:一个角色可以继承另一个角色的所有权限。比如,角色B继承角色 A 的权限,那么角色 B 不仅拥有自己定义的权限,还拥有角色 A 的所有权限。
  • 权限传递:继承关系是传递的,如果角色 C 继承角色 B,而角色 B 继承角色 A,那么角色 C 将拥有角色 A 和角色 B 的所有权限。
优点
  • 简化权限管理:通过角色继承,可以减少重复定义权限的工作。
  • 提高灵活性:可以方便地对角色进行分层管理,满足不同层次用户的权限需求。
场景举例

在一个企业系统中,高级经理(Senior Manager)角色继承经理(Manager)角色的权限,经理角色继承员工(Employee)角色的权限。这样,高级经理角色不仅拥有自己的权限,还拥有经理和员工的所有权限。

RBAC 2:基于约束的 RBAC 模型(Constraints)

RBAC 2 同样建立在 RBAC 0 基础之上,但是增加了约束(Constraints)。约束是用于加强访问控制策略的规则或条件,可以限制用户、角色和权限的关联方式。

主要特点
  • 互斥角色:某些角色不能同时赋予同一个用户。例如,审计员和财务员角色不能同时赋予同一个用户,以避免暗黑交易。
  • 先决条件:用户要获得某个角色,必须先拥有另一个角色。例如,公司研发人员要成为高级程序员,必须先成为中级程序员。
  • 基数约束:限制某个角色可以被赋予的用户数量。例如,某个项目的经理角色只能赋予一个用户,以确保项目的唯一责任人。
优点:
  • 加强安全性:通过约束规则,可以避免权限滥用和利益冲突。
  • 精细化管理:可以更精细地控制用户的角色分配和权限管理。
场景举例

在一个金融系统中,为了避免利益冲突,定义了互斥角色规则:审计员和财务员角色不能同时赋予同一个用户。这样可以确保审计员和财务员的职责分离,增强系统的安全性。

RBAC 3:统一模型(Consolidated Model)

RBAC 3 是最全面的 RBAC 模型,它结合了 RBAC1 的角色层次结构和 RBAC2 的约束,形成一个统一的模型,提供了最大程度的灵活性和安全性。

主要特点
  • 包含RBAC 1的所有功能:角色层次结构,角色继承和权限传递。
  • 包含RBAC 2的所有功能:互斥角色、先决条件角色和角色卡数限制等约束规则。
  • 综合管理:可以同时利用角色继承和约束规则,提供最全面的权限管理解决方案。
优点
  • 高灵活性:可以满足各种复杂的权限管理需求。
  • 高安全性:通过约束规则,进一步加强权限管理的安全性。
场景举例

在一个大型企业系统中,需要复杂的权限管理策略。RBAC 3 模型可以通过角色层次结构定义不同层级的员工权限,通过约束规则确保权限分配的安全性。例如,高级经理角色继承经理角色的权限,但为了避免利益冲突,财务员和审计员角色互斥,不能同时赋予同一个用户。

基于 RBAC 的延展:用户组

在实际业务场景中,举个栗子,比如销售部门,分配到此部门的员工都是销售员,拥有同一类角色。如果要为每一个员工手动分配角色,就显得非常繁琐了,而且容易出错。于是乎,在系统设计上,引入了用户组的概念,我们可以把销售部看成一个用户组,对用户组提前分配好角色,这样后续只需将员工拉入该部门,即可拥有该部门已分配的权限。

RBAC 模型是为了更加灵活的控制权限。那么问题来了,需要控制的权限通常都有哪些?

在系统设计时,通常你需要考虑以下几类权限:

  1. 菜单权限:控制用户在管理后台中,可以看到的菜单项与页面。
  2. 操作权限:控制用户可以执行的具体操作。比如新增、删除、修改按钮的权限。
  3. 数据权限:控制用户可以访问的数据范围。比如只能看到本部门的数据,其他部门的员工登录则无法查看。
  4. 字段权限:控制用户可以查看或编辑的字段。
  5. 等等…

具体还得结合你的业务来,没有绝对,毕竟技术服务于业务。

3.RBAC 权限表设计、微服务鉴权架构设计

  • 角色表;
  • 权限表;
  • 角色权限关联表;
  • 用户角色关联表;
CREATE TABLE `t_role` (`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',`role_name` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色名',`role_key` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色唯一标识',`status` tinyint NOT NULL DEFAULT '0' COMMENT '状态(0:启用 1:禁用)',`sort` int unsigned NOT NULL DEFAULT 0 COMMENT '管理系统中的显示顺序',`remark` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后一次更新时间',`is_deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除(0:未删除 1:已删除)',PRIMARY KEY (`id`) USING BTREE,UNIQUE KEY `uk_role_key` (`role_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色表';
CREATE TABLE `t_permission` (`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',`parent_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '父ID',`name` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '权限名称',`type` tinyint unsigned NOT NULL COMMENT '类型(1:目录 2:菜单 3:按钮)',`menu_url` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '菜单路由',`menu_icon` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '菜单图标',`sort` int unsigned NOT NULL DEFAULT 0 COMMENT '管理系统中的显示顺序',`permission_key` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '权限标识',`status` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '状态(0:启用;1:禁用)',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',`is_deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除(0:未删除 1:已删除)',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='权限表';
CREATE TABLE `t_user_role_rel` (`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',`user_id` bigint unsigned NOT NULL COMMENT '用户ID',`role_id` bigint unsigned NOT NULL COMMENT '角色ID',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',`is_deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除(0:未删除 1:已删除)',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户角色表';
CREATE TABLE `t_role_permission_rel` (`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',`role_id` bigint unsigned NOT NULL COMMENT '角色ID',`permission_id` bigint unsigned NOT NULL COMMENT '权限ID',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',`is_deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '逻辑删除(0:未删除 1:已删除)',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户权限表';

鉴权放哪里合适?

关于用户认证(登录),我们已经知道是通过认证服务来处理。那么问题来了,鉴权在哪一层处理呢?通常来说,有以下 3 种方案:

  1. 每个微服务各自鉴权
  2. 网关统一鉴权
  3. 混合策略
鉴权方案优点缺点
1. 每个微服务各自鉴权- 每个微服务独立处理鉴权,权限控制更细粒度。- 鉴权逻辑重复,增加了维护成本。
- 不利于全局权限管理,可能存在权限漏斗。
- 每个服务需要单独处理认证逻辑,可能影响性能。
2. 网关统一鉴权- 简化了每个微服务的鉴权逻辑,避免重复实现。
- 可以集中管理认证和授权,减少安全风险。
- 更易于实现权限的统一管理和更新。
- 网关成了单点故障,性能瓶颈容易产生。
- 如果网关配置出现问题,所有服务的访问都将受限。
- 可能增加网关的复杂度,影响响应速度。
3. 混合策略- 结合了两者的优点,在网关层进行基础鉴权,细粒度的权限控制在微服务内部处理。
- 灵活性高,可以针对不同场景选择不同策略。
- 配置和管理较复杂,可能导致维护困难。
- 需要较强的服务协作和协调,增加了系统的复杂度。

权限数据获取方案?

权限数据获取方案优点缺点
1. 权限数据存储在数据库中,按需查询- 权限数据存储持久化,数据持久性强,修改权限时只需更新数据库。
- 权限数据查询灵活,可以支持复杂的查询条件。
- 每次请求都需要查询数据库,增加了数据库压力,可能影响性能。
- 权限变化时需要及时同步到微服务或缓存。
2. 权限数据缓存到 Redis 中- 查询速度更快,减少数据库压力,适用于高并发场景。
- 可以在缓存中存储用户的权限数据,快速获取。
- 缓存过期机制可以保证数据的新鲜度。
- 数据一致性问题:缓存和数据库之间可能会出现数据不同步的情况。
- 需要额外的缓存管理机制(如缓存失效、更新等)。
3. 权限数据静态配置(硬编码到应用中)- 访问权限数据速度最快,直接嵌入到应用代码中,无需查询数据库或缓存。
- 配置简单,适合权限变化不频繁的场景。
- 权限管理不灵活,变动时需要重新部署应用。
- 随着权限管理的复杂性增加,代码难以维护。

4.SaToken 整合 Redis

添加依赖

	// 省略...<!-- 统一依赖管理 --><dependencyManagement><dependencies>// 省略...<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) --><dependency><groupId>cn.dev33</groupId><artifactId>sa-token-redis-jackson</artifactId><version>${sa-token.version}</version></dependency>// 省略...</dependencies></dependencyManagement>// 省略...<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) --><dependency><groupId>cn.dev33</groupId><artifactId>sa-token-redis-jackson</artifactId></dependency><!-- Redis 连接池 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>// 省略...// 省略...

为 SaToken 权限框架整合了 Redis , 让会话数据存储在了缓存中间件中,以保证项目重启后,登录状态不会失效。

5.同步【角色-权限集合】数据到 Redis 中

在 Spring Boot 项目中,可以通过多种方式在项目启动时执行初始化工作。以下是一些常见的方法:

1. 使用 @PostConstruct 注解

@PostConstruct 注解可以用于在 Spring 容器初始化 bean 之后立即执行特定的方法。

import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;@Component
public class MyInitializer {@PostConstructpublic void init() {// 初始化工作System.out.println("初始化工作完成");}
}

2. 实现 ApplicationRunner 接口

ApplicationRunner 接口提供了一种在 Spring Boot 应用启动后执行特定代码的方式。

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;@Component
public class MyApplicationRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {// 初始化工作System.out.println("初始化工作完成");}
}

3. 实现 CommandLineRunner 接口

CommandLineRunner 接口类似于 ApplicationRunner,可以在应用启动后执行代码。

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;@Component
public class MyCommandLineRunner implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {// 初始化工作System.out.println("初始化工作完成");}
}

4. 使用 @EventListener 注解监听 ApplicationReadyEvent

通过监听 ApplicationReadyEvent 事件,可以在 Spring Boot 应用完全启动并准备好服务请求时执行初始化工作。

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.boot.context.event.ApplicationReadyEvent;@Component
public class MyApplicationReadyListener {@EventListener(ApplicationReadyEvent.class)public void onApplicationReady() {// 初始化工作System.out.println("初始化工作完成");}
}

5. 使用 SmartInitializingSingleton 接口

SmartInitializingSingleton 接口提供了一种在所有单例 bean 初始化完成后执行代码的方式。

import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.stereotype.Component;@Component
public class MySmartInitializingSingleton implements SmartInitializingSingleton {@Overridepublic void afterSingletonsInstantiated() {// 初始化工作System.out.println("初始化工作完成");}
}

6. 使用 Spring Boot 的 InitializingBean 接口

通过实现 InitializingBean 接口的 afterPropertiesSet 方法,可以在 bean 的属性设置完成后执行初始化工作。

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;@Component
public class MyInitializingBean implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {// 初始化工作System.out.println("初始化工作完成");}
}

7. 总结

以上这些方法各有优缺点,可以根据具体的初始化需求选择合适的方法。

  • @PostConstruct:适合简单的初始化逻辑,执行时机较早。
  • ApplicationRunner 和 CommandLineRunner:适合需要访问命令行参数的初始化逻辑,执行时机在 Spring Boot 应用启动完成后。
  • ApplicationReadyEvent 监听器:适合在整个应用准备好后执行的初始化逻辑。
  • SmartInitializingSingleton:适合需要在所有单例 bean 初始化完成后执行的初始化逻辑。
  • InitializingBean:适合需要在 bean 属性设置完成后执行的初始化逻辑。

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

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

相关文章

Vue 项目中逐步引入 TypeScript 的类型检查

在现有的 Vue 项目中逐步引入 TypeScript 的类型检查 本文源于一道面试题&#xff1a;注&#xff1a;两种问法一个意思哈&#xff01;&#xff01; 问题一&#xff1a;“ 老项目Js写的&#xff0c;如何轻量方式享受 ts 类型&#xff1f;” 问题二&#xff1a;“如何 在现有的 …

python后端调用Deep Seek API

python后端调用Deep Seek API 需要依次下载 ●Ollama ●Deepseek R1 LLM模型 ●嵌入模型nomic-embed-text / bge-m3 ●AnythingLLM 参考教程&#xff1a; Deepseek R1打造本地化RAG知识库:安装部署使用详细教程 手把手教你&#xff1a;deepseek R1基于 AnythingLLM API 调用本地…

本地部署MindSearch(开源 AI 搜索引擎框架),然后上传到 hugging face的Spaces——L2G6

部署MindSearch到 hugging face Spaces上——L2G6 任务1 在 官方的MindSearch页面 复制Spaces应用到自己的Spaces下&#xff0c;Space 名称中需要包含 MindSearch 关键词&#xff0c;请在必要的步骤以及成功的对话测试结果当中 实现过程如下&#xff1a; 2.1 MindSearch 简…

matlab下载安装图文教程

【matlab介绍】 MATLAB是一款由美国MathWorks公司开发的专业计算软件&#xff0c;主要应用于数值计算、可视化程序设计、交互式程序设计等高科技计算环境。以下是关于MATLAB的简要介绍&#xff1a; MATLAB是MATrix LABoratory&#xff08;矩阵实验室&#xff09;的缩写&#…

捷米特 JM - RTU - TCP 网关应用 F - net 协议转 Modbus TCP 实现电脑控制流量计

一、项目背景 在某工业生产园区的供水系统中&#xff0c;为了精确监测和控制各个生产环节的用水流量&#xff0c;需要对分布在不同区域的多个流量计进行集中管理。这些流量计原本采用 F - net 协议进行数据传输&#xff0c;但园区的监控系统基于 Modbus TCP 协议进行数据交互&…

4.1 Hugging Face Datasets实战:构建企业级数据流水线

Hugging Face Datasets实战:构建企业级数据流水线 一、Datasets库核心优势 1.1 企业级数据处理需求全景 # 支持的数据格式示例 data_formats = {"结构化数据": ["CSV", "Parquet", "SQL"]

深入解析队列与广度优先搜索(BFS)的算法思想:原理、实现与应用

目录 1. 队列的基本概念 2. 广度优先搜索&#xff08;BFS&#xff09;的基本概念 3. 队列在BFS中的作用 4. BFS的实现细节 5. C实现BFS 6. BFS的应用场景 7. 复杂度分析 8. 总结 1. 队列的基本概念 队列&#xff08;Queue&#xff09;是一种先进先出&#xff08;FIFO, …

【学术投稿-第四届材料工程与应用力学国际学术会议(ICMEAAE 2025】材料工程与应用力学的探讨

重要信息 官网&#xff1a;www.icmeaae.com 时间&#xff1a;2025年3月7-9日 地点&#xff1a;中国西安 简介 第四届材料工程与应用力学&#xff08;ICMEAAE 2025&#xff09;将于2025年3月7日至9日在中国西安召开。本次会议将重点讨论材料科学、应用力学等领域的最新研究进…

间隔连续问题

间隔连续问题 1. 数据结构&#xff1a;某游戏公司记录的用户每日登录数据 表名&#xff1a;game_user 字段名&#xff1a;id&#xff08;用户id&#xff09;、dt&#xff08;日期&#xff09; 2. 需求&#xff1a; ① 创建表 ② 计算每个用户最大的连续登录天数&#xff0c…

EasyRTC轻量级SDK:智能硬件音视频通信资源的高效利用方案

在智能硬件这片广袤天地里&#xff0c;每一份资源的精打细算都关乎产品的生死存亡。随着物联网技术的疾速演进&#xff0c;实时音视频通信功能已成为众多设备的标配。然而&#xff0c;硬件资源的捉襟见肘&#xff0c;让开发者们常常陷入两难境地。EasyRTC&#xff0c;以它的极致…

神经网络剪枝技术的重大突破:sGLP-IB与sTLP-IB

神经网络剪枝技术的重大突破:sGLP-IB与sTLP-IB 在人工智能飞速发展的今天,深度学习技术已经成为推动计算机视觉、自然语言处理等领域的核心力量。然而,随着模型规模的不断膨胀,如何在有限的计算资源和存储条件下高效部署这些复杂的神经网络模型,成为了研究者们亟待解决的…

[AI相关]Unity的C#代码如何简写

是一个某培训机构的飞行棋教学源码 不知道&#xff0c;是否有人想知道怎么可以简写 &#xff08;这个问AI&#xff0c;DeepSeek也应该找不到答案的&#xff09; 静态变量 属性引用 单例 注入 一些UnityEvent特性就不说了。。。 IL 注入 运算符号改写

【Docker】容器被停止/删除的方式及命令:全面解析与实践指南

文章目录 引言一、容器的生命周期二、停止容器的命令及方式1. docker stop 命令2. docker kill 命令3. docker pause 和 docker unpause 命令4. docker restart 命令 三、删除容器的命令及方式1. docker rm 命令2. docker container prune 命令3. docker rm 与 docker rmi 的区…

Node.js技术原理分析系列——Node.js调试能力分析

本文由体验技术团队屈金雄原创。 Node.js 是一个开源的、跨平台的 JavaScript 运行时环境&#xff0c;它允许开发者在服务器端运行 JavaScript 代码。Node.js 是基于 Chrome V8引擎构建的&#xff0c;专为高性能、高并发的网络应用而设计&#xff0c;广泛应用于构建服务器端应…

轻松搭建本地大语言模型(二)Open-WebUI安装与使用

文章目录 前置条件目标一、安装 Open-WebUI使用 Docker 部署 二、使用 Open-WebUI&#xff08;一&#xff09;访问Open-WebUI&#xff08;二&#xff09;注册账号&#xff08;三&#xff09;模型选择&#xff08;四&#xff09;交互 四、常见问题&#xff08;一&#xff09;容器…

阿里云百炼通义大模型

阿里云百炼通义大模型 Part one&#xff08;阿里云百炼大模型&#xff09;一、什么是百炼&#xff08;一&#xff09;调用大模型 二、支持的大模型三、模型总览四、为什么选择百炼&#xff1f;五、开始使用百炼Part two一、开发参考二、模型调用&#xff08;一&#xff09;通义…

Golang学习笔记_33——桥接模式

Golang学习笔记_30——建造者模式 Golang学习笔记_31——原型模式 Golang学习笔记_32——适配器模式 文章目录 桥接模式详解一、桥接模式核心概念1. 定义2. 解决的问题3. 核心角色4. 类图 二、桥接模式的特点三、适用场景1. 多维度变化2. 跨平台开发3. 动态切换实现 四、与其他…

低代码(Low Code)全解析:从概念到应用,从选择到价值

​在数字化浪潮席卷全球的当下&#xff0c;企业对软件开发的效率与灵活性愈发重视&#xff0c;低代码平台应运而生并迅速掀起技术热潮。 本文基于笔者 6 年的低代码实践经验&#xff0c;深入剖析低代码的诸多方面&#xff0c;涵盖其定义、发展历程、国内平台对比、开发流程、与…

函数重载讲解

虽然在初识C-CSDN博客中介绍过&#xff0c;但还是感觉要单发出来大概讲解下 什么是函数重载&#xff1f; 函数重载是指在同一个作用域内&#xff0c;函数名相同&#xff0c;但它们的 参数列表 不同。C 允许你根据函数的参数个数、类型或者顺序的不同来定义多个同名函数。编译…

14-H指数

给你一个整数数组 citations &#xff0c;其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。 根据维基百科上 h 指数的定义&#xff1a;h 代表“高引用次数” &#xff0c;一名科研人员的 h 指数 是指他&#xff08;她&#xff09;至少发…