RuoYi-Vue-Plus(sa-token)

一、介绍

官网: 

Sa-Tokenicon-default.png?t=N7T8https://sa-token.cc/index.html

特性:

  1. 登录与权限认证:支持用户登录和细粒度权限认证。
  2. 会话管理:提供会话创建、维护和销毁功能。
  3. 单点登录:支持单点登录,简化多应用登录流程。
  4. OAuth2.0集成:集成OAuth2.0协议,实现安全授权与认证。
  5. 微服务网关鉴权:确保微服务间的安全访问。
  6. 轻量且易用:功能强大但易于集成和使用。

登录流程简介:

对于一些登录之后才能访问的接口(例如:查询我的账号资料),我们通常的做法是增加一层接口校验:

  • 如果校验通过,则:正常返回数据。
  • 如果校验未通过,则:抛出异常,告知其需要先进行登录。
  1. 用户提交 name + password 参数,调用登录接口。
  2. 登录成功,返回这个用户的 Token 会话凭证。
  3. 用户后续的每次请求,都携带上这个 Token。
  4. 服务器根据 Token 判断此会话是否登录成功。

所谓登录认证,指的就是服务器校验账号密码,为用户颁发 Token 会话凭证的过程,这个 Token 也是我们后续判断会话是否登录的关键所在。

二、集成

注:如果你使用的是 SpringBoot 3.x,只需要将 sa-token-spring-boot-starter 修改为 sa-token-spring-boot3-starter 即可。

1-添加依赖 
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring-boot-starter</artifactId><version>1.37.0</version>
</dependency>
2-配置文件编写 

  若依sa-token 配置在yml中,如下:ruoyi-admin/src/main/resources/application.yml

属性讲解:

  •   timeout: 86400  固定有效期,必定一天过期
  •   active-timeout: 1800   临时有效期,30分钟误操作token过期
  • is-concurrent:并发登录,为true时允许一起登录, 为false时新登录挤掉旧登录
    is-read-cookie 是否尝试从cookie里读取token,默认不从cookie中获取,可能会有csrf攻击
# Sa-Token配置
sa-token:# token名称 (同时也是cookie名称)token-name: Authorization# token有效期 设为一天 (必定过期) 单位: 秒timeout: 86400# 多端不同 token 有效期 可查看 LoginHelper.loginByDevice 方法自定义# token最低活跃时间 (指定时间无操作就过期) 单位: 秒active-timeout: 1800# 允许动态设置 token 有效期dynamic-active-timeout: true# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)is-concurrent: true# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)is-share: false# 是否尝试从header里读取tokenis-read-header: true# 是否尝试从cookie里读取tokenis-read-cookie: false# token前缀token-prefix: "Bearer"# jwt秘钥jwt-secret-key: abcdefghijklmnopqrstuvwxyz

三、 常用函数 

1-登录、注销函数
StpUtil.login(Object id);    

只此一句代码,便可以使会话登录成功,实际上,Sa-Token 在背后做了大量的工作,包括但不限于:

1-检查此账号是否之前已有登录;
2-为账号生成 Token 凭证与 Session 会话;
3-记录 Token 活跃时间;
4-通知全局侦听器,xx 账号登录成功;
5-将 Token 注入到请求上下文

 

你暂时不需要完整了解整个登录过程,你只需要记住关键一点:Sa-Token 为这个账号创建了一个Token凭证,且通过 Cookie 上下文返回给了前端。

流程与思路详见:

登录认证 (sa-token.cc)icon-default.png?t=N7T8https://sa-token.cc/doc.html?code=25446615d46b82ca1f92853e66d5d64c63fe3a34e6a611a52458847155bff768#/use/login-auth

StpUtil.logout();
 

// 当前会话注销登录


StpUtil.isLogin();

// 获取当前会话是否已经登录,返回true=已登录,false=未登录
StpUtil.checkLogin();// 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
2-强制注销
StpUtil.logout(10001);                    // 强制指定账号注销下线 
StpUtil.logout(10001, "PC");              // 强制指定账号指定端注销下线 
StpUtil.logoutByTokenValue("token");      // 强制指定 Token 注销下线 

3-踢人下线
StpUtil.kickout(10001);                    // 将指定账号踢下线 
StpUtil.kickout(10001, "PC");              // 将指定账号指定端踢下线
StpUtil.kickoutByTokenValue("token");      // 将指定 Token 踢下线

强制注销 和 踢人下线 的区别在于:

  • 强制注销等价于对方主动调用了注销方法,再次访问会提示:Token无效。
  • 踢人下线不会清除Token信息,而是将其打上特定标记,再次访问会提示:Token已被踢下线。
 4-会话函数
StpUtil.getLoginId();        // 获取当前会话账号id, 如果未登录,则抛出异常:`NotLoginException`
类似上面

StpUtil.getLoginIdAsString();   // 获取当前会话账号id, 并转化为`String`类型

StpUtil.getLoginIdAsInt();    // 获取当前会话账号id, 并转化为`int`类型

StpUtil.getLoginIdAsLong();   // 获取当前会话账号id, 并转化为`long`类型

StpUtil.getLoginIdDefaultNull();/ 获取当前会话账号id, 如果未登录,则返回 null
StpUtil.getLoginId(T defaultValue);// 获取当前会话账号id, 如果未登录,则返回默认值 (`defaultValue`可以为任意类型)
5-Token查询
StpUtil.getTokenValue();// 获取当前会话的 token 值
StpUtil.getTokenName();// 获取当前`StpLogic`的 token 名称
StpUtil.getLoginIdByToken(String tokenValue);
// 获取指定 token 对应的账号id,如果未登录,则返回 null
StpUtil.getTokenTimeout();// 获取当前会话剩余有效期(单位:s,返回-1代表永久有效)
StpUtil.getTokenInfo();// 获取当前会话的 token 信息参数

关于token参数详解:

{"code": 200,"msg": "ok","data": {"tokenName": "satoken",           // token名称"tokenValue": "e67b99f1-3d7a-4a8d-bb2f-e888a0805633",      // token值"isLogin": true,                  // 此token是否已经登录"loginId": "10001",               // 此token对应的LoginId,未登录时为null"loginType": "login",              // 账号类型标识"tokenTimeout": 2591977,          // token剩余有效期 (单位: 秒)"sessionTimeout": 2591977,        // Account-Session剩余有效时间 (单位: 秒)"tokenSessionTimeout": -2,        // Token-Session剩余有效时间 (单位: 秒) (-2表示系统中不存在这个缓存)"tokenActiveTimeout": -1,         // token 距离被冻结还剩的时间 (单位: 秒)"loginDevice": "default-device"   // 登录设备类型 },
}

 四、权限

自行查看 api接口

权限认证 (sa-token.cc)icon-default.png?t=N7T8https://sa-token.cc/doc.html?code=25446615d46b82ca1f92853e66d5d64c63fe3a34e6a611a52458847155bff768#/use/jur-auth

5-注解鉴权

注解鉴权 —— 优雅的将鉴权与业务代码分离!

  • @SaCheckLogin: 登录校验 —— 只有登录之后才能进入该方法。
  • @SaCheckRole("admin"): 角色校验 —— 必须具有指定角色标识才能进入该方法。
  • @SaCheckPermission("user:add"): 权限校验 —— 必须具有指定权限才能进入该方法。
  • @SaCheckSafe: 二级认证校验 —— 必须二级认证之后才能进入该方法。
  • @SaCheckBasic: HttpBasic校验 —— 只有通过 Basic 认证后才能进入该方法。
  • @SaIgnore:忽略校验 —— 表示被修饰的方法或类无需进行注解鉴权和路由拦截器鉴权。
  • @SaCheckDisable("comment"):账号服务封禁校验 —— 校验当前账号指定服务是否被封禁。

你必须手动将 Sa-Token 的全局拦截器注册到你项目中 

官网文档:

路由拦截鉴权 (sa-token.cc)icon-default.png?t=N7T8https://sa-token.cc/doc.html?code=25446615d46b82ca1f92853e66d5d64c63fe3a34e6a611a52458847155bff768#/use/route-check?id=_1%E3%80%81%E6%B3%A8%E5%86%8C-sa-token-%E8%B7%AF%E7%94%B1%E6%8B%A6%E6%88%AA%E5%99%A8

下面是若依中的实现: 

@RequiredArgsConstructor
@Slf4j
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {private final SecurityProperties securityProperties;/*** 注册sa-token的拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册路由拦截器,自定义验证规则registry.addInterceptor(new SaInterceptor(handler -> {AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class);// 登录验证 -- 排除多个路径SaRouter// 获取所有的.match(allUrlHandler.getUrls())// 对未排除的路径进行检查.check(() -> {// 检查是否登录 是否有tokenStpUtil.checkLogin();// 有效率影响 用于临时测试// if (log.isDebugEnabled()) {//     log.info("剩余有效时间: {}", StpUtil.getTokenTimeout());//     log.info("临时有效时间: {}", StpUtil.getTokenActiveTimeout());// }});})).addPathPatterns("/**")// 排除不需要拦截的路径.excludePathPatterns(securityProperties.getExcludes());}@Beanpublic StpLogic getStpLogicJwt() {// Sa-Token 整合 jwt (简单模式)return new StpLogicJwtForSimple();}/*** 权限接口实现(使用bean注入方便用户替换)*/@Beanpublic StpInterface stpInterface() {return new SaPermissionImpl();}/*** 自定义dao层存储*/@Beanpublic SaTokenDao saTokenDao() {return new PlusSaTokenDao();}}

五、session 会话 

在 Sa-Token 中,Session 分为三种,分别是:

  • Account-Session: 指的是框架为每个 账号id 分配的 Session
  • Token-Session: 指的是框架为每个 token 分配的 Session
  • Custom-Session: 指的是以一个 特定的值 作为SessionId,来分配的 Session
// 在登录时缓存 user 对象 
StpUtil.getSession().set("user", user);// 然后我们就可以在任意处使用这个 user 对象
SysUser user = (SysUser) StpUtil.getSession().get("user");

1-Account-Session 绑定当前用户id ,api如下
// 获取当前账号 id 的 Account-Session (必须是登录后才能调用)
StpUtil.getSession();// 获取当前账号 id 的 Account-Session, 并决定在 Session 尚未创建时,是否新建并返回
StpUtil.getSession(true);// 获取账号 id 为 10001 的 Account-Session
StpUtil.getSessionByLoginId(10001);// 获取账号 id 为 10001 的 Account-Session, 并决定在 Session 尚未创建时,是否新建并返回
StpUtil.getSessionByLoginId(10001, true);// 获取 SessionId 为 xxxx-xxxx 的 Account-Session, 在 Session 尚未创建时, 返回 null 
StpUtil.getSessionBySessionId("xxxx-xxxx");
 2- Token-Session 绑定当前token的信息
// 获取当前 Token 的 Token-Session 对象
StpUtil.getTokenSession();// 获取指定 Token 的 Token-Session 对象
StpUtil.getTokenSessionByToken(token);
3-Custom-Session  自定义sessionid

比如 ,下面goods-10001是某个商品的id

// 查询指定key的Session是否存在
SaSessionCustomUtil.isExists("goods-10001");// 获取指定key的Session,如果没有,则新建并返回
SaSessionCustomUtil.getSessionById("goods-10001");// 获取指定key的Session,如果没有,第二个参数决定是否新建并返回  
SaSessionCustomUtil.getSessionById("goods-10001", false);   // 删除指定key的Session
SaSessionCustomUtil.deleteSessionById("goods-10001");

 官网还提供一些 session 读写的api ,自行查看

Session会话 (sa-token.cc)icon-default.png?t=N7T8https://sa-token.cc/doc.html?code=25446615d46b82ca1f92853e66d5d64c63fe3a34e6a611a52458847155bff768#/use/session?id=%E5%9C%A8-session-%E4%B8%8A%E5%AD%98%E5%8F%96%E5%80%BC

六、sa-token 登录拦截器

1、路由权限拦截器

类路径:com.ruoyi.framework.config.SaTokenConfig,实现WebMvcConfigurer 接口

1-通过 registry.addInterceptor(new SaInterceptor(handler -> { } 添加 SaInterceptor 拦截器

2-在拦截器中可以自定义登录、角色、权限的校验

  • 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录 SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin());
  • 角色校验 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证 SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin")); 权限校验 -- 不同模块校验不同权限 SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));

3- 排除不需要拦截的路径(该配置在 ruoyi-admin 模块的yml中配置
            .excludePathPatterns(securityProperties.getExcludes());

其他注入  

  • 通过 getStpLogicJwt 方法, 注入 tpLogic 类是为了整合Jwt
  • 通过 stpInterface方法,注入 StpInterface 接口,手动去实现
  • 注入SaTokenDao ,实现对redis对sotoken的读写
    
@RequiredArgsConstructor
@Slf4j
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {private final SecurityProperties securityProperties;/*** 注册sa-token的拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册路由拦截器,自定义验证规则registry.addInterceptor(new SaInterceptor(handler -> {AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class);// 登录验证 -- 排除多个路径SaRouter// 获取所有的.match(allUrlHandler.getUrls())// 对未排除的路径进行检查.check(() -> {// 检查是否登录 是否有tokenStpUtil.checkLogin();// 有效率影响 用于临时测试// if (log.isDebugEnabled()) {//     log.info("剩余有效时间: {}", StpUtil.getTokenTimeout());//     log.info("临时有效时间: {}", StpUtil.getTokenActiveTimeout());// }});})).addPathPatterns("/**")// 排除不需要拦截的路径.excludePathPatterns(securityProperties.getExcludes());}@Beanpublic StpLogic getStpLogicJwt() {// Sa-Token 整合 jwt (简单模式)return new StpLogicJwtForSimple();}/*** 权限接口实现(使用bean注入方便用户替换)*/@Beanpublic StpInterface stpInterface() {return new SaPermissionImpl();}/*** 自定义dao层存储* PlusSaTokenDao  Sa-Token持久层接口(使用框架自带RedisUtils实现 协议统一)*/@Beanpublic SaTokenDao saTokenDao() {return new PlusSaTokenDao();}}
2- saTokenDao

     上面配置中,自定义dao层存储,注入 PlusSaTokenDao 作为 Sa-Token持久层接口(使用框架自带RedisUtils实现 协议统一) ,
     

@Beanpublic SaTokenDao saTokenDao() {return new PlusSaTokenDao();}

若果不去自己实现sotoken的DAO层接口,框架默认会基于内存区存储,如下 SaTokenDaoDefaultImpl 类实现 SaTokenDao

public class SaTokenDaoDefaultImpl implements SaTokenDao {public Map<String, Object> dataMap = new ConcurrentHashMap();public Map<String, Long> expireMap = new ConcurrentHashMap();.......
3-sotoken Jwt 介绍

JWT就是上述流程当中token的一种具体实现方式,其全称是JSON Web Token

通俗地说,JWT的本质就是一个字符串,它是将用户信息保存到一个Json字符串中,然后进行编码后得到一个JWT token,并且这个JWT token带有签名信息,接收后可以校验是否被篡改,所以可以用于在各方之间安全地将信息作为Json对象传输。JWT的详细博文如下:

JWT详解-CSDN博客文章浏览阅读10w+次,点赞927次,收藏4.6k次。本文从本人博客搬运,原文格式更加美观,可以移步原文阅读:JWT详解JWT简介1.什么是JWT在介绍JWT之前,我们先来回顾一下利用token进行用户身份验证的流程:客户端使用用户名和密码请求登录服务端收到请求,验证用户名和密码验证成功后,服务端会签发一个token,再把这个token返回给客户端客户端收到token后可以把它存储起来,比如放到cookie中客户端每次向服务端请求资源时需要携带服务端签发的token,可以在cookie或者header中携带服务端收到请求,然后去验证客户端请_jwt详解https://blog.csdn.net/weixin_45070175/article/details/118559272

 

1-集成

依赖:ruoyi-common/pom.xml 中

        <!-- Sa-Token 整合 jwt --><dependency><groupId>cn.dev33</groupId><artifactId>sa-token-jwt</artifactId></dependency>

 配置秘钥 : 上面 ruoyi-amin配置文件sotoken中配置

# Sa-Token配置
sa-token:# jwt秘钥jwt-secret-key: abcdefghijklmnopqrstuvwxyz

 com.ruoyi.framework.config.SaTokenConfig 类中注入

 @Beanpublic StpLogic getStpLogicJwt() {// Sa-Token 整合 jwt (简单模式)return new StpLogicJwtForSimple();}

整合文档参考:

和 jwt 集成 (sa-token.cc)icon-default.png?t=N7T8https://sa-token.cc/doc.html?code=25446615d46b82ca1f92853e66d5d64c63fe3a34e6a611a52458847155bff768#/plugin/jwt-extend

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

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

相关文章

聚类分析|基于层次的聚类方法及其Python实现

聚类分析|基于层次的聚类方法及其Python实现 0. 基于层次的聚类方法1. 簇间距离度量方法1.1 最小距离1.2 最大距离1.3 平均距离1.4 中心法1.5 离差平方和 2. 基于层次的聚类算法2.1 凝聚&#xff08;Agglomerative&#xff09;2.3 分裂&#xff08;Divisive&#xff09; 3. 基于…

GAMES Webinar 288-VR/AR专题-陆峰-混合现实中的多模态自然人机交互

感知交互增强智能 研究室虚拟现实技术与系统国家重点实验室&#xff0c;北京航空航天大学计算医学研究所&#xff0c;大数据精准医疗北京市高精尖创新中心 Perception & Hybrid Interaction (PHI) for Augmented & Affective Intelligence (A2I) We are working on v…

力扣56. 合并区间

Problem: 56. 合并区间 文章目录 题目描述思路及解法复杂度Code 题目描述 思路及解法 1.将数组按内部的一维数组的第一项按从小到大的顺序排序&#xff1b; 2.创建二维结果数组merged&#xff0c;并将排序后的数组中的第一个一维度数组存入到merged中&#xff1b; 3.从后面的一…

九泰智库 | 医械周刊- Vol.17

⚖️ 法规动态 器审中心公示新一期医疗器械优先审批申请审核结果 3月22日&#xff0c;依据原国家食品药品监督管理总局《医疗器械优先审批程序》&#xff08;总局公告2016年168号&#xff09;&#xff0c;器审中心对申请优先审批的医疗器械注册申请进行了审核&#xff0c;对相关…

elasticsearch _cat/indices docs.count is different than <index>/_count

今天遇到一个问题&#xff0c;kibana中看到文档数与下面语句查询到的不同 GET /_cat/count/jiankunking_xxxxx_product_expand_test?v GET /jiankunking_xxxxx_product_expand_test/_search?track_total_hitstrue语句查询结果 epoch timestamp count 1711433785 06:16…

详解从ERP传到MES系统的数据

1、物料需求计划 MES系统提供的物料需求计划与传统BOM-MRP方式提供的物料需求计划有本质的不同。首先&#xff0c;满足产能约束、各种生产约束、优化生产调度、提高工作效率的要求。其次&#xff1a;它有详细的以分钟为单位的时间信息。将这些数据提供给ERP&#xff0c;可以大…

是德科技KEYSIGHT N9938A频谱分析仪

181/2461/8938产品概述&#xff1a; N9938A 是一款使用电池供电的便携式微波频谱分析仪&#xff1b;配置还包括全频段跟踪发生器和前置放大器、干扰分析仪、时间选通、VSWR 和反射测量、内置功率计。 N9938A FieldFox 手持式微波频谱分析仪 主要特性和功能 频率范围&#xff…

美团面试一面凉经

1.自我介绍 2.科研项目提问 没咋准备&#xff0c;说的有点没逻辑 3.问论坛项目 为什么用Redis实现登录&#xff1f;能不能用其他方式实现&#xff1f; 1、Redis 具备高性能 假如用户第一次访问 MySQL 中的某些数据。这个过程会比较慢&#xff0c;因为是从硬盘上读取的。将…

000_coolprop_in_matlab在Matlab中使用CoolProp

在Matlab中使用CoolProp 简介 CoolProp是一个开源的热力学性质库&#xff0c;可以计算多种流体的热力学性质。CoolProp支持多种编程语言&#xff0c;包括Python、C、Matlab等。本文将介绍如何在Matlab中使用CoolProp。 CoolProp官网 本文所使用的Matlab版本为R2021a。 在Ma…

C++基础--类和对象(上)--类与类成员及其成员函数

C基础--类和对象&#xff08;上&#xff09;--类与类成员及其成员函数 一、类的引入二、类的定义三、类的访问限定符及封装1、访问限定符2、封装 四、类的作用域五、类的实例化六、类的对象大小的计算七、类成员函数的 this 指针1、this指针的引出2、this指针的特性 八、总结 一…

Vit Transformer

一 VitTransformer 介绍 vit : An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale 论文是基于Attention Is All You Need&#xff0c;由于图像数据和词数据数据格式不一样&#xff0c;经典的transformer不能处理图像数据&#xff0c;在视觉领域的应…

4、事件修饰符、过滤器、自定义指令、生命周期

一、事件修饰符 按键别名enter 回车 delete 删除键 esc取消键 space 空格键 <script> export default {name: "KeyUp",methods:{keyUp(e){ console.log(e) }},skip(){window.location.href "http:www.xx.com"} } </script> <template>…

鸿蒙应用开发-录音保存并播放音频

功能介绍&#xff1a; 录音并保存为m4a格式的音频&#xff0c;然后播放该音频&#xff0c;参考文档使用AVRecorder开发音频录制功能(ArkTS)&#xff0c;更详细接口信息请查看接口文档&#xff1a;ohos.multimedia.media (媒体服务)。 知识点&#xff1a; 熟悉使用AVRecorder…

super的使用细节

1、super的使用细节 2、super和this的比较

159.乐理基础-和声模板是什么?优缺点与运用要点

如果到这五线谱还没记住还不认识的话去看102.五线谱-高音谱号与103.五线谱-低音谱号这两个里&#xff0c;这里面有五线谱对应的音名&#xff0c;对比着看 如果一章没落下&#xff0c;看到这里&#xff0c;但是看不懂什么意思&#xff0c;那就强行下看&#xff0c;看着看着指不…

[leetcode]118.杨辉三角

前言&#xff1a;剑指offer刷题系列 问题&#xff1a; 给定一个非负整数 *numRows&#xff0c;*生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例&#xff1a; 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,…

CKS之镜像漏洞扫描工具:Trivy

目录 Trivy介绍 Trivy安装 Trivy使用命令 容器镜像扫描 打印指定&#xff08;高危、严重&#xff09;漏洞信息 JSON格式输出 HTML格式输出 离线扫描命令 离线更新Trivy数据库 Harbor安装Trivy Trivy介绍 Trivy是一款用于扫描容器镜像、文件系统、Git仓库等的漏洞扫描…

Matlab|基于两阶段鲁棒优化的微网电源储能容量优化配置

目录 主要内容 1.1 目标函数 1.2 约束条件 1.3 不确定变量 部分代码 结果一览 下载链接 主要内容 程序主要复现的是《考虑寿命损耗的微网电池储能容量优化配置》&#xff0c;解决微网中电源/储能容量优化配置的问题&#xff0c;即风电、光伏、储能以及燃气轮机…

LeetCode - 执行子串操作后的字典序最小字符串

题目要求经过操作后的字符串的字典序要比之前小。 在做这道题的之后陷入了一个误区&#xff0c;就是看a的位置&#xff0c;a-1之后z&#xff0c;z的字典序比a大&#xff0c;所以要尽可能的避免a变成z&#xff0c;但是字典序的比较是从前往后比较的&#xff0c;纠结于a变成z&am…

NSCaching: Simple and Efficient NegativeSampling for Knowledge Graph Embedding

摘要 知识图嵌入是数据挖掘研究中的一个基本问题&#xff0c;在现实世界中有着广泛的应用。它的目的是将图中的实体和关系编码到低维向量空间中&#xff0c;以便后续算法使用。负抽样&#xff0c;即从训练数据中未观察到的负三元组中抽取负三元组&#xff0c;是KG嵌入的重要步…