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

单点登录三:添加RBAC权限校验模型功能理解及实现demo

1、RBAC权限模型

RBAC(Role-Based Access Control)是一种基于角色的访问控制模型,用于管理系统中用户的权限和访问控制。它将用户、角色和权限之间的关系进行了明确的定义,以实现灵活的权限管理和控制。

1.1、RBAC模型主要包括以下几个核心概念:

1、模型概念:

用户(User):系统中的实际操作者,拥有唯一标识符。

角色(Role):权限的集合,可以被赋予给用户,一个用户可以拥有一个或多个角色。

权限(Permission):系统中的具体操作权限,定义了用户可以执行的操作,可以是功能菜单的接口路径URL,也可以是其他细粒度的操作权限。

2、操作概念:

授权(Authorization):将权限赋予用户或角色的过程,即为用户分配相应的角色或权限。

认证(Authentication):验证用户的身份和权限,确保用户具有访问系统资源的合法权限。

RBAC模型的基本原则是:权限授权应该基于角色,而不是直接授权给特定用户。通过角色的中介,将权限与用户进行解耦,实现了权限的集中管理和灵活分配。

1.2、RBAC模型的优点包括:

  • 简化权限管理:通过角色的授权机制,可以集中管理和维护权限,减少了权限管理的复杂性。
  • 灵活的权限分配:通过给用户分配适当的角色,可以灵活地控制用户的权限,实现细粒度的访问控制。
  • 易于扩展和维护:RBAC模型具有良好的可扩展性和维护性,可以根据业务需求进行权限的增删改操作,而不影响其他部分的权限控制。

在实际应用中,RBAC模型可以结合权限管理框架和安全框架来实现。例如,使用Spring Security框架可以方便地实现RBAC模型的权限控制,通过定义角色、权限和用户的关系,并结合注解和配置来实现权限的校验和访问控制。

总结来说,RBAC模型是一种灵活和可扩展的权限管理模型,通过角色的授权机制实现了权限的集中管理和灵活分配,为系统提供了高效、安全和可维护的访问控制机制。

1.3、RBAC级别

  • RBAC0:用户和角色是多对多,角色和权限是多对多。一个用户拥有的权限,是他所有角色的集合。
  • RBAC1:基于RBAC0,并引入了角色分层的概念,即一个角色分为多个等级,每个等级对应的权限是不一样的。把权限分给用户时,需要分到对应的角色等级。角色等级低时拥有的权限少,角色等级高的权限是所有角色等级低的权限的集合。
  • RBAC2:基于RBAC1,对角色访问进行限制。
    • 如互斥角色限制:同一个用户分配到两个角色,且角色互斥时,那么系统应该提醒只能选择其中一个角色。比如员工拥有商务这个角色,可以创建结算单并提交给财务审核,这时,就不能赋予这个员工财务角色,否则他就自己提交结算自己审核结算单了。
    • 角色数量限制:一个用户拥有的角色数量是有限的;一个角色被分配的用户数量也是有限的。
    • 先决条件限制:用户想获得某个上级角色,必须先获得其下一级的角色。比如想获得产品总监的权限,那就需要从产品助理这一角色开始,再到产品经理角色,最后到产品总监角色。
  • RBAC3:基于RBAC0,对RBAC1和RBAC2进行了整合,是最全面的权限管理。

1.4、RBAC模型复杂情况

当用户非常多的情况,可以设计用户组的概念,用户组代替原先用户的概念,这样能起到批量操作用户角色的作用;

权限组的概念也差不多,是权限过多的情况,一个一个赋权操作太繁琐,可以用权限组批量操作,非常方便。

1.5、springSecruity中实际运用简单的步骤

  1. 用户表、角色表、权限表。然后两张关联表将用户和角色,角色和权限做关联。
  2. 添加用户的时候,给user特定的用户角色。
  3. 登录时,将查询用户信息,将角色信息放进token,或缓存(比如redis,外部缓存好处是能临时控制权限)中。
  4. 登录后的操作,都会经过自定义filter,验证通过的话,可以将用户信息放进springSecruity上下文,和ThreadLocal(这里是因为登录以及验证角色权限是单线程操作,使用本地线程速度最快,比map以及外部缓存都快)。
  5. 我们想使用权限,而且无侵入的去控制的话,可以弄个自定义注解,参数为角色名,验证ThreadLocal中保存的用户信息中的角色中是否包含此角色名,返回boolean类型。

2、demo实现

结合前面我写的两篇帖子,这里整理了一个demo,能够实现一个简单的无侵入的登录及权限控制方案。这里用到springSecruity、jwt、redis、mysql、threadLocal等技术

0、springboot配置

数据源自己配,就是要提前有redis和mysql

server:port: 8083spring:application:name: playerredis:host: xxxxxxxport: xxxxxxxdatasource:url: jdbc:mysql://xxxxxxx:xxxx/xxxxxxusername: rootpassword: Aa@123456driver-class-name: com.mysql.cj.jdbc.Driverjpa:hibernate:ddl-auto: nonemybatis:mapper-locations: classpath:mappers/*.xmltype-aliases-package: com.loong.nba.player.pojo

1、依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.2</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.2</version><scope>runtime</scope></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.2</version><scope>runtime</scope></dependency><!-- MyBatis --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version></dependency><!-- 数据库驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.31</version></dependency>
</dependencies>

2、util

package com.loong.nba.player.util;import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.security.Key;
import java.util.Date;
import java.util.concurrent.TimeUnit;/*** @author jilong* @date 2023/5/18*/
@Component
public class JwtUtil {private final Key secretKey;private final long expirationTime;@Autowiredprivate StringRedisTemplate redisTemplate;public JwtUtil() {this.secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);this.expirationTime = 120000;}/*** 生成jwt令牌** @param username 用户名* @return token*/public String generateToken(String username) {Date now = new Date();Date expirationDate = new Date(System.currentTimeMillis() + expirationTime);String token = Jwts.builder().setSubject(username).setIssuedAt(now).setExpiration(expirationDate).signWith(secretKey, SignatureAlgorithm.HS256).compact();redisTemplate.opsForValue().set(username, token, expirationTime, TimeUnit.MILLISECONDS);return token;}/*** 解析令牌** @param token token* @return 内容*/public String getUsernameFormToken(String token) {return extractClaims(token).getBody().getSubject();}public boolean validateToken(String token) {try {Jws<Claims> claims = extractClaims(token);return !claims.getBody().getExpiration().before(new Date());} catch (Exception e) {e.printStackTrace();return false;}}private Jws<Claims> extractClaims(String token) {JwtParser parser = Jwts.parserBuilder().setSigningKey(secretKey).build();return parser.parseClaimsJws(token);}
}
package com.loong.nba.player.util;import com.loong.nba.player.pojo.LoginUserBO;public class SessionUtils {static ThreadLocal<LoginUserBO> loginUser = new ThreadLocal<>();public static LoginUserBO getLoginUser() {return loginUser.get();}public static void setLoginUser(LoginUserBO loginUserBO) {loginUser.set(loginUserBO);}
}

3、pojo

package com.loong.nba.player.pojo;public class UserPO {private Integer id;private String username;private String password;private String salt;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getSalt() {return salt;}public void setSalt(String salt) {this.salt = salt;}
}
package com.loong.nba.player.pojo;import java.util.List;public class LoginUserBO {private String username;private Integer userId;private String password;private List<Role> roleList;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public List<Role> getRoleList() {return roleList;}public void setRoleList(List<Role> roleList) {this.roleList = roleList;}
}
package com.loong.nba.player.pojo;public class Role {private Integer id;private String roleName;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName = roleName;}
}
package com.loong.nba.player.pojo;/*** @author jilong* @date 2023/5/19*/
public class UserDO {private String name;private String password;public UserDO() {}public UserDO(String name, String password) {this.name = name;this.password = password;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}

4、config

package com.loong.nba.player.config;import com.loong.nba.player.filter.JwtAuthenticationFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;/*** @author jilong* @date 2023/5/18*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {private final JwtAuthenticationFilter jwtAuthenticationFilter;public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) {this.jwtAuthenticationFilter = jwtAuthenticationFilter;}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/login","/user").permitAll().anyRequest().authenticated().and().addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class).sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}

5、dao层

package com.loong.nba.player.dao;import com.loong.nba.player.pojo.Role;
import org.apache.ibatis.annotations.Mapper;import java.util.List;@Mapper
public interface RoleMapper {List<Role> findByUserId(Integer id);}
package com.loong.nba.player.dao;import com.loong.nba.player.pojo.UserPO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;@Mapper
public interface UserMapper {UserPO findById(Integer id);UserPO findByName(@Param("name") String name);Integer addUser(@Param("userPO") UserPO userPO);}

6、service

package com.loong.nba.player.service;import com.loong.nba.player.pojo.UserDO;
import com.loong.nba.player.pojo.UserPO;public interface UserService {/*** 添加用户* @return 用户id*/UserPO addUser(UserDO userDO);boolean comparePassword(UserDO userDO);}
package com.loong.nba.player.service;import com.loong.nba.player.dao.UserMapper;
import com.loong.nba.player.pojo.UserDO;
import com.loong.nba.player.pojo.UserPO;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;/*** @author jilong* @date 2023/5/19*/
@Service
public class UserServiceImpl implements UserService {private final UserMapper userMapper;public UserServiceImpl(UserMapper userMapper) {this.userMapper = userMapper;}@Overridepublic UserPO addUser(UserDO userDO) {// 定义盐的长度(字节数)int saltLength = 6;// 创建一个安全的随机数生成器SecureRandom secureRandom = new SecureRandom();// 生成盐byte[] salt = new byte[saltLength];secureRandom.nextBytes(salt);// 将盐转换为字符串或字节数组String saltString = encodeSalt(salt);// 计算密码摘要String password = encryptPassword(userDO.getPassword(), saltString);UserPO userPO = new UserPO();userPO.setUsername(userDO.getName());userPO.setPassword(password);userPO.setSalt(saltString);userMapper.addUser(userPO);System.out.println("Salt (Base64 string): " + saltString);return userPO;}String encodeSalt(byte[] salt) {return Base64.getEncoder().encodeToString(salt);}byte[] decodeSaltString(String saltString) {return Base64.getDecoder().decode(saltString);}String encryptPassword(String password, String salt) {String plaintext = password + salt;try {// 创建SHA-256算法的MessageDigest实例MessageDigest digest = MessageDigest.getInstance("SHA-256");// 计算中文字符串的摘要byte[] hash = digest.digest(plaintext.getBytes(StandardCharsets.UTF_8));// 将摘要字节数组转换为十六进制字符串表示String digestHex = bytesToHex(hash);System.out.println("SHA-256摘要:" + digestHex);return digestHex;} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return null;}// 将摘要字节数组转换为十六进制字符串表示private static String bytesToHex(byte[] bytes) {StringBuilder hexStringBuilder = new StringBuilder();for (byte b : bytes) {String hex = Integer.toHexString(0xff & b);if (hex.length() == 1) {hexStringBuilder.append('0');}hexStringBuilder.append(hex);}return hexStringBuilder.toString();}@Overridepublic boolean comparePassword(UserDO userDO) {UserPO user = userMapper.findByName(userDO.getName());String salt = user.getSalt();String password = encryptPassword(userDO.getPassword(), salt);return password.equals(user.getPassword());}}

7、filter

package com.loong.nba.player.filter;import com.loong.nba.player.dao.RoleMapper;
import com.loong.nba.player.dao.UserMapper;
import com.loong.nba.player.pojo.LoginUserBO;
import com.loong.nba.player.pojo.Role;
import com.loong.nba.player.pojo.UserPO;
import com.loong.nba.player.util.JwtUtil;
import com.loong.nba.player.util.SessionUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.List;/*** @author jilong* @date 2023/5/18*/
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {private final String tokenHeader = "Authorization";private final String tokenPrefix = "Bearer ";private final JwtUtil jwtUtil;private final StringRedisTemplate redisTemplate;private final UserMapper userMapper;private final RoleMapper roleMapper;public JwtAuthenticationFilter(JwtUtil jwtUtil, StringRedisTemplate redisTemplate, UserMapper userMapper, RoleMapper roleMapper) {this.jwtUtil = jwtUtil;this.redisTemplate = redisTemplate;this.userMapper = userMapper;this.roleMapper = roleMapper;}@Overridepublic void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {String header = request.getHeader(tokenHeader);if (!ObjectUtils.isEmpty(header) && header.startsWith(tokenPrefix)) {String token = header.replace(tokenPrefix, "");if (!ObjectUtils.isEmpty(token) && jwtUtil.validateToken(token)) {String username = jwtUtil.getUsernameFormToken(token);UserPO userPO = userMapper.findByName(username);List<Role> roleList = roleMapper.findByUserId(userPO.getId());LoginUserBO loginUserBO = new LoginUserBO();loginUserBO.setUserId(userPO.getId());loginUserBO.setUsername(username);loginUserBO.setPassword(userPO.getPassword());loginUserBO.setRoleList(roleList);if (redisTemplate.opsForValue().get(username) != null) {UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, null, Collections.emptyList());SecurityContextHolder.getContext().setAuthentication(authenticationToken);SessionUtils.setLoginUser(loginUserBO);}}}chain.doFilter(request, response);}
}

8、controller

package com.loong.nba.player.controller;import com.loong.nba.player.pojo.UserDO;
import com.loong.nba.player.pojo.UserPO;
import com.loong.nba.player.service.UserServiceImpl;
import com.loong.nba.player.util.JwtUtil;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletResponse;/*** @author jilong* @date 2023/5/15*/
@RestController
public class LoginController {private final JwtUtil jwtUtil;private final UserServiceImpl userService;public LoginController(JwtUtil jwtUtil, UserServiceImpl userService) {this.jwtUtil = jwtUtil;this.userService = userService;}@PostMapping("/login")public ResponseEntity<UserDO> postLogin(@RequestBody UserDO userDO, HttpServletResponse response) {if (!userService.comparePassword(userDO)) {return ResponseEntity.ok(new UserDO());}String token = jwtUtil.generateToken(userDO.getName());response.addHeader("Authorization", "Bearer " + token);return ResponseEntity.ok(userDO);}@PostMapping("/user")public UserPO addUser(@RequestBody UserDO userDO) {return userService.addUser(userDO);}@GetMapping("/test")@PreAuthorize("@permission.hasRole("+"'管理员'"+")")public String test() {return "hello test";}
}

9、mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.loong.nba.player.dao.RoleMapper"><select id="findByUserId" resultType="Role">SELECT role.id , role.rolename FROM role where idIN (SELECT role_id FROM user_role WHERE user_id = #{id})</select></mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.loong.nba.player.dao.UserMapper"><select id="findById" resultType="UserPO">SELECT * FROM user WHERE id = #{id}</select><select id="findByName" resultType="UserPO">SELECT * FROM user WHERE username = #{name}</select><insert id="addUser" parameterType="UserPO">INSERT INTO user (username, user_password, salt)VALUES (#{userPO.username}, #{userPO.password}, #{userPO.salt})</insert>
</mapper>

相关文章:

单点登录三:添加RBAC权限校验模型功能理解及实现demo

1、RBAC权限模型 RBAC&#xff08;Role-Based Access Control&#xff09;是一种基于角色的访问控制模型&#xff0c;用于管理系统中用户的权限和访问控制。它将用户、角色和权限之间的关系进行了明确的定义&#xff0c;以实现灵活的权限管理和控制。 1.1、RBAC模型主要包括以…...

基于用户认证数据构建评估模型预测认证行为风险系统(附源码)

文件说明 datasets // 数据集(训练集、测试集) feature engineering // 特征工程 models // 评估模型 测试环境 Python3.8 任务描述 项目来自系统认证风险预测https://www.datafountain.cn/competitions/537 项目完整源码下载:https://download.csdn.net/download/liu…...

本地训练中文LLaMA模型实战教程,民间羊驼模型,24G显存盘它!

羊驼实战系列索引 博文1:本地部署中文LLaMA模型实战教程,民间羊驼模型 博文2:本地训练中文LLaMA模型实战教程,民间羊驼模型(本博客) 博文3:精调训练中文LLaMA模型实战教程,民间羊驼模型(马上发布) 简介 在学习完上篇【1本地部署中文LLaMA模型实战教程,民间羊驼模…...

快速学Go依赖注入工具wire

Go相对java和C是较新的语言&#xff0c;但也有诸多优秀特性及生态库。本文介绍大多数软件工程中常用的功能&#xff1a;依赖注入。首先介绍什么是依赖注入&#xff0c;go实现库wire与其他语言的差异。然后通过简单示例实现依赖注入&#xff0c;简化代码、提升可读性。 依赖注入…...

python入门(4)流程控制语句

1. 条件判断语句 条件控制语句用于根据条件来决定程序的执行路径。在Python中&#xff0c;常见的条件控制语句有以下几种&#xff1a; &#xff08;1&#xff09;if语句&#xff1a;用于执行满足条件的代码块。示例代码&#xff1a; age 20 if age > 18:print("成年…...

【进阶】C 语言表驱动法编程原理与实践

数据压倒一切。如果选择了正确的数据结构并把一切组织的井井有条&#xff0c;正确的算法就不言自明。编程的核心是数据结构&#xff0c;而不是算法。——Rob Pike 目录 说明 概念提出 查表方式 直接查找 索引查找 分段查找 实战示例 字符统计 月天校验 名称构造 值名…...

java+springboot留学生新闻资讯网的设计与实现

Spring框架是Java平台的一个开放源代码的Full-stack(全栈)应用程序框架&#xff0c;和控制翻转容器的实现。Spring框架的一些核心功能理论&#xff0c;可以用于所有Java应用&#xff0c;Spring还为Java EE构建的Web应用提供大量的扩展支持。Spring框架没有实现任何的编程模型&a…...

分布式事务与分布式锁区别及概念学习

一、 分布式事务 1.1 背景 传统事务ACID是基于单数据库的本地事务,仅支持单机事务,并不支持跨库事务。但随着微服务架构的普及,业务的分库分表导致一个大型业务系统往往由若干个子系统构成,这些子系统又拥有各自独立的数据库。往往一个业务流程需要由多个子系统共同完成,…...

windows先的conda环境复制到linux环境

如果是迁移的环境一致&#xff1a;同是windows或同是linux直接用这个命令即可&#xff1a; conda create -n new_env_name --clone old_env_path 如果是window的环境迁移到linux这种跨环境就不能用上面的方法&#xff0c;网上这方面的资料也很多&#xff0c;记录一下我的…...

庄懂的TA笔记(十七)<特效:屏幕UV + 屏幕扰动>

庄懂的TA笔记&#xff08;十七&#xff09;&#xff1c;特效&#xff1a;屏幕UV 屏幕扰动&#xff1e; 大纲&#xff1a; 目录 庄懂的TA笔记&#xff08;十七&#xff09;&#xff1c;特效&#xff1a;屏幕UV 屏幕扰动&#xff1e; 大纲&#xff1a; 正文&#xff1a; 一…...

手写简易RPC框架

目录 简介 服务提供者 服务注册&#xff1a;注册中心 HttpServerHandler处理远程调用请求 consumer服务消费端 简介 RPC&#xff08;Remote Procedure Call&#xff09;——远程过程调用&#xff0c;它是一种通过网络从远程计算机程序上请求服务&#xff0c; 而不需要了解…...

基于孪生网络的目标跟踪

一、目标跟踪 目标跟踪是计算机视觉领域研究的一个热点问题&#xff0c;其利用视频或图像序列的上下文信息&#xff0c;对目标的外观和运动信息进行建模&#xff0c;从而对目标运动状态进行预测并标定目标的位置。具体而言&#xff0c;视觉目标&#xff08;单目标&#xff09;…...

苏州狮山广场能耗管理系统

摘要&#xff1a;随着社会生活水平的提高&#xff0c;经济的繁荣发展&#xff0c;人们对能源的需求逐渐增长&#xff0c;由此带来的能源危机日益严重。商场如何实时的了解、分析和控制商场的能源消耗已成为需要解决的迫在眉睫的难题。传统的能源消耗智能以月/季度/年为周期进行…...

Jupyter Notebook 10个提升体验的高级技巧

Jupyter 笔记本是数据科学家和分析师用于交互式计算、数据可视化和协作的工具。Jupyter 笔记本的基本功能大家都已经很熟悉了&#xff0c;但还有一些鲜为人知的技巧可以大大提高生产力和效率。在这篇文章中&#xff0c;我将介绍10个可以提升体验的高级技巧。 改变注释的颜色 颜…...

CF 751 --B. Divine Array

Black is gifted with a Divine array a consisting of n (1≤n≤2000) integers. Each position in a has an initial value. After shouting a curse over the array, it becomes angry and starts an unstoppable transformation. The transformation consists of infinite…...

Springcloud1--->Eureka注册中心

目录 Eureka原理Eureka入门案例编写EurekaServer将user-service注册到Eureka消费者从Eureka获取服务 Eureka详解基础架构高可用的Eureka Server失效剔除和自我保护 Eureka原理 Eureka&#xff1a;就是服务注册中心&#xff08;可以是一个集群&#xff09;&#xff0c;对外暴露自…...

面试阿里、字节全都一面挂,被面试官说我的水平还不如应届生

测试员可以先在大厂镀金&#xff0c;以后去中小厂毫无压力&#xff0c;基本不会被卡&#xff0c;事实果真如此吗&#xff1f;但是在我身上却是给了我很大一巴掌... 所谓大厂镀金只是不卡简历而已&#xff0c;如果面试答得稀烂&#xff0c;人家根本不会要你。况且要不是大厂出来…...

JAVA开发(记一次删除完全相同pgSQL数据库记录只保留一条)

进行数据管理时&#xff0c;无效数据可能会对生产力和决策质量造成严重的影响。如何发现和处理无效数据变得愈发重要。一起来唠唠你会如何处理无效数据吧~ 方向一&#xff1a;介绍无效数据的概念 最近遇到了pg数据库表中的大量数据重复了&#xff0c;需要删除其中的一条。一条…...

音视频八股文(7)-- 音频aac adts三层结构

AAC介绍 AAC&#xff08;Advanced Audio Coding&#xff09;是一种现代的音频编码技术&#xff0c;用于数字音频的传输和存储领域。AAC是MPEG-2和MPEG-4标准中的一部分&#xff0c;可提供更高质量的音频数据&#xff0c;并且相比于MP3等旧有音频格式&#xff0c;AAC需要更少的…...

Docker代码环境打包进阶 - DockerHub分享镜像

1. Docker Hub介绍 Docker Hub是一个广泛使用的容器镜像注册中心&#xff0c;为开发人员提供了方便的平台来存储、共享和分发Docker容器镜像。它支持版本控制、访问控制和自动化构建&#xff0c;并提供了丰富的公共镜像库&#xff0c;方便开发人员快速获取和使用各种开源应用和…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...