新版SpringSecurity5.x使用与配置
目录
一、了解SpringSecurity
1.1 什么是Spring Security?
1.2 Spring Security功能
1.3 Spring Security原理
1.4 RABC (Role-Based Access Control)
二、SpringSecurity简单案例
2.1 引入SpringSecurity依赖
2.2 创建一个简单的Controller
三、SpringSecurity配置
3.1 自定义用户与密码
3.2 允许匿名访问路径
3.3 数据库实现登陆校验
3.4 实现角色权限访问
3.5 对密码进行B加密
3.6 结合Jwt实现多重校验
一、了解SpringSecurity
1.1 什么是Spring Security?
Spring Security 是一个强大且高度可定制的身份验证和访问控制框架。它是 Spring 生态系统的一部分,为基于 Spring 的应用提供了全面的安全服务。Spring Security 的设计目标是为应用的安全需求提供一个完整的解决方案,同时保持高度的灵活性和可扩展性。
1.2 Spring Security功能
Spring Security 提供的功能包括但不限于:
- 认证(Authentication):验证用户身份,通常需要用户名和密码。
- 授权(Authorization):确定已认证的用户可以访问哪些资源或执行哪些操作。
- CSRF 保护:防止跨站请求伪造攻击。
- 会话管理:处理用户的会话,包括会话的创建、维护和销毁。
- 加密和编码:提供加密和散列算法的支持。
- OAuth2 和 OpenID Connect 支持:集成 OAuth2 和 OpenID Connect 协议,实现第三方认证。
- CORS 支持:处理跨域资源共享(Cross-Origin Resource Sharing)请求。
- 安全配置:允许通过 XML 或 Java 配置来定制安全策略。
1.3 Spring Security原理
Spring Security 的工作原理涉及几个关键组件:
- SecurityContext:存储认证信息,如当前登录用户和他们的权限。
- AuthenticationManager:负责用户认证,通常使用
UserDetailsService
来加载用户信息。 - AccessDecisionManager:决定用户是否有权访问特定资源。
- Filter Chain:一系列的过滤器处理请求和响应,例如
UsernamePasswordAuthenticationFilter
用于处理用户名和密码的提交。
1.4 RABC (Role-Based Access Control)
RABC,即基于角色的访问控制,是一种常见的访问控制机制,用于管理用户对资源的访问权限。在 RABC 中,权限不是直接授予用户,而是授予用户所属的角色。每个用户可以拥有一个或多个角色,而每个角色则有一组相应的权限。这种机制简化了权限管理,因为只需更改用户的角色就可以改变他们的权限集。
二、SpringSecurity简单案例
2.1 引入SpringSecurity依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-test</artifactId><scope>test</scope>
</dependency>
2.2 创建一个简单的Controller
@RestController
public class HelloController {@GetMapping("Hello")public String Hello(){return "Hello SpringSecurity";}
}
2.3 运行后访问localhost:8080/Hello,会自动跳转到localhost:8080/login
这里的用户密码都在启动时候的控制台上 (注意:每一次启动密码都不一样)
用户名:user
密码: b82aa5e5-0a3a-466b-90a8-e94098877823(控制台上的一串密码)
登陆后成功访问
三、SpringSecurity配置
后面的配置都是基于小案例的基础上实现,请先完成上述的小案例
3.1 自定义用户与密码
由于每一次生成密码都是不固定的,对调试并不友好,springSecurity可以通过在application.yml中进行自定义设置用户和密码
spring:security:user:name: alphaMilkpassword: 123456
输入用户名和密码即可正常登陆并访问资源
3.2 允许匿名访问路径
在Spring Security框架中,允许某些路径或资源在未经过身份验证的情况下被访问,通常称为“允许匿名访问”。这种配置对于公共页面、登录页面、注册页面、API文档等是非常必要的,因为这些页面或资源需要对所有用户开放,无论他们是否已经登录。
以下通过配置类实现,用户能够匿名访问login页面
// 使用@Configuration标记此类为Spring的配置类
@Configuration
// 启用WebSecurity的自动配置,以便Spring Security可以管理Web安全
@EnableWebSecurity
public class SecurityConfiguration {// 定义一个名为securityFilterChain的bean,该bean将负责构建和应用安全过滤器链@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {// 配置HttpSecurity对象,定义安全规则http// 授权HTTP请求,定义哪些URL需要什么类型的访问控制.authorizeHttpRequests((authz) -> authz// 允许"/user/login" URL匿名访问.requestMatchers("/user/login").anonymous()// 所有其他请求都需要认证才能访问.anyRequest().authenticated())// 启用HTTP Basic认证,默认情况下提供简单的用户名/密码认证.httpBasic(Customizer.withDefaults());// 构建并返回SecurityFilterChainreturn http.build();}
}
创建一个LoginController类
@RestController
@RequestMapping("user")
public class LoginController {@GetMapping("/login")public String Login(){return "这是登陆资源页面";}
}
重启系统后直接访问,不需要登陆即可获取资源.
3.3 数据库实现登陆校验
通过自己数据库的用户和密码,实现登陆。将之前的自定义用户密码(application.yml中)都删除掉,并执行以下操作:
用户表单:
-- 创建一个包含用户信息和角色的简化表
CREATE TABLE IF NOT EXISTS `users` (`id` INT AUTO_INCREMENT PRIMARY KEY, -- 用户ID,自增主键`username` VARCHAR(255) NOT NULL UNIQUE, -- 用户名,唯一且不能为空`password` VARCHAR(255) NOT NULL, -- 密码,存储加密后的密码`role` ENUM('ROLE_USER', 'ROLE_ADMIN') NOT NULL, -- 角色,预定义为'ROLE_USER'或'ROLE_ADMIN'`enabled` TINYINT(1) NOT NULL DEFAULT 1 -- 用户状态,1表示启用,0表示禁用
);
注意:这里的role需要按照ROLE_身份 的方式进行存储以便springsecurity进行权限访问控制
插入案例数据 :
-- 插入示例用户数据
INSERT INTO `users` (`username`, `password`, `role`, `enabled`)
VALUES('user1', '123456', 'ROLE_USER', 1),('admin1', '123456', 'ROLE_ADMIN', 1),('disabledUser', '123456', 'ROLE_USER', 0);
引入依赖:
<!-- 数据库依赖--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.5</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>3.0.3</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency>
配置数据源:
spring:datasource:url: jdbc:mysql://localhost:3306/ap_security?characterEncoding=utf-8&serverTimezone=UTCusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver
创建User实体与mapper并加上启动注释
User实体
@TableName(value ="users")
@Data
public class Users implements Serializable {/*** */@TableId(type = IdType.AUTO)private Integer id;/*** */private String username;/*** */private String password;/*** */private Object role;/*** */private Integer enabled;@TableField(exist = false)private static final long serialVersionUID = 1L;@Overridepublic boolean equals(Object that) {if (this == that) {return true;}if (that == null) {return false;}if (getClass() != that.getClass()) {return false;}Users other = (Users) that;return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))&& (this.getUsername() == null ? other.getUsername() == null : this.getUsername().equals(other.getUsername()))&& (this.getPassword() == null ? other.getPassword() == null : this.getPassword().equals(other.getPassword()))&& (this.getRole() == null ? other.getRole() == null : this.getRole().equals(other.getRole()))&& (this.getEnabled() == null ? other.getEnabled() == null : this.getEnabled().equals(other.getEnabled()));}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((getId() == null) ? 0 : getId().hashCode());result = prime * result + ((getUsername() == null) ? 0 : getUsername().hashCode());result = prime * result + ((getPassword() == null) ? 0 : getPassword().hashCode());result = prime * result + ((getRole() == null) ? 0 : getRole().hashCode());result = prime * result + ((getEnabled() == null) ? 0 : getEnabled().hashCode());return result;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();sb.append(getClass().getSimpleName());sb.append(" [");sb.append("Hash = ").append(hashCode());sb.append(", id=").append(id);sb.append(", username=").append(username);sb.append(", password=").append(password);sb.append(", role=").append(role);sb.append(", enabled=").append(enabled);sb.append(", serialVersionUID=").append(serialVersionUID);sb.append("]");return sb.toString();}
}
UserMapper
public interface UsersMapper extends BaseMapper<Users> {}
@MapperScan
@SpringBootApplication
@MapperScan("com.example.mysecurity.mapper")
public class MySecurityApplication {public static void main(String[] args) {SpringApplication.run(MySecurityApplication.class, args);}}
测试mybatisPlus是否配置正确
@SpringBootTest
class MySecurityApplicationTests {@Autowiredprivate UsersMapper usersMapper;@Testvoid contextLoads() {List<Users> users = usersMapper.selectList(null);System.out.println(users);}}
通过后,即可开始实现通过自己数据库进行登陆功能:
先创建返回的验证类
LoginUser 实现 UserDetails
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginUser implements UserDetails {private Users user;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return null;}@Overridepublic String getPassword() {return user.getPassword();}@Overridepublic String getUsername() {return user.getUsername();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}
登陆实现类
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UsersMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//根据用户名查询用户信息LambdaQueryWrapper<Users> wrapper = new LambdaQueryWrapper<>();wrapper.eq(Users::getUsername,username);Users user = userMapper.selectOne(wrapper);//如果查询不到数据就通过抛出异常来给出提示if(Objects.isNull(user)){throw new RuntimeException("用户名或密码错误");}Collection<? extends GrantedAuthority> authorities = Collections.singletonList(new SimpleGrantedAuthority(user.getRole()));//封装成UserDetails对象返回 return new LoginUser(user,authorities);}
}
由于在Spring Boot 2.3及更高版本中,Spring Security默认不再提供任何内置的PasswordEncoder
。这意味着如果在配置中直接使用明文密码或没有正确配置PasswordEncoder
,你将看到这个异常。这里暂时先使用明文加密。后面将一步步完善加密功能.
在SecurityConfig中加入配置
@Configuration
// 启用WebSecurity的自动配置,以便Spring Security可以管理Web安全
@EnableWebSecurity
public class SecurityConfiguration {// 设置密码加密为明文加密@Beanpublic org.springframework.security.crypto.password.PasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}// 定义一个名为securityFilterChain的bean,该bean将负责构建和应用安全过滤器链@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {// 配置HttpSecurity对象,定义安全规则http// 授权HTTP请求,定义哪些URL需要什么类型的访问控制.authorizeHttpRequests((authz) -> authz// 允许"/user/login" URL匿名访问.requestMatchers("/user/login").anonymous()// 所有其他请求都需要认证才能访问.anyRequest().authenticated())// 启用HTTP Basic认证,默认情况下提供简单的用户名/密码认证.httpBasic(Customizer.withDefaults());// 构建并返回SecurityFilterChainreturn http.build();}
}
再次访问localhost:8080/Hello后弹出登陆框:
输入任意的用户与密码即可正常访问
3.4 实现角色权限访问
在Controller中定义一个Admin资源类,只有admin用户才能进行访问
@RequestMapping("admin")
@RestController
@Slf4j
public class AdminController {@GetMapping("resourse")public String AdminRole(){return "这是只有管理员用户才能访问的资源";}}
在设置中进行配置
@Configuration
// 启用WebSecurity的自动配置,以便Spring Security可以管理Web安全
@EnableWebSecurity
public class SecurityConfiguration {// 设置密码加密为明文加密@Beanpublic org.springframework.security.crypto.password.PasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}// 定义一个名为securityFilterChain的bean,该bean将负责构建和应用安全过滤器链@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {// 配置HttpSecurity对象,定义安全规则http// 授权HTTP请求,定义哪些URL需要什么类型的访问控制.authorizeHttpRequests((authz) -> authz.requestMatchers("/user/login").anonymous()
// 需要有Admin身份的用户才能进行访问.requestMatchers("/admin/**").hasRole("ADMIN")// 所有其他请求都需要认证才能访问.anyRequest().authenticated())// 启用HTTP Basic认证,默认情况下提供简单的用户名/密码认证.httpBasic(Customizer.withDefaults());// 构建并返回SecurityFilterChainreturn http.build();}
}
重启服务器后分别用两种身份进行访问
用户访问:
管理员访问:
3.5 对密码进行B加密
config中进行配置BCrypt
@Configuration
// 启用WebSecurity的自动配置,以便Spring Security可以管理Web安全
@EnableWebSecurity
public class SecurityConfiguration {@Autowiredprivate UserDetailsServiceImpl userDetailsService;// 设置密码加密为B加密@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}protected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService);}// 定义一个名为securityFilterChain的bean,该bean将负责构建和应用安全过滤器链@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {// 配置HttpSecurity对象,定义安全规则http// 授权HTTP请求,定义哪些URL需要什么类型的访问控制.authorizeHttpRequests((authz) -> authz.requestMatchers("/user/login").anonymous()
// 需要有Admin身份的用户才能进行访问.requestMatchers("/admin/**").hasRole("ADMIN")// 所有其他请求都需要认证才能访问.anyRequest().authenticated())// 启用HTTP Basic认证,默认情况下提供简单的用户名/密码认证.httpBasic(Customizer.withDefaults());// 构建并返回SecurityFilterChainreturn http.build();}
}
由于数据库中都是明文的密码,所以这里可以通过创建一个SpringbootTest类,将所有用户的密码改为B加密后的数据.
@Testpublic void testUpdateAllPasswords() {// 创建一个BCryptPasswordEncoder实例BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();// 更新所有用户的密码为加密后的"123456"String encodedPassword = encoder.encode("123456");// 构造更新条件LambdaUpdateWrapper<Users> updateWrapper = new LambdaUpdateWrapper<>();updateWrapper.set(Users::getPassword, encodedPassword);// 执行更新操作boolean result = usersMapper.update(null, updateWrapper) > 0;if (result) {System.out.println("所有用户的密码更新成功!");} else {System.out.println("密码更新失败!");}}
配置好后,重新进行登陆查看输入对应的admin1和123456
3.6 结合Jwt实现多重校验
Spring Security 和 JSON Web Tokens (JWT) 可以协同工作来提供更灵活和安全的身份验证和授权机制。尽管 Spring Security 提供了一套全面的安全框架,但它默认使用基于会话的认证机制,这意味着服务器维护着与客户端的活动会话状态。而JWT提供了一种无状态的认证方式,这意味着每个请求都包含完整的认证信息,无需服务器保存会话状态。
pom文件中引入jwt所需要的依赖
<!-- JWT依赖--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>
Jwt资源类:
@Component
@ConfigurationProperties(prefix = "jwt")
@Data
public class JwtProperties {private String SecretKey;private long Ttl;private String TokenName;}
Jwt yml配置:
jwt:secret-key: Alphamilktoken-name: Authorizationttl: 10800000
实现Jwt的工具类
@Component
public class JwtUtil {@Autowiredprivate JwtProperties jwtProperties;public String createJWT(Map<String, Object> claims, long ttlMillis) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;long expMillis = System.currentTimeMillis() + ttlMillis;Date exp = new Date(expMillis);return Jwts.builder().setClaims(claims).signWith(signatureAlgorithm, jwtProperties.getSecretKey().getBytes(StandardCharsets.UTF_8)).setExpiration(exp).compact();}public Claims parseJWT(String token) {return Jwts.parser().setSigningKey(jwtProperties.getSecretKey().getBytes(StandardCharsets.UTF_8)).parseClaimsJws(token).getBody();}public boolean isTokenValid(String token, UserDetails userDetails) {final String username = getUsernameFromToken(token);return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));}private String getUsernameFromToken(String token) {Claims claims = parseJWT(token);return (String) claims.getSubject();}private boolean isTokenExpired(String token) {try {final Date expiration = parseJWT(token).getExpiration();return expiration.before(new Date());} catch (ExpiredJwtException e) {return true;}}
}
Jwt的校验Filter
@Component
public class JwtFilter extends OncePerRequestFilter {@Autowiredprivate JwtProperties jwtProperties;@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate JwtUtil jwtUtil;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {String token = request.getHeader(jwtProperties.getTokenName());if (token != null) {try {Claims claims = jwtUtil.parseJWT(token);String username = (String) claims.get("userName");if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);if (jwtUtil.isTokenValid(token, userDetails)) {UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authentication);}}} catch (ExpiredJwtException ex) {response.sendError(HttpServletResponse.SC_FORBIDDEN, "Token has expired.");} catch (JwtException ex) {response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid token.");}}else {response.sendError(HttpServletResponse.SC_FORBIDDEN, "No token provided.");}filterChain.doFilter(request, response);}
}
将jwt校验规则加入到Spring的Filter中进行校验
@Configuration
// 启用WebSecurity的自动配置,以便Spring Security可以管理Web安全
@EnableWebSecurity
public class SecurityConfiguration {@Autowiredprivate JwtFilter jwtFilter;@Autowiredprivate UserDetailsServiceImpl userDetailsService;// 设置密码加密为B加密@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}protected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService);}// 定义一个名为securityFilterChain的bean,该bean将负责构建和应用安全过滤器链@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {// 配置HttpSecurity对象,定义安全规则http// 授权HTTP请求,定义哪些URL需要什么类型的访问控制.authorizeHttpRequests((authz) -> authz.requestMatchers("/user/login").anonymous()
// 需要有Admin身份的用户才能进行访问.requestMatchers("/admin/**").hasRole("ADMIN")// 所有其他请求都需要认证才能访问.anyRequest().authenticated())// 启用HTTP Basic认证,默认情况下提供简单的用户名/密码认证.httpBasic(Customizer.withDefaults());
// 加入jwtFIlterhttp.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);// 构建并返回SecurityFilterChainreturn http.build();}
}
相关文章:

新版SpringSecurity5.x使用与配置
目录 一、了解SpringSecurity 1.1 什么是Spring Security? 1.2 Spring Security功能 1.3 Spring Security原理 1.4 RABC (Role-Based Access Control) 二、SpringSecurity简单案例 2.1 引入SpringSecurity依赖 2.2 创建一个简单的Controller 三、SpringSecu…...

JavaScript实战 - JavaScript 中实现线程锁
作者:逍遥Sean 简介:一个主修Java的Web网站\游戏服务器后端开发者 主页:https://blog.csdn.net/Ureliable 觉得博主文章不错的话,可以三连支持一下~ 如有需要我的支持,请私信或评论留言! 前言: …...

基于PaddleClas的人物年龄分类项目
目录 一、任务概述 二、算法研发 2.1 下载数据集 2.2 数据集预处理 2.3 安装PaddleClas套件 2.4 算法训练 2.5 静态图导出 2.6 静态图推理 三、小结 一、任务概述 最近遇到个需求,需要将图像中的人物区分为成人和小孩,这是一个典型的二分类问题…...

20240725java的Controller、DAO、DO、Mapper、Service层、反射、AOP注解等内容的学习
在Java开发中,controller、dao、do、mapper等概念通常与MVC(Model-View-Controller)架构和分层设计相关。这些概念各自承担着不同的职责,共同协作以构建和运行一个应用程序。以下是这些概念的解释:…...

dynslam的安装
1. 安装opencv 2.4.9 下载opencv2.4.9 apt-get install build-essential apt-get install libgtk2.0-dev libavcodec-dev libavformat-dev libtiff4-dev libswscale-dev libjasper-dev apt-get install cmake apt-get install pkg-config 进入安装包文件: m…...

stats 监控 macOS 系统
Stats 监控 macOS 系统 CPU 利用率GPU 利用率内存使用情况磁盘利用率网络使用情况电池电量 brew install stats参考 stats github...

后端面试题日常练-day05 【Java基础】
题目 希望这些选择题能够帮助您进行后端面试的准备,答案在文末 在Java中,以下哪个关键字用于表示方法重写(Override)? a) override b) overrule c) overwrite d) supercede Java中的HashMap和Hashtable有什么区别&am…...

mac|安装PostgreSQL
1、官网下载:EDB: Open-Source, Enterprise Postgres Database Management 选择需要的版本: 双击得到的.dmg文件 双击,弹窗选择打开,一路next,然后输入你要设置的密码,默认账号名字为:postgres…...

内网对抗-隧道技术篇防火墙组策略FRPNPSChiselSocks代理端口映射C2上线
知识点: 1、隧道技术篇-传输层-工具项目-Frp&Nps&Chisel 2、隧道技术篇-传输层-端口转发&Socks建立&C2上线Frp Frp是专注于内网穿透的高性能的反向代理应用,支持TCP、UDP、HTTP、HTTPS等多种协议。可以将内网服务以安全、便捷的方式通过…...

arinc664总线协议
AFDX总线协议简介 (1)AFDX的传输速率高:带宽100MHZ,远远高于其他的类型的航空总线。(2)AFDX网络的鲁棒性高:AFDX的双冗余备份网络可以在某一个网络出现故障时,仍能正常通讯。 其中…...

UNIX 域协议
1. UNIX域协议 利用socket编程接口实现本地进程间通信 UNIX域协议套接字:可以使用TCP,也可以使用UDP SOCK_STREAM -----> TCP 面向字节流 SOCK_DGRAM -----> UDP 面向数据报 UNIX域协议并不是一个实际的协议族,而是在单个主机上执…...

昇思25天学习打卡营第17天|LLM-基于MindSpore的GPT2文本摘要
打卡 目录 打卡 环境准备 准备阶段 数据加载与预处理 BertTokenizer 部分输出 模型构建 gpt2模型结构输出 训练流程 部分输出 部分输出2(减少训练数据) 推理流程 环境准备 pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspo…...

Clion开发STM32——移植FreeModbus
STM32型号 :STM32H743VIT6 FreeModbus版本 :1.6 使用工具:stm32cubeMX,Clion 使用STM32作从机,模式:RTU 网上用keil的比较多,用Clion的比较少,如果你也用Clion,那么希望…...

c++栈笔记
一种常见的数据结构,遵循后进先出,先进后出的原则。地址不连续,栈顶(top) 1.常见函数 stack<int> s;定义一个参数类型为int 的栈 名为ss.push()向栈中插入元素s.emplace()压栈,无返回值s.pop()删除…...

Oracle配置TCPS加密协议测试
文章目录 一、环境信息二、配置过程1.创建证书2.监听配置2.1.配置sqlnet.ora2.2.配置listener.ora文件2.3.配置tnsnames.ora文件2.4.重载监听 3.数据库本地测试3.1. tcps登录测试3.2.日志监控 一、环境信息 操作系统:Linux 版本信息:Oracle 19c 参考文档…...

Jetpack Compose 通过 OkHttp 发送 HTTP 请求的示例
下面是一个使用 Kotlin 和 Jetpack Compose 来演示通过 OkHttp 发送 HTTP 请求的示例。这个示例包括在 Jetpack Compose 中发送一个 GET 请求和一个 POST 请求,并显示结果。 添加okhttp依赖 首先,在你的 build.gradle.kts 文件中添加必要的依赖…...

Pytorch使用教学3-特殊张量的创建与类型转化
1 特殊张量的创建 与numpy类似,PyTorch中的张量也有很多特殊创建的形式。 zeros:全0张量 # 形状为2行3列 torch.zeros([2, 3]) # tensor([[0., 0., 0.], # [0., 0., 0.]])ones:全1张量 # 形状为2行3列 torch.ones([2, 3]) # tensor([[1., 1., 1.], # …...

【日记】办个护照不至于有这种刑事罪犯一样的待遇吧……(737 字)
正文 暴晒,中午出去骑共享单车,座垫都不敢坐。 至于为什么,中午觉都不睡跑出去,是因为今天他们办承兑汇票的业务,搞了一天,中午不休息,说可能还会用到我的指纹,让我 on call。我心想…...

【矩阵微分】在不涉及张量的前提下计算矩阵对向量的导数并写出二阶泰勒展开
本篇内容摘自CMU 16-745最优控制的第10讲 “Nonlinear Trajectory Optimization”。 如何在不涉及张量运算的前提下,计算矩阵对向量的导数并写出二阶泰勒展开 在多维微积分中,计算矩阵对向量的导数和二阶泰勒展开是一项重要的任务。本文将介绍如何在不涉…...

数据结构之判断平衡二叉树详解与示例(C,C++)
文章目录 AVL树定义节点定义计算高度获取平衡因子判断是否为平衡二叉树完整示例代码结论 在计算机科学中,二叉树是一种非常重要的数据结构。它们被广泛用于多种算法中,如排序、查找等。然而,普通的二叉树在极端情况下可能退化成链表ÿ…...

深入解析仓颉编程语言:函数式编程的核心特性
摘要 仓颉编程语言以其独特的语法和功能,为开发者提供了强大的编程工具。本文将深入探讨仓颉语言中的嵌套函数、Lambda 表达式和闭包等函数式编程的核心特性,帮助开发者更好地理解和利用这些工具。 引言 在现代编程语言中,函数式编程范式越…...

springboot惠农服务平台-计算机毕业设计源码50601
目录 1 绪论 1.1 研究背景 1.2研究意义 1.3论文结构与章节安排 2 惠农服务平台app 系统分析 2.1 可行性分析 2.2 系统功能分析 2.3 系统用例分析 2.4 系统流程分析 2.5本章小结 3 惠农服务平台app 总体设计 3.1 系统功能模块设计 3.2 数据库设计 表access_token (…...

Lua脚本简单理解
目录 1.安装 2.语法 2.1Lua数据类型 2.2变量 2.3lua循环 2.4流程控制 2.5函数 2.6运算符 2.7关系运算符 3.lua脚本在redis中的使用 3.1lua脚本再redis简单编写 3.2普通锁Lua脚本 3.3可重入锁lua脚本 1.安装 centos安装 安装指令: yum -y update yum i…...

AutoSAR自适应平台架构总览--AP的初认识
AutoSAR自适应平台架构总览:AP 基础设施层(Foundation Layer)核心操作系统(Core OS)通信管理(Communication Management) 服务层(Services Layer)诊断服务(Diagnostics S…...

GPT-4o Mini:探索最具成本效益的小模型在软件开发中的应用
随着人工智能技术的迅猛发展,自然语言处理(NLP)领域也取得了显著的进步。OpenAI 最新发布的 GPT-4o Mini 模型,以其卓越的性能和极具竞争力的价格,成为了广大开发者关注的焦点。作为一名长期关注人工智能及其在软件开发…...

{Spring Boot 原理篇} Spring Boot自动装配原理
SpringBootApplication 1,Spring Boot 应用启动,SpringBootApplication标注的类就是启动类,它去实现配置类中的Bean的自动装配 SpringBootApplication public class SpringbootRedis01Application {public static void main(String[] args)…...

QEMU源码全解析 —— CPU虚拟化(10)
接前一篇文章: 本文内容参考: 《趣谈Linux操作系统》 —— 刘超,极客时间 《QEMU/KVM》源码解析与应用 —— 李强,机械工业出版社 《深度探索Linux系统虚拟化原理与实现》—— 王柏生 谢广军, 机械工业出版社 特此致谢! 二、x86架构CPU虚拟化 3. VMX 上一回讲解了支…...

46、PHP实现矩阵中的路径
题目: PHP实现矩阵中的路径 描述: 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。 路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向…...

c++笔记2
目录 2.2 栈底(bottom) } 大数乘大数 节点:包含一个数据元素及若干指向子树分支的信息 。 节点的度:一个节点拥有子树的数目称为节点的度 。 叶子节点:也称为终端节点,没有子树的节点或者度为零的节点…...

通过Lua脚本手写redis分布式锁
1、手写 Redis 分布式锁,包括上锁、解锁、自动续期。 此功能实现采用 Lua脚本实现,Lua脚本可以保证原子性。 setnx可以实现分布式锁,但是无法实现可重入锁,所以用hset来代替setnx实现可重入的分布式锁。 -- lock if redis.call…...