@EnableResourceServer资源服务注解源码分析
文章目录
- 学习参考
- @EnableResourceServer
- 概要
- ResourceServerConfiguration
- 属性定义
- configure(HttpSecurity)
- ResourceServerSecurityConfigurer
- init(HttpSecurit)
- configure(HttpSecurity)
学习参考
Spring Security框架配置运行流程完整分析 - 【必看】
Security OAuth2 授权 & JWT
OAuth2授权流程和源码解析 - 自己总结 - 有道笔记~
@EnableAuthorizationServer授权服务注解源码分析
@EnableResourceServer资源服务注解源码分析
Spring Security整合Gitee第三方登录
第三方登录源码梳理 - 自己总结 - 有道笔记~
Security OAuth2 SSO单点登录(一)
Security OAuth2 SSO单点登录源码剖析 - 自己总结 - 有道笔记~
@EnableResourceServer
概要
@EnableResourceServer用于开启资源服务器,它使用@Import注解引入了ResourceServerConfiguration
- ResourceServerConfiguration
资源服务器配置类
,继承自继承自WebSecurityConfigurerAdapter,order为3,大于AuthorizationServerSecurityConfiguration的order,其中WebSecurityConfigurerAdapter的order默认为100;由此可见它们的顺序:AuthorizationServerSecurityConfiguration、ResourceServerConfiguration、WebSecurityConfigurerAdapter- 自动注入容器中定义的TokenStore令牌存储组件、所有的tokenServices资源服务器令牌服务、AuthorizationServerEndpointsConfiguration授权服务器端点配置类、所有的
ResourceServerConfigurer
资源服务器配置器 - 在配置HttpSecurity时,会创建1个
ResourceServerSecurityConfigurer
资源服务器安全配置器,它用于添加到HttpSecurity中继续配置HttpSecurity,会往HttpSecurity中添加OAuth2AuthenticationProcessingFilter
这一重要的过滤器,该OAuth2AuthenticationProcessingFilter用于使用令牌加载OAuth2Authenticaiton认证对象,绑定到当前线程中。 - 在配置HttpSecurity时,也会对把自动注入的TokenStore、tokenServices设置到ResourceServerSecurityConfigurer资源服务器安全配置器中,并且会使用ResourceServerConfigurer资源服务器配置器对该ResourceServerSecurityConfigurer资源服务器安全配置器进行配置
- 可定义ResourceServerConfigurer类型的bean来配置ResourceServerSecurityConfigurer和HttpSecurity,它们的配置过程都在ResourceServerConfiguration的configure(HttpSecurity)方法中
ResourceServerConfiguration
资源服务器配置类
,继承自继承自WebSecurityConfigurerAdapter,order为3
属性定义
/* 尝试注入容器中的 TokenStore 令牌存储器 */
@Autowired(required = false)
private TokenStore tokenStore;/* 尝试注入容器中的 AuthenticationEventPublisher 认证事件发布器 */
@Autowired(required = false)
private AuthenticationEventPublisher eventPublisher;/* 尝试注入容器中的 ResourceServerTokenServices 资源服务器令牌服务 */
@Autowired(required = false)
private Map<String, ResourceServerTokenServices> tokenServices;/* 注入 ApplicationContext 应用上下文 */
@Autowired
private ApplicationContext context;/* 注入容器中的所有定义的 ResourceServerConfigurer 资源服务器配置器 */
private List<ResourceServerConfigurer> configurers = Collections.emptyList();/* 尝试注入容器中的 AuthorizationServerEndpointsConfiguration 授权服务器都单点配置类因为: 授权服务器经常也会开启资源服务器的功能, 如果未开启, 这里就会是null */
@Autowired(required = false)
private AuthorizationServerEndpointsConfiguration endpoints;
configure(HttpSecurity)
其实就是在配置ResourceServerSecurityConfigurer 资源服务器安全配置器,而 资源服务器安全配置器 则是为了给HttpSecurity添加1个OAuth2AuthenticationProcessingFilter过滤器
@Override
protected void configure(HttpSecurity http) throws Exception {// 创建1个【ResourceServerSecurityConfigurer 资源服务器安全配置器】, 用来继续配置HttpSecurityResourceServerSecurityConfigurer resources = new ResourceServerSecurityConfigurer();// 解析出1个 资源服务器令牌服务, // 从自动注入的tokenServices中获取, 如果没有, 则返回null; 如果只有1个, 则选择这个; 如果有多个, 须使用@Primary来标注使用哪个ResourceServerTokenServices services = resolveTokenServices();// 如果解析出来了 ResourceServerTokenServices 资源服务器令牌服务, 则设置给 资源服务器安全配置器 的 resourceTokenServices属性if (services != null) {resources.tokenServices(services);}else {// 此时, 容器中未定义任何 ResourceServerTokenServices 资源服务器令牌服务if (tokenStore != null) {// 如果令牌存储器有定义 TokenStore令牌存储器, // 则将此TokenStore设置给 【ResourceServerSecurityConfigurer 资源服务器安全配置器】的tokenStore属性resources.tokenStore(tokenStore);}else if (endpoints != null) {// 此时容器中未定义任何 TokenStore令牌存储器, 则使用AuthorizationServerEndpointsConfiguration的endpoints的tokenStore属性// 设置给【ResourceServerSecurityConfigurer 资源服务器安全配置器】的tokenStore属性resources.tokenStore(endpoints.getEndpointsConfigurer().getTokenStore());}}// 如果容器中有定义 AuthenticationEventPublisher 认证事件发布器, 则将它设置给【ResourceServerSecurityConfigurer 资源服务器安全配置器】if (eventPublisher != null) {resources.eventPublisher(eventPublisher);}// 使用容器中所有定义的 *ResourceServerConfigurer* 资源服务器配置器 来配置【ResourceServerSecurityConfigurer 资源服务器安全配置器】// 这个扩展点非常重要, 注意它的执行时机哦~for (ResourceServerConfigurer configurer : configurers) {configurer.configure(resources);}// 给HttpSecurity添加一些配置器http// 1. 给HttpSecurity的sharedObjects属性中AuthenticationManagerBuilder类型的公共属性添加AnonymousAuthenticationProvider// 2. 这个AuthenticationManagerBuilder的公共属性, 在 WebSecurityConfigurerAdapter 的 getHttp()方法中, 在创建HttpSecurity时, // 就会把WebSecurityConfigurerAdapter的authenticationBuilder属性作为AuthenticationManagerBuilder传进去作为HttpSecurity的公共属性.authenticationProvider(new AnonymousAuthenticationProvider("default"))// 添加异常处理配置器, 将resources的accessDeniedHandler设置给异常处理配置器.exceptionHandling().accessDeniedHandler(resources.getAccessDeniedHandler()).and()// 添加会话管理配置器, 不使用HttpSession.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()// 移除掉csrf配置器.csrf().disable();// 将【ResourceServerSecurityConfigurer 资源服务器安全配置器】添加到HttpSecurity, // 目的是使用刚刚配置好的 资源服务器安全配置器 来配置HttpSecurityhttp.apply(resources);// 1. 如果 AuthorizationServerEndpointsConfiguration 不为空, 那说明开启了授权服务器// 那就把@FrameworkEndpoint标注的处理器方法的请求路径排除在 资源服务过滤器链 之外// 2. 其实根本就不用吧?!当同时开启授权服务和资源服务的话, 授权服务过滤器链肯定排在资源服务器链前面, 那么肯定先匹配上授权服务过滤器链阿, // 这在AuthorizationServerSecurityConfiguration的configure(HttpSecurity)方法中就设置了资源过滤器链的匹配的路径,// 难道这里只是想说 授权服务的请求不归资源服务器链管?if (endpoints != null) {http.requestMatcher(new NotOAuthRequestMatcher(endpoints.oauth2EndpointHandlerMapping()));}// 使用容器中所有定义的 *ResourceServerConfigurer* 资源服务器配置器 来配置HttpSecurity过滤器链// 这个扩展点非常重要, 注意它的执行时机哦~for (ResourceServerConfigurer configurer : configurers) {configurer.configure(http);}// 如果没有定义 ResourceServerConfigurer 资源服务器配置器, 那就对资源服务过滤器链匹配到的请求 都需要认证后,才能访问if (configurers.isEmpty()) {http.authorizeRequests().anyRequest().authenticated();}
}
ResourceServerSecurityConfigurer
资源服务器安全配置器,用于给HttpSecurity添加OAuth2AuthenticationProcessingFilter过滤器,该过滤器会通过读取令牌加载OAuth2Authentication绑定到当前线程,以确认客户端身份和用户授权信息。
// 异常处理过滤器的认证入口点
AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();// 异常处理过滤器的访问拒绝处理器
AccessDeniedHandler accessDeniedHandler = new OAuth2AccessDeniedHandler();// 【OAuth2AuthenticationProcessingFilter 资源服务器过滤器】
// 它会使用 TokenExtractor 令牌提取器 从当前请求中获取 令牌, 然后把令牌交给 OAuth2AuthenticationManager 作认证, OAuth2AuthenticationManager 又会交给 ResourceServerTokenServices 来加载 OAuth2Authentication 认证对象
OAuth2AuthenticationProcessingFilter resourcesServerFilter;// 认证管理器, 实现一般为: OAuth2AuthenticationManager, 它会持有ResourceServerTokenServices, 用于读取令牌
AuthenticationManager authenticationManager;// 认证事件发布器
AuthenticationEventPublisher eventPublisher = null;// 资源服务器令牌服务, 用于读取令牌, 以获得OAuth2Authentication认证对象
ResourceServerTokenServices resourceTokenServices;// 令牌存储器, 用户存储令牌和查询令牌
TokenStore tokenStore = new InMemoryTokenStore();// 资源服务标识, 用于标识此资源服务。同时, ClientDetails客户端必须拥有该资源服务, 才能访问该资源
String resourceId = "oauth2-resource";// 用于支持权限表达式, 可参考: Security方法注解权限控制过程及自定义权限表达式 https://blog.csdn.net/qq_16992475/article/details/130462486
SecurityExpressionHandler<FilterInvocation> expressionHandler = new OAuth2WebSecurityExpressionHandler();// 令牌提取器, 用于在 OAuth2AuthenticationProcessingFilter 过滤器中, 从请求中获取令牌
TokenExtractor tokenExtractor;// 获取认证详情信息
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;// 是否无状态。
// 如果是false, 则不仅仅是OAuth2客户端可以访问, 非OAuth2客户端也可以访问;
// 如果是true, 则如果是非OAuth2客户端已被认证了, 那么在OAuth2AuthenticationProcessingFilter中会清除掉这个认证对象
//(注意OAuth2AuthenticationProcessingFilter过滤器排在UsernamePasswordAuthenticationFilter前面, 这在FilterComparator和ResourceServerSecurityConfigurer的configure(HttpSecurity)方法中可以看到)
boolean stateless = true;
init(HttpSecurit)
@Override
public void init(HttpSecurity http) {// 1. 其实就是给HttpSecurity过滤器链上的异常过滤器设置入口点属性,// 2. 将当前ResourceServerSecurityConfigurer资源服务器安全配置器的authenticationEntryPoint属性设置到ExceptionHandlingConfigurer的defaultEntryPointMappings中, 并以MediaTypeRequestMatcher实例作为keyregisterDefaultAuthenticationEntryPoint(http);
}
configure(HttpSecurity)
@Override
public void configure(HttpSecurity http) {// 创建1个 OAuth2AuthenticationManager OAuth2认证管理器, 并完成 OAuth2认证管理器 的配置AuthenticationManager oauthAuthenticationManager = oauthAuthenticationManager(http);// 创建1个 【OAuth2AuthenticationProcessingFilter 过滤器】resourcesServerFilter = new OAuth2AuthenticationProcessingFilter();// 给 【OAuth2AuthenticationProcessingFilter 过滤器】 设置 OAuth2认证管理器 和 认证入口点resourcesServerFilter.setAuthenticationEntryPoint(authenticationEntryPoint);resourcesServerFilter.setAuthenticationManager(oauthAuthenticationManager);// 【OAuth2AuthenticationProcessingFilter 过滤器】 设置 认证事件发布器if (eventPublisher != null) {resourcesServerFilter.setAuthenticationEventPublisher(eventPublisher);}// 给 【OAuth2AuthenticationProcessingFilter 过滤器】 设置 令牌提取器if (tokenExtractor != null) {resourcesServerFilter.setTokenExtractor(tokenExtractor);}// 给 【OAuth2AuthenticationProcessingFilter 过滤器】 设置 认证详情源if (authenticationDetailsSource != null) {resourcesServerFilter.setAuthenticationDetailsSource(authenticationDetailsSource);}// 使用ObjectPostProcessor处理 【OAuth2AuthenticationProcessingFilter 过滤器】resourcesServerFilter = postProcess(resourcesServerFilter);// 给 【OAuth2AuthenticationProcessingFilter 过滤器】 设置 statelessresourcesServerFilter.setStateless(stateless);http// 添加FilterSecurityInterceptor过滤器, 并添加支持权限表达式处理器.authorizeRequests().expressionHandler(expressionHandler).and()// 添加【OAuth2AuthenticationProcessingFilter 过滤器】, 放置在AbstractPreAuthenticatedProcessingFilter前面// 在我们熟悉的 UsernamePasswordAuthenticationFilter, 可在FilterComparator中看到.addFilterBefore(resourcesServerFilter, AbstractPreAuthenticatedProcessingFilter.class)// 添加异常处理配置器, 并指定 访问拒绝处理器 和 认证入口点.exceptionHandling().accessDeniedHandler(accessDeniedHandler).authenticationEntryPoint(authenticationEntryPoint);
}private AuthenticationManager oauthAuthenticationManager(HttpSecurity http) {// 创建1个 OAuth2AuthenticationManager OAuth2认证管理器OAuth2AuthenticationManager oauthAuthenticationManager = new OAuth2AuthenticationManager();// 如果已经设置认证管理器, 并且 如果认证管理器是 OAuth2AuthenticationManager 那么给该oauthAuthenticationManager继续设置属性, // 如果认证管理器不是 OAuth2AuthenticationManager 类型, 那么直接返回if (authenticationManager != null) {if (authenticationManager instanceof OAuth2AuthenticationManager) {oauthAuthenticationManager = (OAuth2AuthenticationManager) authenticationManager;}else {return authenticationManager;}}// 设置 资源服务标识, 若客户端无该资源服务标识, 将不能访问该资源oauthAuthenticationManager.setResourceId(resourceId);// 获取 资源服务器令牌服务, 并设置给 OAuth2认证管理器oauthAuthenticationManager.setTokenServices(resourceTokenServices(http));// 获取 客户端服务, 并设置给 OAuth2认证管理器oauthAuthenticationManager.setClientDetailsService(clientDetails());// 返回配置好的 OAuth2认证管理器return oauthAuthenticationManager;
}// 获取资源服务器令牌服务
private ResourceServerTokenServices resourceTokenServices(HttpSecurity http) {// 获取 ResourceServerSecurityConfigurer 设置的 resourceTokenServices 或 创建1个DefaultTokenServices 作为 资源服务器令牌服务tokenServices(http);return this.resourceTokenServices;
}// 获取 资源服务器令牌服务
private ResourceServerTokenServices tokenServices(HttpSecurity http) {// 如果设置 给 ResourceServerSecurityConfigurer 设置了 resourceTokenServices, 就直接返回指定的资源服务器令牌服务if (resourceTokenServices != null) {return resourceTokenServices;}// 未给 ResourceServerSecurityConfigurer 设置 令牌服务 属性时, // 就会创建默认的令牌服务, 并使用 ResourceServerSecurityConfigurer 设置 的令牌存储器// 创建1个默认的令牌服务DefaultTokenServices tokenServices = new DefaultTokenServices();// 获取tokenStore 设置到 令牌服务 中()tokenServices.setTokenStore(tokenStore());// 设置支持刷新令牌tokenServices.setSupportRefreshToken(true);// 设置客户端详情服务tokenServices.setClientDetailsService(clientDetails());// DefaultTokenServices可作为资源服务器令牌服务this.resourceTokenServices = tokenServices;return tokenServices;
}// 获取 令牌存储器
// 直接返回 ResourceServerSecurityConfigurer 的 tokenStore 属性, 显然它一定要被设置, 否则一调用就会抛异常
private TokenStore tokenStore() {Assert.state(tokenStore != null, "TokenStore cannot be null");return this.tokenStore;
}// 获取访问拒绝处理器, 直接返回 ResourceServerSecurityConfigurer 的 accessDeniedHandler 属性
public AccessDeniedHandler getAccessDeniedHandler() {return this.accessDeniedHandler;
}
相关文章:
@EnableResourceServer资源服务注解源码分析
文章目录 学习参考EnableResourceServer概要ResourceServerConfiguration属性定义configure(HttpSecurity)ResourceServerSecurityConfigurerinit(HttpSecurit)configure(HttpSecurity) 学习参考 Spring Security框架配置运行流程完整分析 - 【必看】 Security OAuth2 授权 &…...

SpringBoot实现图片文件上传和回显的两种方式
目录 一 功能需求 二 上传本地 2.1 实现文件上传的controller层 2.2 图片访问资源映射 二 上传OSS 一 功能需求 实现图片的上传和回显功能其实在业务中是非常常见的,比如需要上传头像,或者交易平台需要上传物品的图片等等,都需要上传和回…...

进程和计划任务以及步骤
进程 进程和程序有关,把该文件放到内存里,进程是动态的,不同时刻的状态不一样 内存:放置正在运行的程序和所需数据的位置 程序启动 ——》将相关文件和数据放到内存里 ——》进程(processes) 进程相关命令 …...
使用Python实现深度学习模型:序列到序列模型(Seq2Seq)
序列到序列(Seq2Seq)模型是一种深度学习模型,广泛应用于机器翻译、文本生成和对话系统等自然语言处理任务。它的核心思想是将一个序列(如一句话)映射到另一个序列。本文将详细介绍 Seq2Seq 模型的原理,并使…...
力扣283. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出:[1,3,12,0,0] 示例 2: 输入: nums [0] …...

二叉树的顺序结构(堆的实现)
前言 普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结 构存储。 现实中我们通常把堆 ( 一种二叉树 ) 使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统 虚拟进程地址空间中的堆是两回事&…...

2024大模型如何学习【附学习资料】
摘要: 通过深入了解本文中的这些细节,并在实际项目中应用相关知识,将能够更好地理解和利用大模型的潜力,不仅在学术研究中,也在工程实践中。通过不断探索新方法、参与项目和保持热情,并将其应用于各种领域&…...

计算机组成原理·考点知识点整理
根据往年考试题,对考点和知识点的一个整理。 校验编码 码距 一种编码的最小码距,其实就是指这种编码的码距。码距有两种定义: 码距所描述的对象含义 2 2 2 个特定的码其二进制表示中不同位的个数一种编码这种编码中任意 2 2 2 个合法编码的…...
python-datetime模块时间戳常用方法汇总
文章目录 datetime模块常用方法1、导入模块2、获取当前日期和时间3、获取当前日期4、创建特定日期或时间5、日期和时间的运算6、使用timedelta运算日期时间创建 timedelta 对象timedelta 的加减运算timedelta 的属性timedelta 的比较示例代码格式化日期和时间获取日期和时间的各…...

【Python报错】已解决ModuleNotFoundError: No module named ‘timm’
成功解决“ModuleNotFoundError: No module named ‘timm’”错误的全面指南 一、引言 在Python编程中,经常会遇到各种导入模块的错误,其中“ModuleNotFoundError: No module named ‘timm’”就是一个典型的例子。这个错误意味着你的Python环境中没有安…...
【设计模式】适配器模式(结构型)⭐⭐⭐
文章目录 1.概念1.1 什么是适配器模式1.2 优点与缺点 2.实现方式2.1 类适配器模式2.2 对象适配器模式 3 Java 哪些地方用到了适配器模式4 Spring 哪些地方用到了适配器模式 1.概念 1.1 什么是适配器模式 简单来说,适配器模式就是作为两个不兼容接口之间的桥梁。 1.…...
云原生周刊:Gateway API v1.1 发布 | 2024.6.3
开源项目推荐 Grafana Tanka Tanka 是 Grafana 开发的一款用于 Kubernetes 的灵活、可重用和简洁的配置工具,是使用 YAML 进行 Kubernetes 配置的一种替代方案。 pv-migrate pv-migrate 是一个 CLI 工具/kubectl 插件,可以轻松地将一个 Kubernetes PersistentVo…...

KotlinConf 2024:深入了解Kotlin Multiplatform (KMP)
KotlinConf 2024:深入了解Kotlin Multiplatform (KMP) 在近期的Google I/O大会上,我们推荐了Kotlin Multiplatform (KMP)用于跨移动、网页、服务器和桌面平台共享业务逻辑,并在Google Workspace中采用了KMP。紧接着,KotlinConf 2…...

探索ChatGPT-4在解决化学知识问题上的研究与应用
1. 概述 近年来,人工智能的发展主要集中在 GPT-4 等大型语言模型上。2023 年 3 月发布的这一先进模型展示了利用广泛知识应对从化学研究到日常问题解决等复杂挑战的能力。也开始进行研究,对化学的各个领域,从化学键到有机化学和物理化学&…...

性能狂飙:SpringBoot应用优化实战手册
在数字时代,速度就是生命,性能就是王道!《极速启航:SpringBoot性能优化的秘籍》带你深入SpringBoot的内核,探索如何打造一个飞速响应、高效稳定的应用。从基础的代码优化到高级的数据库连接池配置,再到前端…...

Github上一款开源、简洁、强大的任务管理工具:Condution
Condution 是一款开源任务管理工具,它以简洁易用、功能强大著称。它旨在为用户提供一个简单高效的平台,帮助他们管理日常任务、提高工作效率。 1. Condution 的诞生背景 现如今,市面上存在着许多任务管理软件,但它们往往价格昂贵…...

LeetCode-2938. 区分黑球与白球【贪心 双指针 字符串】
LeetCode-2938. 区分黑球与白球【贪心 双指针 字符串】 题目描述:解题思路一:贪心解题思路二:一次遍历统计1的个数,找0后累加左边的1的个数解题思路三: 题目描述: 桌子上有 n 个球,每个球的颜色…...

深度神经网络——什么是扩散模型?
1. 概述 在人工智能的浩瀚领域中,扩散模型正成为技术创新的先锋,它们彻底改变了我们处理复杂问题的方式,特别是在生成式人工智能方面。这些模型基于高斯过程、方差分析、微分方程和序列生成等坚实的数学理论构建。 业界巨头如Nvidia、Google…...
有代码冗余的检查工具嘛
是的,有一些代码质量工具可以帮助检查冗余代码。这些工具可以分析代码库,并识别出重复、冗余或不必要的代码片段。一些流行的代码质量工具包括: PMD: PMD 是一个开源的静态代码分析工具,支持多种编程语言,包括 Java、…...

3D培训大师:快速输出标准3D课件,打造沉浸式培训体验
随着技术的日新月异和市场的迅猛扩张,企业对员工专业技能培训的需求日益凸显。传统的培训方式往往依赖于实地操作、现场指导,这不仅需要大量的人力、物力和时间成本,而且存在安全风险。特别是化工、机械制造等行业,实操培训的成本…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...

五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...
规则与人性的天平——由高考迟到事件引发的思考
当那位身着校服的考生在考场关闭1分钟后狂奔而至,他涨红的脸上写满绝望。铁门内秒针划过的弧度,成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定",构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...
CppCon 2015 学习:Time Programming Fundamentals
Civil Time 公历时间 特点: 共 6 个字段: Year(年)Month(月)Day(日)Hour(小时)Minute(分钟)Second(秒) 表示…...