SpringSecurity01

目錄

一、權限控制

二、相關框架

1、shiro

2、springsecurity

三、springsecurity使用流程

1、搭建環境實現默認用戶名和密碼登錄

2、使用數據庫表中定義好的用戶名和密碼訪問實現等值密碼匹配

1)sql文件

2)搭建jdbc或者mybatis或者mybatis-plus環境

3)配置mybatis-plus環境

4)使用mybatisX 生成基本的service和mapper

5)創建一個類實現UserDetailsService接口 ,重寫方法(根據用戶名到數據庫中查找用戶對象)

6)創建一個LoginUser實現UserDetails接口,封裝用戶信息

3、加密機制 自定義密碼匹配器

1)創建加密對象

2)使用測試類,生成臨時密碼,測試匹配方法

4、自定義登錄接口

5、token字符串的生成


一、權限控制

1、認證:是否登錄成功。

2、授權:權限控制,授予權限、校驗權限。

二、相關框架

1、shiro

Shiro 是 apache權限框架,較之 JAAS 和 Spring Security,Shiro 在保持強大功能的同時,還在簡單性和靈活性方面擁有巨大優勢。 Shiro 是一個強大而靈活的開源安全框架,能夠非常清晰的處理認證授權管理會話以及密碼加密

2、springsecurity

Spring Security 是 Spring家族中的一個安全管理框架。相比與另外一個安全框架Shiro,它提供了更豐富的功能,社區資源也比Shiro豐富。

一般來說中大型的項目都是使用SpringSecurity來做安全框架。

小項目用Shiro的比較多,因為相比與SpringSecurity,Shiro的上手更加的簡單。

springsecurity 和 其他組件的簡單交互

前后端分離場景下,登錄校驗流程的核心思路:token。 Token是服務端生成的一串字符串,以作客戶端進行請求的一個令牌,當第一次登錄后,服務器生 成一個Token便將此Token返回給客戶端,以后客戶端只需帶上這個Token前來請求數據即可,無需再次帶上用戶名和密碼。

使用token機制的身份驗證方法,在服務器端不需要存儲用戶的登錄記錄。

JWT:JWT全面解讀、詳細使用步驟 - 簡書

三、springsecurity使用流程

1、搭建環境實現默認用戶名和密碼登錄

springboot環境+springweb+springsecurity權限jar包

訪問目標方法時,自動跳轉到/login接口,輸入用戶名user和默認密碼,登錄成功后,自動跳轉到目標方法。

2、使用數據庫表中定義好的用戶名和密碼訪問實現等值密碼匹配

1)sql文件

DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',`user_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'NULL' COMMENT '用戶名',`nick_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'NULL' COMMENT '昵稱',`password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'NULL' COMMENT '密碼',`status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '賬號狀態(0正常 1停用)',`email` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '郵箱',`phonenumber` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手機號',`sex` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用戶性別(0男,1女,2未知)',`avatar` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '頭像',`user_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '用戶類型(0管理員,1普通用戶)',`create_by` bigint(20) NULL DEFAULT NULL COMMENT '創建人的用戶id',`create_time` datetime NULL DEFAULT NULL COMMENT '創建時間',`update_by` bigint(20) NULL DEFAULT NULL COMMENT '更新人',`update_time` datetime NULL DEFAULT NULL COMMENT '更新時間',`del_flag` int(11) NULL DEFAULT 0 COMMENT '刪除標志(0代表未刪除,1代表已刪除)',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用戶表' ROW_FORMAT = Dynamic;
?INSERT INTO `sys_user` VALUES (1, '張三', '張三', '{noop}1234', '0', NULL, NULL, NULL, NULL, '1', NULL, NULL, NULL, NULL, 0);

2)搭建jdbc或者mybatis或者mybatis-plus環境

<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3</version>
</dependency>

3)配置mybatis-plus環境

server:port: 8080
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/springsecurityusername: rootpassword: 123456
mybatis-plus:configuration:map-underscore-to-camel-case: truetype-aliases-package: com.hl.springsecurity01.domainmapper-locations: classpath:/mapper/*.xml

4)使用mybatisX 生成基本的service和mapper

5)創建一個類實現UserDetailsService接口 ,重寫方法(根據用戶名到數據庫中查找用戶對象)

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.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);//封裝數據到UserDetails接口實現類對象中user = new LoginUser(sysUser);}return user;}
}

6)創建一個LoginUser實現UserDetails接口,封裝用戶信息

package com.hl.springsecurity01.security;
?
import com.hl.springsecurity01.domain.SysUser;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
?
import java.util.Collection;
import java.util.Collections;
/*
創建類實現UsersDetail接口,存儲當前登錄成功的用戶信息*/
@Data
public class LoginUser implements UserDetails {
?private SysUser sysUser;
?public LoginUser() {}public LoginUser(SysUser sysUser) {this.sysUser = sysUser;}
?//返回用戶權限信息,返回權限列表@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return Collections.emptyList();}
?@Overridepublic String getPassword() {return sysUser.getPassword();}
?@Overridepublic String getUsername() {return sysUser.getUserName();}
?@Overridepublic boolean isAccountNonExpired() {return true;}
?@Overridepublic boolean isAccountNonLocked() {return true;}
?@Overridepublic boolean isCredentialsNonExpired() {return true;}
?@Overridepublic boolean isEnabled() {return true;}
}

3、加密機制 自定義密碼匹配器

1)創建加密對象

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

2)使用測試類,生成臨時密碼,測試匹配方法

@SpringBootTest
class Springsecurity01ApplicationTests {@Autowiredprivate PasswordEncoder passwordEncoder;
?@Testvoid contextLoads() {String pwd = passwordEncoder.encode("1234");System.out.println(pwd);//$2a$10$DpNgEn0fiYStJJ/EoYxf7uhBOMnuqK/UdBKmexX5KrEVPLuGQ0LsS//$2a$10$sLUel1CyTVY1kDWM5BwlNu1WMLMqlys00NIir0SiEgR0A5ItM1Vda//比對密碼boolean flag1 = passwordEncoder.matches("1234", "$2a$10$DpNgEn0fiYStJJ/EoYxf7uhBOMnuqK/UdBKmexX5KrEVPLuGQ0LsS");boolean flag2 = passwordEncoder.matches("1234", "$2a$10$sLUel1CyTVY1kDWM5BwlNu1WMLMqlys00NIir0SiEgR0A5ItM1Vda");System.out.println(flag1);System.out.println(flag2);}
?
}

$2a$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
├─┬─┼──┬─┼──────────────┼───────────────────────────────────
? │ │? │? │ ? ?? │ ? ? ? ? ? ? ? ? ? ?
? │ │? │? │ ? ?? └─ 哈希值(31字節)
? │ │? │? └─ 鹽值(22字符,16字節)
? │ │? └─ cost參數(12 → 2^12=4096輪迭代)
? │ └─ 算法版本(2a)
? └─ 固定前綴

$<算法版本>$<cost>$<salt><hash>

修改數據庫的密碼為加密后的密碼再進行測試?,填寫用戶名張三,密碼1234

4、自定義登錄接口

@RestController
public class LoginController {@Autowiredprivate LoginService loginService;@RequestMapping("/login")public R login(String username, String password) throws AuthenticationException {//調用servicereturn loginService.login(username, password);}
}
public interface LoginService {public R login(String username, String password) throws AuthenticationException;
}
@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 == null){//認證失敗throw  new AuthenticationException("用戶名或者密碼錯誤");}if(authentication.isAuthenticated()){//認證成功//返回 code ,msg,tokenreturn R.ok("token.............","認證成功");}return null;}
}
package com.hl.springsecurity01.security;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.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {/*創建加密對象(密碼匹配器對象)*/@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();}@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}
}

登錄成功,看到json返回,失敗,沒有任何提示。

5、token字符串的生成

<!--生成token-->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>

JwtUtil工具類

package com.hl.springsecurity01.util;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;/*** JWT工具類*/
public class JwtUtil {//有效期為public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000  一個小時//設置秘鑰明文public static final String JWT_KEY = "test";public static String getUUID(){String token = UUID.randomUUID().toString().replaceAll("-", "");return token;}/*** 生成jtw字符串* @param subject token中要存放的數據(json格式)* @return*/public static String createJWT(String subject) {JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 設置過期時間return builder.compact();}/*** 生成jtw字符串* @param subject token中要存放的數據(json格式)* @param ttlMillis token超時時間* @return*/public static String createJWT(String subject, Long ttlMillis) {JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 設置過期時間return builder.compact();}private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;SecretKey secretKey = generalKey();long nowMillis = System.currentTimeMillis();Date now = new Date(nowMillis);if(ttlMillis==null){ttlMillis=JwtUtil.JWT_TTL;}long expMillis = nowMillis + ttlMillis;Date expDate = new Date(expMillis);return Jwts.builder().setId(uuid)              //唯一的ID.setSubject(subject)   // 主題  可以是JSON數據.setIssuer("sg")     // 簽發者.setIssuedAt(now)      // 簽發時間.signWith(signatureAlgorithm, secretKey) //使用HS256對稱加密算法簽名, 第二個參數為秘鑰.setExpiration(expDate);}/*** 創建token* @param id* @param subject* @param ttlMillis* @return*/public static String createJWT(String id, String subject, Long ttlMillis) {JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 設置過期時間return builder.compact();}/*** 生成加密后的秘鑰 secretKey* @return*/public static SecretKey generalKey() {byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;}/*** 解析jwt** @param jwt* @return* @throws Exception*/public static Claims parseJWT(String jwt) throws Exception {SecretKey secretKey = generalKey();return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}/***   用于測試*/public static void main(String[] args) throws Exception {
//        String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjYWM2ZDVhZi1mNjVlLTQ0MDAtYjcxMi0zYWEwOGIyOTIwYjQiLCJzdWIiOiJzZyIsImlzcyI6InNnIiwiaWF0IjoxNjM4MTA2NzEyLCJleHAiOjE2MzgxMTAzMTJ9.JVsSbkP94wuczb4QryQbAke3ysBDIL5ou8fWsbt_ebg";
//        Claims claims = parseJWT(token);
//        System.out.println(claims);String token = createJWT("1");String token1 = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJlM2UzMGE0ZjhhMGE0OTQ1ODNjMzZlZmNjMWQ3YzQ4YiIsInN1YiI6IjEiLCJpc3MiOiJzZyIsImlhdCI6MTc1MTUzMjI0MiwiZXhwIjoxNzUxNTM1ODQyfQ.ALfU833lUe1bCRlsAwcDd_mwD5j3sCtFCO3Ue1E-WWw";System.out.println(token);Claims claims = parseJWT(token1);System.out.println(claims);}}
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.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;import javax.security.sasl.AuthenticationException;@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 == null){//認證失敗throw  new AuthenticationException("用戶名或者密碼錯誤");}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;}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/912865.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/912865.shtml
英文地址,請注明出處:http://en.pswp.cn/news/912865.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解決git clone報錯:fatal unable to access xxx. Could not resolve host github.com

作者&#xff1a;唐叔在學習 專欄&#xff1a;問題百寶箱 文章目錄 問題描述問題診斷網絡連通性測試 解決方案1. 獲取GitHub最新IP地址2. 修改系統hosts文件 驗證解決方案常見問題解答總結 問題描述 當使用git clone命令克隆GitHub倉庫時&#xff0c;可能會遇到如下錯誤&#…

魔術方法__call__

__call__ 是一個特殊方法&#xff08;也稱為魔術方法&#xff09;&#xff0c;用于使一個類的實例能夠像函數一樣被調用。當定義了這個方法后&#xff0c;實例對象可以后接括號&#xff08;即 ()&#xff09;來觸發調用&#xff0c;這會讓實例表現得像函數一樣。 ?使實例可調…

PHP中的異常處理與錯誤日志記錄

在PHP編程實踐中&#xff0c;異常處理是一項至關重要的技能&#xff0c;它能夠幫助開發者識別和響應程序執行過程中發生的非預期事件。與此同時&#xff0c;錯誤日志記錄是確保應用程序可靠性和穩定性的關鍵組成部分。本文將詳細介紹如何在PHP中實現這兩個方面的技術。 首先&a…

JS去除空格(數組內字符串)

1.JS中去除空格 去除這個數組中每個對象內部參數&#xff08;也就是屬性值&#xff09;的空格&#xff0c;可以通過遍歷數組&#xff0c;再遍歷每個對象的屬性&#xff0c;使用 trim() 方法來去除字符串首尾的空格。以下是具體實現代碼&#xff1a; let data [{ designHours:…

【Spring篇01】:Bean的線程安全問題總結

文章目錄 1. 核心問題&#xff1a;Spring 框架中的 Bean 是線程安全的嗎&#xff1f;2. 最佳實踐與解決方案禁止方案&#xff1a;濫用prototype作用域推薦方案&#xff08;按優先級排序&#xff09; 3. 生產環境中的典型案例Case 1&#xff1a;訂單服務統計Case 2&#xff1a;用…

本地項目上傳git

將您本地的項目代碼上傳到一個私有的、別人看不見的 GitHub 倉庫&#xff0c;是進行云端協作&#xff08;如使用 Google Colab&#xff09;、版本控制和代碼備份的最佳實踐。這是一個非常重要的技能。 整個過程可以分為三個部分&#xff1a; 準備工作&#xff1a;在您的電腦上…

【.NET Framework 窗體應用程序項目結構介紹】

在使用 Visual Studio (VS) 開發 .NET Framework 窗體應用程序&#xff08;Windows Forms App&#xff09; 時&#xff0c;項目結構通常包含以下核心文件夾和文件。以下是詳細介紹&#xff1a; 1. 項目根目錄下的主要文件 (1) .csproj 文件 作用&#xff1a;C# 項目文件&…

【SpringAI】4.多模態提問

SpringAI多模態提問 概述 SpringAI支持多模態輸入&#xff0c;允許AI模型同時處理文本和圖像內容。這對于需要視覺理解的AI應用場景非常有用&#xff0c;如圖像描述、視覺問答、圖像分析等。 核心概念 1. Media類 SpringAI使用Media類來表示多模態內容&#xff0c;支持圖…

自動化提示工程:未來AI優化的關鍵突破

自動化提示工程:未來AI優化的關鍵突破 自動化提示工程能夠自動化或半自動化地生成或優化提示詞,以探索大規模的提示詞組合,并通過 自動優化技術提升提示詞生成的穩定性? 依據自動化提示工程實現形式在邏輯推理和效能導向 兩個維度的取舍上,將其分為基于思維鏈的自動化提示工…

多模態大語言模型arxiv論文略讀(148)

A Comprehensive Survey and Guide to Multimodal Large Language Models in Vision-Language Tasks ?? 論文標題&#xff1a;A Comprehensive Survey and Guide to Multimodal Large Language Models in Vision-Language Tasks ?? 論文作者&#xff1a;Chia Xin Liang, P…

關于.net core開發的實體所有注解詳解

以下是對 .NET Core 開發中實體類&#xff08;用于數據模型&#xff09;和 Web API 控制器/方法&#xff08;用于定義接口&#xff09;常用注解屬性&#xff08;Attributes&#xff09;的詳細說明與示例&#xff0c;涵蓋數據驗證、API 行為控制、序列化、Swagger/OpenAPI 文檔生…

【安全工具】SQLMap 使用詳解:從基礎到高級技巧

目錄 簡介 一、安裝與基礎配置 1. 安裝方法 2. 基本語法 二、基礎掃描技術 1. 簡單檢測 2. 指定參數掃描 3. 批量掃描 三、信息收集 1. 獲取數據庫信息 2. 獲取當前數據庫 3. 獲取數據庫用戶 4. 獲取數據庫版本 四、數據提取技術 1. 列出所有表 2. 提取表數據 …

Redis大Key拆分實戰指南:從問題定位到落地優化

引言 最近在項目里遇到一個棘手問題&#xff1a;生產環境的Redis突然變“卡”了&#xff01;查詢延遲從幾毫秒飆升到幾百毫秒&#xff0c;監控面板顯示某個節點CPU使用率飆到90%。排查半天才發現&#xff0c;原來是某個用戶訂單的Hash Key太大了——單Key存了100多萬個訂單字段…

RabbitMQ簡單消息發送

RabbitMQ簡單消息發送 簡單代碼實現RabbitMQ消息發送 需要的依賴 <!--rabbitmq--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId><version>x.x.x</version>&l…

【閱讀筆記】基于雙邊濾波改進的空域濾波算法

一、雙邊濾波空域濾波算法 雙邊濾波是一種典型的非線性濾波算法。基于高斯濾波&#xff0c;雙邊濾波利用強度的變化來保存邊緣信息&#xff0c;解決了邊緣模糊在視覺觀感上認為重要信息丟失的問題。雙邊濾波的濾波效果主要取決于兩個參數&#xff1a;兩個像素的空間鄰近性和灰…

華為交換機堆疊與集群技術深度解析附帶腳本

一、引言 在企業園區網、數據中心等網絡場景中&#xff0c;為了提升網絡的可靠性、擴展性和管理效率&#xff0c;華為交換機提供了堆疊&#xff08;Stack&#xff09;和集群&#xff08;CSS&#xff0c;Cluster Switch System &#xff09;技術。這兩種技術能夠將多臺物理交換…

Python網絡爬蟲(十三)- 數據解析模塊 BeautifulSoup

1、BS4簡介 BeautifulSoup(簡稱 BS4) 是一個用于解析 HTML 和 XML 文檔的 Python 第三方庫。它能夠從網頁或其他 HTML/XML 格式的文本中提取數據,并將其轉換為結構化的對象,方便開發者快速定位、提取和操作所需信息。它的核心功能是通過解析器將無序的標記語言轉換為樹形結…

如何使用 Pytorch Lightning 啟用早停機制

【PL 基礎】如何啟用早停機制 摘要1. on_train_batch_start()2. EarlyStopping Callback 摘要 本文介紹了兩種在 PyTorch Lightning 中實現早停機制的方法。第一種是通過重寫on_train_batch_start()方法手動控制訓練流程&#xff1b;第二種是使用內置的EarlyStopping回調&#…

深入理解前綴和與差分算法及其C++實現

前綴和與差分是算法競賽和編程中非常重要的兩種技巧&#xff0c;它們能夠高效地處理區間查詢和區間更新問題。本文將詳細介紹這兩種算法的原理、應用場景以及C實現。 一、前綴和算法 1.1 前綴和的基本概念 前綴和&#xff08;Prefix Sum&#xff09;是一種預處理技術&#x…

HugeGraph【部署】Linux單機部署

注: hugegraph從版本 1.5.0 開始&#xff0c;需要 Java11 運行時環境 一、安裝JDK11 1.下載JDK11 https://www.oracle.com/java/technologies/downloads/#java11 2.解壓縮包 tar -zxvf jdk-11.0.27_linux-x64_bin.tar.gz 3.修改/etc/profile環境變量 export JAVA_HOME/usr…