提前打开Redis

1)通过内置的用户名和密码登录

spring-boot-starter-security.jar

2)使用自定义用户名和密码登录

UserDetailService

自定义类实现UserDetailService接口,重写loadUserByUsername方法

class UserDetailServiceImpl implements UserDetailService{public UserDetails loadUserByUsername(String username){//查询数据库表//获取用户信息SysUser user = mapper.方法();//封装到UserDetails对象中LoginUser loginUser = new LoginUser(user);}}
​
class LoginUser implements UserDetails{private SysUser sysUser;public LoginUser(SysUser user){this.sysUser = user;}getUsername(){return "用户名"}getPassword(){}get....
}

3)加密功能 bcryptPasswordEncoder

@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {/*创建加密对象(密码匹配器对象)*/@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}

4)自定义登录接口

@RestController
public class LoginController {@Autowiredprivate LoginService loginService;@RequestMapping("/login")public R login(String username, String password) throws AuthenticationException {//调用servicereturn loginService.login(username, password);}
}
@Service
public class LoginServiceImpl implements LoginService {@Autowiredprivate AuthenticationManager authenticationManager;@Overridepublic R login(String username, String password) throws AuthenticationException {UsernamePasswordAuthenticationToken token =new UsernamePasswordAuthenticationToken(username, password);//调用认证提供器的认证方法,进行用户名,密码认证Authentication authentication = authenticationManager.authenticate(token);//根据返回值判断是否认证成功if(authentication.isAuthenticated()){//认证成功//获取用户身份 LoginUserLoginUser user = (LoginUser) authentication.getPrincipal();//获取用户idLong id = user.getSysUser().getId();//根据用户id,生成tokenString token2 = JwtUtil.createJWT(id+"");//返回 code ,msg,tokenreturn R.ok(token2,"认证成功");}return null;}
}

5)登录成功后缓存用户信息到redis

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
//将用户信息存储到redis中
redisTemplate.opsForValue().set(id,user,30, TimeUnit.MINUTES);
//将用户信息存储到SecurityContext上下文环境中,供其他过滤器使用
SecurityContextHolder.getContext().setAuthentication(authentication);

完整代码如下:

package com.hl.springsecurity01.service.impl;
​
import com.hl.springsecurity01.domain.R;
import com.hl.springsecurity01.security.LoginUser;
import com.hl.springsecurity01.service.LoginService;
import com.hl.springsecurity01.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
​
import javax.security.sasl.AuthenticationException;
import java.util.concurrent.TimeUnit;
​
@Service
public class LoginServiceImpl implements LoginService {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate RedisTemplate redisTemplate;@Overridepublic R login(String username, String password) throws AuthenticationException {UsernamePasswordAuthenticationToken token =new UsernamePasswordAuthenticationToken(username, password);//调用认证提供器的认证方法,进行用户名,密码认证Authentication authentication = authenticationManager.authenticate(token);//根据返回值判断是否认证成功if(authentication == null){//认证失败throw  new AuthenticationException("用户名或者密码错误");}if(authentication.isAuthenticated()){//认证成功//获取用户身份 LoginUserLoginUser user = (LoginUser) authentication.getPrincipal();//获取用户idLong id = user.getSysUser().getId();//将用户信息存储到redis中redisTemplate.opsForValue().set(id,user,30, TimeUnit.MINUTES);//将用户信息存储到SecurityContext上下文环境中,供其他过滤器使用SecurityContextHolder.getContext().setAuthentication(authentication);//根据用户id,生成tokenString token2 = JwtUtil.createJWT(id+"");//返回 code ,msg,tokenreturn R.ok(token2,"认证成功");}return null;}
}

6)携带token,访问目标方法

创建过滤器并配置过滤器

/*
创建token过滤器*/
@Component
public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {System.out.println("到达jwt过滤器.....");//放行,到达目标方法filterChain.doFilter(request,response);}
}
package com.hl.springsecurity01.security;
​
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate JWTAuthenticationTokenFilter authenticationTokenFilter;/*创建加密对象(密码匹配器对象)*/@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 对于登录接口 允许匿名访问.antMatchers("/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();
​//配置自定义过滤器http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);}@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}
}

token过滤器完整代码

package com.hl.springsecurity01.security;
​
import com.hl.springsecurity01.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
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;
/*
创建token过滤器*/
@Component
public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {@Autowiredprivate RedisTemplate redisTemplate;@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {System.out.println("到达jwt过滤器.....");//获取请求头中的tokenString token = request.getHeader("token");if(token == null){
//            throw new RuntimeException("token不能为空!");System.out.println("token为空!");//放行,到usernamePasswordtokenfilterChain.doFilter(request,response);return;}//校验token是否合法Long userId = null;try {Claims claims = JwtUtil.parseJWT(token);userId = Long.parseLong(claims.getSubject());} catch (Exception e) {e.printStackTrace();throw  new RuntimeException("token 不合法");}//判断用户是否登录成功,服务端是否存在该用户信息Object obj = redisTemplate.opsForValue().get(userId);if(obj == null){System.out.println("用户未登录");throw new RuntimeException("用户未登录!");}//将登录成功的用户信息设置到SecurityContext中UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(obj,null,null);SecurityContextHolder.getContext().setAuthentication(authenticationToken);
​
​//放行,到达目标方法filterChain.doFilter(request,response);}
}

7)退出登录

package com.hl.springsecurity01.web;
​
import com.hl.springsecurity01.domain.R;
import com.hl.springsecurity01.service.LoginService;
import com.hl.springsecurity01.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
import javax.security.sasl.AuthenticationException;
import javax.servlet.http.HttpServletRequest;
​
@RestController
public class LoginController {@Autowiredprivate LoginService loginService;@Autowiredprivate RedisTemplate redisTemplate;@RequestMapping("/login")public R login(String username, String password) throws AuthenticationException {//调用servicereturn loginService.login(username, password);}@RequestMapping("/logout1")public R logout(HttpServletRequest request) throws Exception {String token = request.getHeader("token");//解析token,得到用户idClaims claims = JwtUtil.parseJWT(token);Object object = claims.getSubject();Long userId = Long.parseLong(object.toString());//从redis中删除用户信息redisTemplate.delete(userId);//springsecurity上下文中清除用户信息SecurityContextHolder.getContext().setAuthentication(null);return R.ok();}
​
}

8)权限控制

1. 开启权限拦截

@SpringBootApplication
@MapperScan(basePackages = "com.hl.springsecurity01.mapper")
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class Springsecurity01Application {
​public static void main(String[] args) {SpringApplication.run(Springsecurity01Application.class, args);}
​
}

2.方法上添加拦截注解

@Controller
public class BasicController {
​// http://127.0.0.1:8080/hello?name=lisi@RequestMapping("/hello")@PreAuthorize("hasAuthority('user:list')")@ResponseBodypublic String hello(@RequestParam(name = "name", defaultValue = "unknown user") String name) {return "Hello " + name;}

3、授权(模拟字符串授权)

UserDetailsService和UserDetails
/*
根据用户名查找用户对象*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//根据用户名,到数据库表中,查找用户对象QueryWrapper queryWrapper = new QueryWrapper();queryWrapper.eq("user_name", username);List<SysUser> list = sysUserService.list(queryWrapper);//判断用户是否存在LoginUser user = null;if(list != null && list.size() > 0){SysUser sysUser = list.get(0);//授权List<String> permissions = new ArrayList<>();permissions.add("user:list");permissions.add("user:add");//封装数据到UserDetails接口实现类对象中user = new LoginUser(sysUser,permissions);}return user;
}
@Data
public class LoginUser implements UserDetails {
​private SysUser sysUser;private List<String> permissions;
​public LoginUser() {}public LoginUser(SysUser sysUser, List<String> permissions) {this.sysUser = sysUser;this.permissions = permissions;}
​//返回用户权限信息,返回权限列表@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {List<GrantedAuthority> list = new ArrayList<>();for (String permission : permissions) {list.add(new SimpleGrantedAuthority(permission));}return list;}
JwtAuthenticationInterceptor
package com.hl.springsecurity01.security;
​
import com.hl.springsecurity01.util.JwtUtil;
import com.mysql.cj.log.Log;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
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;
/*
创建token过滤器*/
@Component
public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {@Autowiredprivate RedisTemplate redisTemplate;@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {System.out.println("到达jwt过滤器.....");//获取请求头中的tokenString token = request.getHeader("token");if(token == null){
//            throw new RuntimeException("token不能为空!");System.out.println("token为空!");//放行,到usernamePasswordtokenfilterChain.doFilter(request,response);return;}//校验token是否合法Long userId = null;try {Claims claims = JwtUtil.parseJWT(token);userId = Long.parseLong(claims.getSubject());} catch (Exception e) {e.printStackTrace();throw  new RuntimeException("token 不合法");}//判断用户是否登录成功,服务端是否存在该用户信息Object obj = redisTemplate.opsForValue().get(userId);if(obj == null){System.out.println("用户未登录");throw new RuntimeException("用户未登录!");}LoginUser user = (LoginUser)obj;//将登录成功的用户信息设置到SecurityContext中UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(obj,null,user.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authenticationToken);
​
​//放行,到达目标方法filterChain.doFilter(request,response);}
}
/*** @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>*/
@Controller
public class BasicController {
​// http://127.0.0.1:8080/hello?name=lisi@RequestMapping("/hello")@PreAuthorize("hasAuthority('user:list')")@ResponseBodypublic String hello(@RequestParam(name = "name", defaultValue = "unknown user") String name) {return "Hello " + name;}
​// http://127.0.0.1:8080/hello?name=lisi@RequestMapping("/hello2")@PreAuthorize("hasAuthority('user:hello')")@ResponseBodypublic String hello2(@RequestParam(name = "name", defaultValue = "unknown user") String name) {return "Hello " + name;}

hello可以访问,hello2无法访问。

4、授权(连接数据库表)

public interface SysUserMapper extends BaseMapper<SysUser> {
​@Select(value = "select sys_menu.perms " +"from sys_menu  " +"join sys_role_menu on sys_menu.menu_id = sys_role_menu.menu_id " +"join sys_user_role on sys_role_menu.role_id = sys_user_role.role_id " +"where sys_user_role.user_id = #{id} and perms is not null and perms !=''")public List<String> findPermissionsByUserId(Long userId);
}
package com.hl.springsecurity01.security;
​
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hl.springsecurity01.domain.SysUser;
import com.hl.springsecurity01.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
​
import java.util.ArrayList;
import java.util.List;
​
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate SysUserService sysUserService;/*根据用户名查找用户对象*/@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//根据用户名,到数据库表中,查找用户对象QueryWrapper queryWrapper = new QueryWrapper();queryWrapper.eq("user_name", username);List<SysUser> list = sysUserService.list(queryWrapper);//判断用户是否存在LoginUser user = null;if(list != null && list.size() > 0){SysUser sysUser = list.get(0);//授权
//            List<String> permissions = new ArrayList<>();
//            permissions.add("user:list");
//            permissions.add("user:add");List<String> permissions = sysUserService.findPermissionsByUserId(sysUser.getId());//封装数据到UserDetails接口实现类对象中user = new LoginUser(sysUser,permissions);}return user;}
}

9)权限控制相关的注解

在Spring Security中,hasRole和hasAuthority都可以用来控制用户的访问权限,但它们有一些细微的差别。

hasRole方法是基于角色进行访问控制的。它检查用户是否有指定的角色,并且这些角色以"ROLE_"前缀作为前缀(例如"ROLE_ADMIN")。

hasAuthority方法是基于权限进行访问控制的。它检查用户是否有指定的权限,并且这些权限没有前缀。

因此,使用hasRole方法需要在用户的角色名称前添加"ROLE_"前缀,而使用hasAuthority方法不需要这样做。

例如,假设用户有一个角色为"ADMIN"和一个权限为"VIEW_REPORTS",可以使用以下方式控制用户对页面的访问权限:

.antMatchers("/admin/").hasRole("ADMIN") .antMatchers("/reports/").hasAuthority("VIEW_REPORTS") 在这个例子中,只有具有"ROLE_ADMIN"角色的用户才能访问/admin/路径下的页面,而具有"VIEW_REPORTS"权限的用户才能访问/reports/路径下的页面。

@PreAuthorize("hasAuthority('system:user:list')")   特定的菜单权限
@PreAuthorize("hasAnyAuthority('system:user:list','system:user:add')")  多个菜单权限只要有一个就可以访问
@PreAuthorize("hasRole('admin')")
@PreAuthorize("hasAnyRole('admin','comm')")-- 根据用户,查询角色列表
select sys_role.role_key
from sys_role join sys_user_role
on sys_role.role_id = sys_user_role.role_id
where  sys_user_role.user_id = 2
union all
select sys_menu.perms
from sys_menu 
join sys_role_menu on sys_menu.menu_id = sys_role_menu.menu_id
join sys_user_role on sys_role_menu.role_id = sys_user_role.role_id
where sys_user_role.user_id = 2 and perms is not null and perms !=''
​
​
​
ROLE_common
system:user:list
system:role:list
system:menu:list
system:dept:list
system:post:list

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

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

相关文章

Apache组件遭大规模攻击:Tomcat与Camel高危RCE漏洞引发数千次利用尝试

漏洞态势分析帕洛阿尔托网络公司Unit 42团队最新研究报告显示&#xff0c;针对Apache Tomcat和Apache Camel关键漏洞的网络攻击正在全球激增。2025年3月披露的这三个远程代码执行&#xff08;RCE, Remote Code Execution&#xff09;漏洞——CVE-2025-24813&#xff08;Tomcat&…

Odoo 中国特色高级工作流审批模块研发

本文旨在为基于Odoo 18平台开发一款符合中国用户习惯的、功能强大的通用工作流审批模块提供一份全面的技术实现与产品设计方案。该模块的核心特性包括&#xff1a;为最终用户设计的图形化流程设计器、对任意Odoo模型的普适性、复杂的审批节点逻辑&#xff08;如会签、条件分支、…

unplugin-vue-components 最佳实践手册

&#x1f3a8; unplugin-vue-components 最佳实践手册 整理不易&#xff0c;收藏、点赞、关注支持下&#xff01;本文详细介绍了 unplugin-vue-components 插件的作用、配置方法、常用场景及与 unplugin-auto-import 配合使用的实战技巧&#xff0c;特别适合 Vue 3 Vite 项目。…

⿻ Java 学习日志 01

Java 运行机制&#xff1a; 原文件>编译器>字节码&#xff08;class后缀&#xff09;>JVM虚拟机>操作系统既有编译的过程也有解释的过程。JVM&#xff1a;Java Virture Machine/执行字节码的虚拟机&#xff0c;是实现跨平台——Java核心机制的核心。 JRE&…

基于Flutter的web登录设计

基于Flutter的web登录设计 1. 概述 本文档详细介绍了基于Flutter Web的智能家居系统登录模块的设计与实现。登录模块作为系统的入口&#xff0c;不仅提供了用户身份验证功能&#xff0c;还包括注册新用户的能力&#xff0c;确保系统安全性的同时提供良好的用户体验。 本文档…

Maven继承:多模块项目高效管理秘笈

Maven继承是Maven项目管理中的核心机制&#xff0c;允许子模块共享并统一管理父模块的配置信息&#xff08;尤其是依赖关系&#xff09;&#xff0c;其核心原理与Java中的类继承类似。以下是关键要点解析&#xff1a;一、核心概念与作用消除配置冗余 多个子模块共享相同依赖&am…

关于系统无法找到 arm-linux-gcc 命令,这表明你的环境中尚未安装 ARM 交叉编译工具链。以下是详细的解决方案:(DIY机器人工房)

1. 错误原因分析 错误信息&#xff1a;无法将“arm-linux-gcc”项识别为 cmdlet/函数/程序 这说明 Windows 或 Cygwin 环境中没有安装 ARM 交叉编译工具&#xff0c;或者工具路径未添加到系统 PATH 中。当前环境&#xff1a; 你之前使用的是 Cygwin 环境下的 x86_64 架构 GCC&…

redis一篇入门

一、Redis 安装 Linux 系统安装通过包管理器安装 (以 Ubuntu 为例): sudo apt update sudo apt install redis-server从源码编译安装: wget https://download.redis.io/redis-stable.tar.gz tar -xzvf redis-stable.tar.gz cd redis-stable make sudo make installWindows 安装…

【JAVAFX】webview导入本地html并传入参数

java侧String num"234234";URL url1 getClass().getResource("/html/imGroupVar.html");webview.getEngine().load(url1.toExternalForm() "?cc" num);本地html <!DOCTYPE html> <html lang"en"> <head><met…

Playfun即将开启大型Web3线上活动,打造沉浸式GameFi体验生态

作为致力于构建健康游戏生态与优质用户体验的领先游戏平台&#xff0c;Playfun始终以“让游戏更有价值”为理念&#xff0c;持续探索Web3与GameFi融合的新可能。凭借其开放、公平与共创的核心价值观&#xff0c;Playfun正逐步成为连接玩家、开发者与数字资产生态的重要桥梁。为…

WSL2配置freesurfer

Windows 11 安装 WSL2 Ubuntu 22.04 并迁移到 E 盘 前言 本文详细记录了在 Windows 11 上通过 Microsoft Store 安装 WSL2 Ubuntu 22.04&#xff0c;并将其从默认的 C 盘迁移到 E 盘的完整过程。适合想要节省 C 盘空间或需要将 WSL2 安装到其他磁盘的用户。 环境信息 操作系…

论客邮箱导出发信信息脚本

#!/bin/bash# 检查是否提供了CSV文件名if [ $# -ne 1 ]; thenecho "用法: $0 <csv文件>"exit 1ficsv_file"$1"# 暂存用户和midoutput_csv"user_mid.csv"# 抄送人优化extract_value() {[[ "$1" *,* ]] || return # 无逗号直接返…

Windows 本地安装部署 Apache Druid

在 Windows 本地安装部署 Apache Druid 可以按照以下步骤进行。由于 Druid 是基于 Java 的应用&#xff0c;需要先准备好 Java 环境&#xff0c;然后下载配置 Druid。 一、环境准备 1. 安装 Java 确保已安装 Java 8 或以上版本&#xff08;推荐 Java 11&#xff09;&#xf…

PY32F002A单片机 低成本控制器解决方案,提供多种封装

PY32F002A 是一款32 位 ARM Cortex-M0 内核的高性价比单片机。PY32F002A单片机提供了多种封装类型&#xff0c;最大有18个IO&#xff0c;芯片采用32位ARM内核&#xff0c;M0架构&#xff0c;最高工作频率24MHz。flash 存储器20KByte,SRAM 3K。最大支持9路12位ADC&#xff0c;5个…

区块链技术在物联网(IoT)中的核心应用场景

以下是区块链技术在物联网&#xff08;IoT&#xff09;中的核心应用场景及具体实例&#xff0c;涵盖技术原理、实施架构和实际价值&#xff1a;一、区块链解决物联网的四大核心问题痛点区块链方案技术实现设备身份伪造唯一数字身份链上注册非对称加密生成设备DID&#xff08;去…

PostgreSQL DELETE 语句详解

PostgreSQL DELETE 语句详解 在数据库管理中,删除数据是日常操作中不可或缺的一环。PostgreSQL 是一款功能强大的开源关系型数据库管理系统,其 DELETE 语句在数据删除方面表现出色。本文将详细解析 PostgreSQL 的 DELETE 语句,包括其语法、使用场景和注意事项。 1. DELETE…

传统报警难题频现,安全运行隐患重重

在企业生产运营与安全管理过程中&#xff0c;报警系统作为保障安全运行的重要防线&#xff0c;其作用不言而喻。然而&#xff0c;传统报警系统在实际应用中却难题频现&#xff0c;不仅无法及时、准确地预警潜在风险&#xff0c;还为企业的安全运行埋下了重重隐患。青岛国瑞信息…

WPF学习笔记(23)Window、Page与Frame、ViewBox

Window、Page与Frame一、Window1.模态窗口与非模态窗口2.Window类3.示例二、Page1.概述2.Page类三、Frame1.概述2.Frame类3.示例四、ViewBox1. 概述2. 详解3. 示例总结一、Window 1.模态窗口与非模态窗口 2.Window类 属性说 明Title获取或设置窗口的标题。lcon设获取或设置窗…

设计模式---观察者模式(发布-订阅模式)

设计模式—观察者模式(发布-订阅模式) 一、简介 发布-订阅模式是一种消息传递模式&#xff0c;用于实现对象间的一对多依赖关系。在这种模式中&#xff1a; 发布者&#xff08;Publisher&#xff09;不直接向订阅者&#xff08;Subscriber&#xff09;发送消息发布者和订阅者…

一文讲清楚React Fiber

文章目录一文讲清楚React Fiber1. 基础概念1.1浏览器刷新率&#xff08;帧&#xff09;1.2 JS执行栈1.3 时间分片1.4 链表2. React Fiber是如何实现更新过程控制2.1 任务拆分2.2挂起、恢复、终止2.2.1 挂起2.2.2 恢复2.2.3 终止2.3 任务具备优先级一文讲清楚React Fiber 1. 基…