Spring Security密碼編輯器示例詳解
Spring Security 密碼編輯器
Maven 依賴
Maven 版本管理
Spring Security 和 Spring Framework 是 獨立版本體系:
Spring Security 示例版本:
<spring.security.version>5.3.4.RELEASE</spring.security.version>
Spring Framework 示例版本:
<spring.version>5.2.8.RELEASE</spring.version>
注意:Spring Security 與 Spring Framework 版本不必一致,但需要兼容。一般查看官方兼容矩陣即可。
Maven 依賴示例(傳統(tǒng) Spring)
典型 POM.XML 結(jié)構(gòu):
<dependencies>
<!-- Spring MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring Security 核心模塊 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- JSTL -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>這種方式適合傳統(tǒng) Spring MVC 項目,手動管理模塊版本。
Spring Boot 集成(推薦方式)
Spring Boot 提供了 starter 依賴,自動引入所有核心和常用模塊:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>Spring Boot 示例 POM:
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Thymeleaf + Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>
<!-- 測試支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>優(yōu)點:
- 自動引入
core + web + config等依賴; - 版本統(tǒng)一管理,無需手動設(shè)置
spring-security.version; - 支持 Spring Boot 自動配置,快速集成安全功能。
依賴管理技巧
- 版本統(tǒng)一:使用
<properties>統(tǒng)一定義spring.security.version和spring.version,方便升級。 - 按需引入擴展模塊:
- LDAP 項目 → 添加
spring-security-ldap - SSO 項目 → 添加
spring-security-cas - OAuth2 項目 → 添加
spring-security-oauth2
- LDAP 項目 → 添加
- 避免冗余依賴:
- Web 項目無需引入 LDAP 或 ACL 模塊,保持輕量化。
- 測試支持:
- 使用
spring-security-test可輕松模擬用戶認證、角色授權(quán),便于單元測試。
- 使用
密碼編碼器
在 Spring Security 5 之前,我們可以直接在內(nèi)存中使用明文密碼,比如:
UserDetails user = User.builder()
.username("user")
.password("user123") // 明文
.roles("USER")
.build();但是 Spring Security 5 之后,為了增強安全性:
- 默認 不再支持明文密碼。
- 所有密碼都必須經(jīng)過編碼(加密)。
- 如果你要使用明文密碼,需要顯式加上
{noop}前綴:
.password("{noop}user123") // 表示明文這種做法僅用于開發(fā)或測試環(huán)境,生產(chǎn)環(huán)境絕對不能用。
NoOpPasswordEncoder
{noop} 對應(yīng)的是 Spring 內(nèi)置的 NoOpPasswordEncoder,它只是直接返回原始密碼,不做加密。
@Bean
protected UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("user")
.password("{noop}user123")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}- 優(yōu)點:簡單、方便測試。
- 缺點:不安全、已廢棄(deprecated),不適合生產(chǎn)環(huán)境。
推薦做法:使用密碼編碼器(PasswordEncoder)
Spring Security 提供了多種 密碼編碼器,最常用的是 BCryptPasswordEncoder。
使用 BCryptPasswordEncoder 的示例:
@Bean
protected PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
protected UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder().encode("user123")) // 密碼加密
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("admin123")) // 密碼加密
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}測試案例:用戶/管理員登錄
引入 Spring Security、Thymeleaf 的相關(guān)依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity6</artifactId> </dependency>
在 src/main/resources/templates 目錄下創(chuàng)建測試頁面
登錄頁(login.html)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<h1>登錄</h1>
<!-- 顯示登錄錯誤信息 -->
<div th:if="${param.error}" style="color: red;">
用戶名或密碼錯誤
</div>
<!-- 顯示登出信息 -->
<div th:if="${param.logout}" style="color: green;">
已成功登出
</div>
<!-- 登錄表單:Spring Security 會自動處理提交的 username 和 password -->
<form th:action="@{/login}" method="post">
<div>
<label>用戶名:</label>
<input type="text" name="username" required>
</div>
<div>
<label>密碼:</label>
<input type="password" name="password" required>
</div>
<div>
<button type="submit">登錄</button>
</div>
</form>
</body>
</html>首頁(home.html)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="UTF-8">
<title>首頁</title>
</head>
<body>
<h1>歡迎,<span sec:authentication="name"></span>!</h1> <!-- 顯示當前用戶名 -->
<p>你的角色:<span sec:authentication="authorities"></span></p> <!-- 顯示角色 -->
<!-- 僅 ADMIN 可見的鏈接 -->
<div sec:authorize="hasRole('ADMIN')">
<a th:href="@{/admin}" rel="external nofollow" >管理員頁面</a>
</div>
<!-- 登出鏈接 -->
<form th:action="@{/logout}" method="post">
<button type="submit">登出</button>
</form>
</body>
</html>管理員頁面(admin/admin.html)
僅 ADMIN 角色可訪問:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>管理員頁面</title>
</head>
<body>
<h1>管理員專屬頁面</h1>
<a th:href="@{/home}" rel="external nofollow" >返回首頁</a>
</body>
</html>創(chuàng)建相關(guān)配置類
PasswordConfig 密碼加密配置類
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class PasswordConfig {
@Bean
protected PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}UserConfig 用戶配置類
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class UserConfig {
// 注入 PasswordConfig 中定義的 PasswordEncoder
private final PasswordEncoder passwordEncoder;
public UserConfig(PasswordConfig passwordConfig) {
this.passwordEncoder = passwordConfig.passwordEncoder();
}
@Bean
protected UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder.encode("user123")) // 密碼加密
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder.encode("admin123")) // 密碼加密
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}SecurityConfig 權(quán)限控制配置類
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// 注入 UserConfig 和 PasswordConfig 中定義的 PasswordEncoder 和 UserDetailsService
private final UserConfig userConfig;
private final PasswordConfig passwordConfig;
public SecurityConfig(UserConfig userConfig, PasswordConfig passwordConfig) {
this.userConfig = userConfig;
this.passwordConfig = passwordConfig;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// 配置登錄頁和權(quán)限規(guī)則
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/css/**").permitAll() // 登錄頁和靜態(tài)資源允許匿名訪問
.requestMatchers("/admin/**").hasRole("ADMIN") // /admin/** 路徑需要 ADMIN 角色
.anyRequest().authenticated() // 其他路徑需要認證
)
// 配置登錄頁(Thymeleaf 頁面)
.formLogin(form -> form
.loginPage("/login") // 自定義登錄頁路徑
.defaultSuccessUrl("/home", true) // 登錄成功后跳轉(zhuǎn)首頁
.failureUrl("/login?error=true") // 登錄失敗跳轉(zhuǎn)
)
// 配置登出
.logout(logout -> logout
.logoutSuccessUrl("/login?logout=true") // 登出成功跳轉(zhuǎn)
);
return http.build();
}
}三個配置類也可以合為一個配置類:
package com.scarletkite.springsecuritydemo.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// 1. 定義 PasswordEncoder Bean
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// 2. 定義 UserDetailsService Bean(直接調(diào)用當前類的 passwordEncoder() 方法)
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder().encode("user123")) // 直接調(diào)用本類的 passwordEncoder()
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("admin123")) // 直接調(diào)用本類的 passwordEncoder()
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
// 3. 刪除構(gòu)造器注入(不再需要,因為內(nèi)部方法可直接調(diào)用)
// 4. 定義 SecurityFilterChain Bean(配置安全規(guī)則)
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/css/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/home", true)
.failureUrl("/login?error=true")
)
.logout(logout -> logout
.logoutSuccessUrl("/login?logout=true")
);
return http.build();
}
}創(chuàng)建控制器(處理頁面跳轉(zhuǎn))
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class PageController {
// 登錄頁
@GetMapping("/login")
public String login() {
return "login";
}
// 首頁
@GetMapping("/home")
public String home() {
return "home";
}
// 管理員頁面
@GetMapping("/admin")
public String admin() {
return "admin/admin";
}
}在瀏覽器地址欄輸入 localhost:8080/login 進行測試
BCrypt 密碼結(jié)構(gòu)解析
BCrypt 密碼在內(nèi)存中或數(shù)據(jù)庫中存儲的格式如下:
$2a$10$acaXGauv/3buNdwQWeOgu.iab3LLDclrH64xVMsSxd9Lp/otgUfMm
各字段含義:
| 字段 | 說明 |
|---|---|
2a | 使用的編碼算法,bcrypt |
10 | 算法強度(strength,cost factor) |
| 前 22 個字符 | 隨機鹽(salt) |
| 后 31 個字符 | 哈希后的密碼(hashed password) |
BCrypt 的特點:
- 每次編碼都使用隨機鹽(salt)
- 相同的明文密碼每次編碼結(jié)果都不同
- 提供強抗破解能力,適合生產(chǎn)環(huán)境
使用場景
- 內(nèi)存用戶(InMemoryUserDetailsManager)
- 對開發(fā)或測試環(huán)境,使用
BCryptPasswordEncoder也可以。
- 對開發(fā)或測試環(huán)境,使用
- 數(shù)據(jù)庫用戶(Persistent storage)
- 推薦在用戶注冊時先用
BCryptPasswordEncoder.encode()加密密碼,再存入數(shù)據(jù)庫。 - 登錄驗證時,Spring Security 會自動調(diào)用
matches()方法比較原始密碼和加密后的密碼。
- 推薦在用戶注冊時先用
passwordEncoder.matches(rawPassword, encodedPassword)
密碼編碼器代理
什么是 DelegatingPasswordEncoder?
DelegatingPasswordEncoder 是 Spring Security 的密碼編碼器代理(Delegator)。
它的作用是:
“根據(jù)密碼前綴(id)動態(tài)選擇合適的密碼加密算法。”
比如數(shù)據(jù)庫中存了三種不同類型的密碼:
{bcrypt}$2a$10$Fbp...
{noop}123456
{pbkdf2}9ddae64d...Spring Security 看到 {bcrypt} 前綴,就自動使用 BCryptPasswordEncoder 去驗證;
看到 {pbkdf2} 就用 PBKDF2 算法。
總結(jié):
DelegatingPasswordEncoder = “密碼算法調(diào)度中心”,用來統(tǒng)一管理多種加密方式。
為什么需要它?
背景問題:Spring Security 5 之前,密碼一般只用一種算法,比如:
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
但隨著項目演進,你可能遇到這些問題:
- 老系統(tǒng)用 MD5 或 SHA 存密碼;
- 新系統(tǒng)想改用更安全的 BCrypt;
- 不同模塊或第三方用戶來源不同;
- 想平滑過渡,不影響舊用戶登錄。
于是 Spring Security 引入了 DelegatingPasswordEncoder 來統(tǒng)一管理不同加密算法的兼容性與遷移。
內(nèi)部原理結(jié)構(gòu)
它的核心思想就是一個 Map + 默認算法 ID
public class DelegatingPasswordEncoder implements PasswordEncoder {
private final String idForEncode; // 當前默認算法
private final Map<String, PasswordEncoder> idToPasswordEncoder; // 所有可用算法
private final PasswordEncoder defaultPasswordEncoderForMatches; // 匹配時默認使用的
// encode() 時加上 {id}
// matches() 時根據(jù) {id} 選擇對應(yīng) encoder
}Spring 提供了一個工廠方法:
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
這行代碼創(chuàng)建了一個默認配置的 DelegatingPasswordEncoder,支持以下算法:
| ID | 對應(yīng)編碼器 |
|---|---|
| bcrypt | BCryptPasswordEncoder |
| ldap | LdapShaPasswordEncoder |
| MD4 | Md4PasswordEncoder |
| MD5 | MessageDigestPasswordEncoder |
| noop | NoOpPasswordEncoder |
| pbkdf2 | Pbkdf2PasswordEncoder |
| scrypt | SCryptPasswordEncoder |
| sha256 | StandardPasswordEncoder |
| argon2 | Argon2PasswordEncoder |
使用方式
創(chuàng)建并使用默認 DelegatingPasswordEncoder
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}它的默認算法是 {bcrypt}。
String encoded = passwordEncoder().encode("123456");
// 輸出類似:{bcrypt}$2a$10$NPMD...
會發(fā)現(xiàn),前綴
{bcrypt}自動加上了
驗證時,Spring Security 會:
- 讀取密碼前綴
{bcrypt} - 從內(nèi)部 Map 查找對應(yīng)編碼器
- 調(diào)用
matches()進行驗證
自定義 DelegatingPasswordEncoder
比如,想默認用 PBKDF2,但仍然支持舊的 BCrypt:
@Bean
public PasswordEncoder passwordEncoder() {
String idForEncode = "pbkdf2";
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("pbkdf2", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("bcrypt", new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
return new DelegatingPasswordEncoder(idForEncode, encoders);
}效果:
- 新注冊用戶 → PBKDF2 編碼(前綴
{pbkdf2}) - 老用戶若用
{bcrypt}→ 仍然能匹配 - 臨時測試賬號可用
{noop}明文密碼
舊密碼無前綴怎么辦?
如果數(shù)據(jù)庫中的密碼沒有 {id} 前綴,比如舊系統(tǒng)存的是純 BCrypt:
可以設(shè)置一個默認匹配策略:
DelegatingPasswordEncoder delegatingPasswordEncoder =
(DelegatingPasswordEncoder) PasswordEncoderFactories.createDelegatingPasswordEncoder();
// 設(shè)置一個默認匹配器,當沒有前綴時使用 bcrypt
delegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(new BCryptPasswordEncoder());工作流程圖
┌──────────────┐
│ encode("123")│
└──────┬───────┘
↓
+--------------------------+
| DelegatingPasswordEncoder|
+--------------------------+
| idForEncode = "bcrypt" |
| idToPasswordEncoder = { |
| bcrypt → BCryptEncoder |
| pbkdf2 → Pbkdf2Encoder |
| noop → NoOpEncoder |
| } |
+--------------------------+
↓
輸出 {bcrypt}$2a$10$...驗證過程:
matches(raw, "{bcrypt}$2a$10$...")
→ 提取 {bcrypt}
→ 找出 BCryptPasswordEncoder
→ 調(diào)用 matches()
→ 返回 true / false
前面的 PasswordConfig 配置類可以改為:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder() {
String idForEncode = "bcrypt";
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("bcrypt", new BCryptPasswordEncoder());
encoders.put("pbkdf2", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8());
encoders.put("argon2", new Argon2PasswordEncoder(10, 8, 1, 16, -1));
encoders.put("noop", NoOpPasswordEncoder.getInstance());
DelegatingPasswordEncoder passwordEncoder = new DelegatingPasswordEncoder(idForEncode, encoders);
passwordEncoder.setDefaultPasswordEncoderForMatches(new BCryptPasswordEncoder());
return passwordEncoder;
}
}DelegatingPasswordEncoder 是 Spring Security 密碼策略的核心。
它讓我們可以:
- 安全地管理多種密碼算法;
- 平滑升級加密方案;
- 保持老用戶可登錄;
- 確保系統(tǒng)的密碼驗證邏輯統(tǒng)一、可擴展、可演化。
到此這篇關(guān)于Spring Security 密碼編輯器的文章就介紹到這了,更多相關(guān)Spring Security 密碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring?Security中用戶名和密碼的驗證完整流程
- Spring Security實現(xiàn)5次密碼錯誤觸發(fā)賬號自動鎖定功能
- spring security的BCryptPasswordEncoder加密和對密碼驗證的原理分析
- 使用spring security明文密碼校驗時報錯-BadCredentialsException: Bad credentials的問題
- 一文掌握SpringSecurity?BCrypt密碼加密和解密
- Spring Security 密碼驗證動態(tài)加鹽的驗證處理方法
- Spring Security保護用戶密碼常用方法詳解
- Spring security基于數(shù)據(jù)庫中賬戶密碼認證
- Spring security BCryptPasswordEncoder密碼驗證原理詳解
- Spring Security使用數(shù)據(jù)庫認證及用戶密碼加密和解密功能
相關(guān)文章
springboot2.0?@Slf4j?log?彩色日志配置輸出到文件
這篇文章主要介紹了springboot2.0 @Slf4j log日志配置輸出到文件(彩色日志),解決方式是使用了springboot原生自帶的一個log框架,結(jié)合實例代碼給大家講解的非常詳細,需要的朋友可以參考下2023-08-08
關(guān)于Spring?Cloud實現(xiàn)日志管理模塊
這篇文章主要介紹了關(guān)于Spring?Cloud實現(xiàn)日志管理模塊問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11
Spring的嵌套事務(wù)(Propagation.NESTED)到底是個啥案例代碼講解
SavePoint是數(shù)據(jù)庫事務(wù)中的一個概念,?可以將整個事務(wù)切割為不同的小事務(wù),可以選擇將狀態(tài)回滾到某個小事務(wù)發(fā)生時的樣子,本文通過案例代碼講解Spring的嵌套事務(wù)(Propagation.NESTED)到底是個啥,感興趣的朋友跟隨小編一起看看吧2023-01-01
Java集合類的組織結(jié)構(gòu)和繼承、實現(xiàn)關(guān)系詳解
這篇文章主要介紹了Java集合類的組織結(jié)構(gòu)和繼承、實現(xiàn)關(guān)系,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11
SpringSecurity中內(nèi)置過濾器的使用小結(jié)
SpringSecurity通過其復(fù)雜的過濾器鏈機制,為Java應(yīng)用提供了全面的安全防護,本文主要介紹了SpringSecurity中內(nèi)置過濾器的使用小結(jié),感性的可以了解一下2025-03-03

