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

认证鉴权框架之—sa-token

一、概述

Satoken 是一个 Java 实现的权限认证框架,它主要用于 Web 应用程序的权限控制。Satoken 提供了丰富的功能来简化权限管理的过程,使得开发者可以更加专注于业务逻辑的开发。

二、逻辑流程

1、登录认证
(1)、创建token
当用户输入用户名和密码请求登录,后端验证用户名和密码的正确性。验证成功时,调用sa-token提供的登录接口,创建token

StpUtil.login(saBaseLoginUser.getId(), new SaLoginModel().setDevice(device).setExtra("name", saBaseLoginUser.getName()));

此方法,会自动创建token,并将token和会话session相关联,并且返回给前端的响应头中自动设置token:如下:
Response Header中返回set-cookie:token=token值
在这里插入图片描述
浏览器接受response后,会自动设置token的请求头,之后请求该域的接口时,会自动带上该请求头
Request Header中会携带token
在这里插入图片描述
如上的创建token,到给前端设置token的过程,只需要后端调用sa-token的登录接口,其他无需我们做任何事情。

(2)、创建当前用户的缓存
当调用完成sa-token的登录接口后,我们可以构建当前登录用户的对象SaBaseLoginUser,该对象可以添加权限,角色,组织等信息。
设置到sa-token的缓存中,这样在之后的接口中,我们需要获取当前用户信息或当前用户信息的权限等信息时,就可以直接从sa-token缓存中获取,就无需从数据库中再次查询。

设置当前用户的缓存
StpUtil.getTokenSession().set("loginUser", saBaseLoginUser);
获取当前用户的缓存
Object loginUser = StpUtil.getTokenSession().get("loginUser");
if (ObjectUtil.isNull(loginUser)) throw new CommonException("用户未登录");
SaBaseLoginUser saBaseLoginUser = (SaBaseLoginUser) loginUser;

注意,这里我们最好整合redis使用,否则会占用系统内存,占用内存多了就会造成性能瓶颈问题。同时整合redis也可以适用分布式多节点的服务。

2、查询权限(菜单和接口)
(1)、菜单权限
关于菜单,针对每一个前端页面的路由创建不同的菜单数据保存到数据库就行,之后针对角色进行授权即可。方法比较常见不在赘述。

(2)、接口权限
关于接口权限,sa-token自带一些注解类去管理接口权限,如:在controller类上使用@SaCheckRole注解或接口上使用@SaCheckPermission注解,标识该类或者接口为待认证的接口。

在spring容器初始化时,会初始化和注入所有的接口到容器中被spring所管理,可以通过springApplication上下文对象获取所有的RequestMappingHandlerMapping.class,即所有的controller类。在分别requestMappingHandlerMapping.getHandlerMethods()方法,即查询了所有的接口。
示例代码:

SpringUtil.getApplicationContext().getBeansOfType(RequestMappingHandlerMapping.class).values().forEach(requestMappingHandlerMapping -> requestMappingHandlerMapping.getHandlerMethods().forEach((key, value) -> {SaCheckPermission saCheckPermission = value.getMethod().getAnnotation(SaCheckPermission.class);if (ObjectUtil.isNotEmpty(saCheckPermission)) {PatternsRequestCondition patternsCondition = key.getPatternsCondition();if (patternsCondition != null) {String apiName = "未定义接口名称";ApiOperation apiOperation = value.getMethod().getAnnotation(ApiOperation.class);if (ObjectUtil.isNotEmpty(apiOperation)) {String annotationValue = apiOperation.value();if (ObjectUtil.isNotEmpty(annotationValue)) {apiName = annotationValue;}}
permissionResult.add(patternsCondition.getPatterns().iterator().next() + StrUtil.BRACKET_START + apiName + StrUtil.BRACKET_END);}}}));

3、授权
(1)、菜单授权
从数据库中查询所有的菜单数据,直接授权给角色即可。
(2)、接口授权
通过如上的方法,查询所有的接口权限(可以在容器初始化时保存到缓存中,减少查询次数)。之后做成表单,授权给角色或者指定账号即可。
在这里插入图片描述
4、鉴权
sa-token拦截器(SaInterceptor),我们只需要将拦截器注册到spring容器中,拦截所有的请求进行校验。

    @Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关,只是说明哪些接口不需要被拦截器拦截,此处都拦截)registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");}

sa-token会开放查询用户权限和角色的接口给我们重写,我们只需要覆写(自定义类实现StpInteface接口,覆写里面的方法)获取用户权限和角色的接口即可。
在这里插入图片描述
5、总结
如上,我们描述了一个完整示例。从创建token,前端在指定域内请求携带token。在到获取权限,授权和鉴权的全过程。授权信息一般可以保存到数据库中,通过sa-token官方的示例去覆写接口即可。其他只需要我们在合适的类上或者接口上添加注解就行。

三、代码示例
1、引入依赖
如果服务只有一个节点,仅配置第一个sa-token-spring-boot-starter就够用了,后两个依赖是将redis和sa-token整合,这样认证信息保存到redis中,跨节点权限认证时也不会出现问题。

<!--版本-->
<properties><sa.token.version>1.31.0</sa.token.version>
</properties><!-- sa-token -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring-boot-starter</artifactId><version>${sa.token.version}</version>
</dependency><!-- sa-token 整合 redis (使用jackson序列化方式) -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-dao-redis-jackson</artifactId><version>${sa.token.version}</version>
</dependency><!-- Sa-Token插件:权限缓存与业务缓存分离 -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-alone-redis</artifactId><version>${sa.token.version}</version>
</dependency>

2、配置文件

#########################################
# redis configuration
#########################################
spring:redis:database: 0host: 172.xx.xxx.xxport: 6379password:timeout: 10slettuce:pool:max-active: 200       // 连接池最大连接数max-wait: -1ms       // 连接池最大阻塞等待时间(负数表示不限制)max-idle: 10          // 连接池中最大空闲连接min-idle: 0           // 连接池中最小空闲连接
#########################################
# sa-token configuration
#########################################
sa-token:token-name: token     // token名称,即设置cookie的key值timeout: 2592000      // token有效期(秒),默认30天,-1代表永久有效activity-timeout: -1     // 最低活跃频率(秒),即超过这个时间没有访问系统会冻结该token,默认-1代表永不冻结is-concurrent: true    // 是否允许同一账号多地登录is-share: false      // 是否同一账号多地登录时共用同一个tokenmax-login-count: -1token-style: random-32is-log: false     // 是否输出操作日志is-print: false# sa-token alone-redis configurationalone-redis:database: 2    // 指定sa-token使用redis的哪一个库host: ${spring.redis.host}port: ${spring.redis.port}password: ${spring.redis.password}timeout: ${spring.redis.timeout}lettuce:pool:max-active: ${spring.redis.lettuce.pool.max-active}max-wait: ${spring.redis.lettuce.pool.max-wait}max-idle: ${spring.redis.lettuce.pool.max-idle}min-idle: ${spring.redis.lettuce.pool.min-idle}

如上配置的sa-token整合redis后,sa-token在创建token信息时,会自动将token信息保存到配置的redis中,无需我们在操作redis进行设置。
在这里插入图片描述
3、全局管理类
这里我们注册sa-token拦截器,注入StpLogic管理类(一般多种用户类型时需要),重写注解合并方法(父类有的注解也会被作用到子类处理),覆写sa-token的自定义接口查询用户角色和权限。

import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.strategy.SaStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import cn.nivic.common.auth.enums.SaClientTypeEnum;
import cn.nivic.common.auth.util.StpClientLoginUserUtil;
import cn.nivic.common.auth.util.StpLoginUserUtil;
import java.util.List;/*** SaToken鉴权配置**/
@Configuration
public class AuthConfigure implements WebMvcConfigurer {/*** 注册Sa-Token的注解拦截器,打开注解式鉴权功能** 注解的方式有以下几中,注解既可以加在接口方法上,也可加在Controller类上:* 1.@SaCheckLogin: 登录认证 —— 只有登录之后才能进入该方法(常用)* 2.@SaCheckRole("admin"): 角色认证 —— 必须具有指定角色标识才能进入该方法(常用)* 3.@SaCheckPermission("user:add"): 权限认证 —— 必须具有指定权限才能进入该方法(常用)* 4.@SaCheckSafe: 二级认证校验 —— 必须二级认证之后才能进入该方法* 5.@SaCheckBasic: HttpBasic认证 —— 只有通过 Basic 认证后才能进入该方法** 在Controller中创建一个接口,默认不需要登录也不需要任何权限都可以访问的,只有加了上述注解才会校验**/@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关,只是说明哪些接口不需要被拦截器拦截,此处都拦截)registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");}@Bean("stpLogic")public StpLogic getStpLogic() {// 注入Sa-Token的StpLogic,客户端类型为B,处理B端用户的权限管理return new StpLogic(SaClientTypeEnum.B.getValue());}@Bean("stpClientLogic")public StpLogic getStpClientLogic() {// 注入Sa-Token的StpLogic,客户端类型为C,处理C端用户的权限管理        		return new StpLogic(SaClientTypeEnum.C.getValue());}@Beanpublic void rewriteSaStrategy() {// 重写Sa-Token的注解处理器,增加注解合并功能
// 这里的注解合并,即在继承体系中,也能获取到父类的注解实例。SaStrategy.me.getAnnotation = AnnotatedElementUtils::getMergedAnnotation;}/*** 权限认证接口实现类,集成权限认证功能
* 重写sa-token获取权限的接口,这里用户更具业务编码从数据库或者mongoDb中获取权限**/@Componentpublic static class StpInterfaceImpl implements StpInterface {/*** 返回一个账号所拥有的权限码集合*/@Overridepublic List<String> getPermissionList(Object loginId, String loginType) {if (SaClientTypeEnum.B.getValue().equals(loginType)) {return StpLoginUserUtil.getLoginUser().getPermissionCodeList();} else {return StpClientLoginUserUtil.getClientLoginUser().getPermissionCodeList();}}/*** 返回一个账号所拥有的角色标识集合*/@Overridepublic List<String> getRoleList(Object loginId, String loginType) {if (SaClientTypeEnum.B.getValue().equals(loginType)) {return StpLoginUserUtil.getLoginUser().getRoleCodeList();} else {return StpClientLoginUserUtil.getClientLoginUser().getRoleCodeList();}}}}

4、注解和使用
(1)、@SaCheckLogin
放在controller的接口方法上,在调用到这个方法的时候,会校验用户是否登录,如果没有登录会直接报错,保障安全。一般放在关键接口上,一般接口无需如此。

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;@Api(tags = "B端登录控制器")
@RestController
@Validated
public class AuthController {/*** B端退出**/@ApiOperationSupport(order = 5)@ApiOperation("B端退出")@SaCheckLogin@GetMapping("/auth/b/doLogout")public CommonResult<String> doLogout() {StpUtil.logout();return CommonResult.ok();}/*** B端获取用户信息**/@ApiOperationSupport(order = 6)@ApiOperation("B端获取用户信息")@SaCheckLogin@GetMapping("/auth/b/getLoginUser")public CommonResult<SaBaseLoginUser> getLoginUser() {return CommonResult.data(authService.getLoginUser());}
}

(2)、@SaCheckPermission
放在controller的接口方法上,用户请求到这个方法时,会校验用户是否有这个接口的权限,没有权限会直接报错。常用在数据增删改查接口上。
至于sa-token获取接口权限:则是通过全局配置类中实现StpInterfaceImpl接口,获取当前用户的全部权限。

 @ApiOperationSupport(order = 1)@ApiOperation("获取机构分页")@SaCheckPermission("/biz/org/page")@GetMapping("/biz/org/page")public CommonResult<Page<BizOrg>> page(BizOrgPageParam bizOrgPageParam) {return CommonResult.data(bizOrgService.page(bizOrgPageParam));}

(3)、@SaCheckRole
@SaCheckRole是sa-token校验角色权限的注解,这里自定义注解SaClientCheckRole,在注解类上添加@SaCheckRole注解,从而达到sa-token校验角色的效果之后,还可以继续扩展注解功能。
前提:我们在全部配置类中调整了注解处理器为注解合并方式,这样sa-token在解析注解SaClientCheckRole时也会读取父类的SaCheckRole注解,从而达到校验的效果。
至于sa-token获取角色:则是通过全局配置类中实现StpInterfaceImpl接口,获取当前用户的全部角色。

@SaCheckRole(type = StpClientUtil.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE})
public @interface SaClientCheckRole {/*** 需要校验的角色标识* @return 需要校验的角色标识*/@AliasFor(annotation = SaCheckRole.class)String [] value() default {};/*** 验证模式:AND | OR,默认AND* @return 验证模式*/@AliasFor(annotation = SaCheckRole.class)SaMode mode() default SaMode.AND;}

四、sa-token基本组件
1、StpUtil
sa-token官方提供的工具类,提供了许多静态方法来帮助开发者快速地完成登录认证、权限校验等工作。例如,当用户登录时,可以通过 StpUtil.login(10001) 方法来标记当前会话已登录,并将账号ID写入会话中。设置当前用户信息缓存,可在之后的请求中获取登录用户信息等。具体实现还是依靠StpLogic完成的。

2、StpLogic
是 Sa-Token 框架的核心逻辑处理类,它封装了与认证和授权相关的具体实现。例如,当调用 StpUtil.logout() 方法时,实际上是调用了 StpLogic 的 logout 方法来处理会话注销的操作。此外,StpLogic 也用于实现登录、会话管理等核心逻辑。

3、StpInterface
是一个接口,它用于自定义权限认证的逻辑。开发者可以通过实现这个接口来提供自己的业务逻辑,比如实现 getPermissionList 方法来获取一个账号的所有权限列表,或者实现 getRoleList 方法来获取一个账号的角色列表。当 Sa-Token 需要校验权限时,它会调用这个接口的方法来获取相应的信息。

4、SaManager
一个管理类,它负责管理 Sa-Token 框架的各种全局组件,如全局配置 SaTokenConfig、持久化处理 SaTokenDao、权限认证 StpInterface、框架行为 SaTokenAction、上下文处理器 SaTokenContext 与 SaTokenSecondContext、认证活动监听 SaTokenListener、临时令牌验证 SaTempInterface、认证处理逻辑 StpLogic 等等。通过 SaManager,开发者可以方便地获取和管理这些组件。

5、SaStrategy
是一个策略类,它提供了一组策略方法,允许开发者自定义框架内部的一些行为。例如,你可以重写createToken方法来改变创建Token的策略,或者重写checkMethodAnnotation方法来改变如何校验一个Method 对象上的注解。

6、关联性
这些组件之间通过 SaManager 和 StpUtil 等工具类相互关联起来。例如,StpUtil 中的很多方法实际上都是调用了 StpLogic 的相应方法来实现其功能。而 StpLogic 在执行一些核心逻辑时,可能会调用 SaManager 中的组件,比如 SaTokenDao 来进行数据的持久化操作,或者调用 StpInterface 来获取权限信息。SaStrategy 则提供了一种机制,允许开发者在不改变 Sa-Token 框架核心逻辑的情况下调整某些行为。

7、流程图示例
StpUtil完成创建token,登录,登出等操作,具体通过StpLogic完成;
SaManager负责管理所有的Sa-token组件(StpLogic,StpInteface等…)
StpLogic负责实现所有的业务,会通过SaManager获取其他组件协调完成。
StpInterface给用户实现,提供具体的获取权限,角色等信息
SaStrategy指定策略,如注解合并等。
在这里插入图片描述

学海无涯苦作舟!!!

相关文章:

认证鉴权框架之—sa-token

一、概述 Satoken 是一个 Java 实现的权限认证框架&#xff0c;它主要用于 Web 应用程序的权限控制。Satoken 提供了丰富的功能来简化权限管理的过程&#xff0c;使得开发者可以更加专注于业务逻辑的开发。 二、逻辑流程 1、登录认证 &#xff08;1&#xff09;、创建token …...

Spring源码(十一):Spring MVC之DispatchServlet

本篇重点在于分析Spring MVC与Servlet标准的整合&#xff0c;下节将详细讨论Spring MVC的启动/加载流程、处理请求的具体流程。 一、介绍 Spring框架提供了构建Web应用程序的全功能MVC模块。通过策略接口 &#xff0c;Spring框架是高度可配置的&#xff0c;而且支持多种视图技…...

gitbash简单操作

https://blog.csdn.net/qq_42363495/article/details/104878170 工作区(空间)--暂存区--本地仓库--远程仓库 方法一&#xff1a;创建一个新的分支master&#xff0c;且远程库里没有该分支 只要将.gitignore文件放在文件夹下就可以&#xff0c;.gitignore是文本文档形式的文件…...

pnpm install安装element-plus的版本跟package.json指定的版本不一样

pnpm安装的版本不同于package.json中指定的版本可能是由于以下几种情况导致的&#xff1a; 依赖项冲突&#xff1a;当项目依赖的不同模块或库之间存在版本冲突时&#xff0c;pnpm可能会安装与package.json中指定的版本不同的版本。这可能是因为其他依赖项指定了不同的版本&…...

Java线程池的核心内容详解

文章内容已经收录在《面试进阶之路》&#xff0c;从原理出发&#xff0c;直击面试难点&#xff0c;实现更高维度的降维打击&#xff01; 目录 文章目录 目录Java线程池的核心内容详解线程池的优势什么场景下要用到线程池呢&#xff1f;线程池中重要的参数【掌握】新加入一个任…...

学习笔记——三小时玩转JQuery

也可以使用在线版&#xff0c;不过在线版需要有网络&#xff0c;网不好的情况下加载也不好 取值的时候也是只会取到有样式的纯文本&#xff0c;不会取到标签&#xff0c;会取到标签效果 prepend和append这两个方法用的比较多&#xff0c;before和affter用的比较少 想要把代码写…...

word试题转excel(最简单的办法,无格式要求)

分享早下班的终极秘诀~ 今天本来是个愉快的周五&#xff0c;心里想着周末的聚会和各种安排&#xff0c;然而突然一个加急任务砸了过来——要求在下周一提交一份精细整理的Excel表格&#xff01; 打开Word文件一看&#xff0c;成堆的试题内容需要整理到Excel里。看着满屏的题目…...

基于web的中小学成绩管理系统的设计与实现

目录 第一章 研究背景与意义 1.1 研究背景 1.2 研究意义 1.3 研究目的 第二章 关于系统的设计 2.1系统总体架构设计 2.2功能模块设计 2.3数据存储与管理 第三章 系统功能介绍 3.1成绩录入及发布 3.2班级管理和学生管理 3.3成绩分析结果展示 3.4用户反馈与改进 …...

Conmi的正确答案——在Kibana中进入Elasticsearch的索引管理页面

Elasticsearch版本&#xff1a;7.17.25 Kibana版本&#xff1a;7.17.25 注&#xff1a;索引即类似mysql的表。 0、进入首页 1、未创建任何“索引模式”时&#xff1a; 1.1、点击左边的三横菜单&#xff1b; 1.2、点击“Discover”&#xff0c;进入“发现”页面&#xff1b; 2…...

【JavaEE】【多线程】进阶知识

目录 一、常见的锁策略1.1 悲观锁 vs 乐观锁1.2 重量级锁 vs 轻量级锁1.3 挂起等待锁 vs 自旋锁1.4 普通互斥锁 vs 读写锁1.5 可重入锁 vs 不可重入锁1.6 不公平锁 vs 公平锁 二、synchronized特性2.1 synchronized的锁策略2.2 synchronized加锁过程2.3 其它优化措施 三、CAS3.…...

LeetCode100之三数之和(15)--Java

1.问题描述 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意 答案中不可以包含重复的三元组 示例1 输入&…...

并发编程三大特性--可见性和有序性

可见性&#xff1a; 什么是可见性&#xff1a; 可见性是指在数据在收到一个线程的修改时&#xff0c;其他的线程也可以得知并获取修改后的值的属性。这是并发编程的三大特性之一。 为了提高cpu的利用率&#xff0c;cpu在获取数据时&#xff0c;不是直接在主内存读取数据&…...

Android 使用ninja加速编译的方法

ninja的简介 随着Android版本的更迭&#xff0c;makefile体系逐渐增多&#xff0c;导致make单编模块的时间越来越长&#xff0c;每次都需要半个小时甚至更长时间&#xff0c;其原因为每次make都会重新加载所有mk文件&#xff0c;再生成ninja编译&#xff0c;此完整过程十分耗时…...

《Java 实现选择排序:原理剖析与代码详解》

目录 一、引言 二、选择排序原理 三、代码分析 1. 代码整体结构 2. main方法 3. sort方法&#xff08;选择排序核心逻辑&#xff09; 四、测试结果 一、引言 排序算法在计算机科学领域中是非常重要的一部分&#xff0c;它能够帮助我们将无序的数据按照特定的顺序进行排列…...

数据结构之双链表——考研笔记

文章目录 一.单链表VS双链表二.创建双链表&#xff08;带头结点&#xff09;三.双链表的插入四.双链表删除五.销毁双链表六.双链表遍历七. 循环链表八.静态链表1.用代码定义一个静态链表 一.单链表VS双链表 单链表中只包含指向它后继结点的指针&#xff0c;所以给定一个结点p找…...

Django视图写法

1.View&#xff1a;Django默认的视图基类,Django的HttpRequeset对象 2.APIView&#xff1a;REST-framework提供的所有视图的基类,继承自Django的View REST framework的Request对象 Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。 serializer Book…...

单臂路由实现不同VLAN之间设备通信

转载请注明出处 本实验为单臂路由配置&#xff0c;目的为让不同VLAN之间的设备能够互相通信。 1.首先&#xff0c;按照要求配置两个pc的ip地址&#xff0c;以pc0为例子&#xff1a; 2在交换机创建vlan10和vlan20 3.划分vlan&#xff0c;pc0为vlan10的设备&#xff0c;pc1为vla…...

Linux·进程控制(system V)

1. 共享内存 system V共享内存是最快的IPC形式&#xff0c;之前的管道是基于Linux内核开发的通讯方案&#xff0c;其读写接口都是现成的&#xff0c;因此内核设计者为了完成进程间通讯任务并不需要新增太多代码。而共享内存属于system V标准&#xff0c;是操作系统单独…...

华为云Stack名词解释

1、MRS MapReduce服务&#xff08;MRS&#xff09;是一种基于云计算平台的即开即用、稳定可靠、弹性伸缩、便捷管理的数据处理分析服务。 2、VBS 云硬盘备份服务&#xff08;VBS&#xff0c;Volume Backup Service&#xff09;可为云硬盘&#xff08;EVS&#xff0c;Elastic…...

YoloV9改进策略:上采样改进|CARAFE,轻量级上采样|即插即用|附改进方法+代码

论文介绍 CARAFE模块概述&#xff1a;本文介绍了一种名为CARAFE&#xff08;Content-Aware ReAssembly of FEatures&#xff09;的模块&#xff0c;它是一种用于特征上采样的新方法。应用场景&#xff1a;CARAFE模块旨在改进图像处理和计算机视觉任务中的上采样过程&#xff0…...

从预处理指令看跨语言兼容:手把手封装C++库供C调用的5个关键步骤

从预处理指令看跨语言兼容&#xff1a;手把手封装C库供C调用的5个关键步骤 在嵌入式开发和SDK设计中&#xff0c;经常需要将C库封装成C语言接口。这种跨语言调用看似简单&#xff0c;实则暗藏玄机。本文将深入剖析extern "C"和__cplusplus预处理指令的底层原理&#…...

SEO_新手必看的SEO优化入门教程与核心方法(361 )

<h3 id"seoseo">SEO:新手必看的SEO优化入门教程与核心方法</h3> <p>在互联网时代&#xff0c;拥有一个成功的网站不仅仅是有好的设计和内容&#xff0c;还需要通过SEO&#xff08;搜索引擎优化&#xff09;来提升网站的可见性和流量。对于新手来说…...

Presto函数实战指南:从基础到高阶应用

1. Presto函数入门&#xff1a;从零开始掌握基础操作 第一次接触Presto函数时&#xff0c;我完全被它丰富的功能震撼到了。记得当时我需要快速分析一个包含数百万条记录的日志表&#xff0c;传统方法需要写复杂的MapReduce作业&#xff0c;而Presto仅用几行SQL函数就搞定了。下…...

避开这些坑!Sigma-Delta调制器设计中最容易忽略的5个稳定性问题(附MASH级联实测数据)

避开这些坑&#xff01;Sigma-Delta调制器设计中最容易忽略的5个稳定性问题&#xff08;附MASH级联实测数据&#xff09; 在高速高精度ADC设计中&#xff0c;Sigma-Delta调制器因其优异的噪声整形特性成为首选方案。但当工程师们沉浸在理论计算的理想世界时&#xff0c;实验室示…...

FPGA实战:8点FFT运算的Verilog实现与误差优化技巧

FPGA实战&#xff1a;8点FFT运算的Verilog实现与误差优化技巧 在数字信号处理领域&#xff0c;快速傅里叶变换&#xff08;FFT&#xff09;算法是频谱分析的核心工具。对于FPGA开发者而言&#xff0c;掌握FFT的硬件实现不仅能提升系统性能&#xff0c;更能深入理解算法与硬件的…...

Nanbeige 4.1-3B赋能微信小程序:打造智能客服对话机器人

Nanbeige 4.1-3B赋能微信小程序&#xff1a;打造智能客服对话机器人 最近在帮一个做电商的朋友琢磨怎么优化他们的客服系统。他们每天要处理大量重复的咨询&#xff0c;比如“什么时候发货”、“怎么退换货”&#xff0c;人工客服忙得团团转&#xff0c;用户还得排队等。这让我…...

StructBERT-Large中文相似度工具一文详解:三级匹配等级判定逻辑与业务适配建议

StructBERT-Large中文相似度工具一文详解&#xff1a;三级匹配等级判定逻辑与业务适配建议 本文深度解析StructBERT-Large中文相似度工具的核心匹配逻辑&#xff0c;提供实际业务场景中的适配建议和优化方案 1. 工具核心价值与适用场景 StructBERT-Large中文相似度工具是一个基…...

Qwen3.5-9B+OpenClaw组合方案:3类高性价比自动化场景实测

Qwen3.5-9BOpenClaw组合方案&#xff1a;3类高性价比自动化场景实测 1. 为什么选择这个组合&#xff1f; 去年夏天&#xff0c;我花了整整两周时间在本地部署各种开源大模型&#xff0c;试图找到一个既能在预算内运行、又能稳定执行自动化任务的方案。经过反复测试&#xff0…...

DoL-Lyra整合包完整使用指南:5分钟掌握汉化版Degrees of Lewdity一键安装

DoL-Lyra整合包完整使用指南&#xff1a;5分钟掌握汉化版Degrees of Lewdity一键安装 【免费下载链接】DOL-CHS-MODS Degrees of Lewdity 整合 项目地址: https://gitcode.com/gh_mirrors/do/DOL-CHS-MODS DoL-Lyra整合包为Degrees of Lewdity玩家提供了一站式解决方案&…...

OpenClaw多模态飞书助手:Qwen3-VL:30B实战详解

OpenClaw多模态飞书助手&#xff1a;Qwen3-VL:30B实战详解 1. 为什么需要多模态飞书助手&#xff1f; 去年夏天&#xff0c;我负责一个跨部门协作项目时&#xff0c;每天要处理上百条飞书消息。最头疼的是同事发来的各种截图——有的是数据报表需要整理&#xff0c;有的是会议…...