springsecurity02

提前打開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. 基…